~unity-2d-team/unity-2d/natty

« back to all changes in this revision

Viewing changes to launcher/UnityApplications/launcherapplicationslist.cpp

  • Committer: Tarmac
  • Author(s): Florian Boucault
  • Date: 2011-03-23 17:31:31 UTC
  • mfrom: (476.2.8 startup_notification)
  • Revision ID: ubuntu.builder@gmail.com-20110323173131-zecdrbzmdb60c6la
[launcher] Added support for startup notification protocol.

Launcher now depends on libstartup-notification.
  
New APIs:
- LauncherApplication::executable QString property
- LauncherApplication::setSnStartupSequence(SnStartupSequence* sequence)
  
LauncherApplication::launching is updated depending on the startup notification sequence set to the LauncherApplication.
LauncherApplications created for startup notification are matched with their corresponding BamfApplication based on their executable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
#include <QDebug>
29
29
#include <QDBusConnection>
30
30
#include <QFileInfo>
 
31
#include <QX11Info>
 
32
 
 
33
extern "C" {
 
34
#include <libsn/sn.h>
 
35
}
 
36
 
31
37
 
32
38
#define FAVORITES_KEY QString("/desktop/unity-2d/launcher/favorites")
33
39
#define DBUS_SERVICE_UNITY "com.canonical.Unity"
69
75
        }
70
76
    }
71
77
 
 
78
    /* Register the display to receive startup notifications */
 
79
    Display *xdisplay = QX11Info::display();
 
80
    m_snDisplay = sn_display_new(xdisplay, NULL, NULL);
 
81
    m_snContext = sn_monitor_context_new(m_snDisplay, QX11Info::appScreen(),
 
82
                                          LauncherApplicationsList::snEventHandler,
 
83
                                          this, NULL);
 
84
    Unity2dApplication::instance()->installX11EventFilter(this);
 
85
 
72
86
    load();
73
87
}
74
88
 
75
89
void
 
90
LauncherApplicationsList::snEventHandler(SnMonitorEvent *event, void *user_data)
 
91
{
 
92
    /* This method is static and only forwards the event to a non static method. */
 
93
    ((LauncherApplicationsList*)user_data)->onSnMonitorEventReceived(event);
 
94
}
 
95
 
 
96
void
 
97
LauncherApplicationsList::onSnMonitorEventReceived(SnMonitorEvent *event)
 
98
{
 
99
    SnStartupSequence *sequence = sn_monitor_event_get_startup_sequence(event);
 
100
 
 
101
    switch (sn_monitor_event_get_type (event)) {
 
102
        case SN_MONITOR_EVENT_INITIATED:
 
103
            insertSnStartupSequence(sequence);
 
104
            break;
 
105
        case SN_MONITOR_EVENT_CHANGED:
 
106
        case SN_MONITOR_EVENT_COMPLETED:
 
107
        case SN_MONITOR_EVENT_CANCELED:
 
108
            /* These events are ignored for now. This is acceptable since the
 
109
               case of a failed application startup is handled by
 
110
               LauncherApplication::launching being automatically reset to
 
111
               false after a timeout. */
 
112
            break;
 
113
    }
 
114
}
 
115
 
 
116
 
 
117
bool
 
118
LauncherApplicationsList::x11EventFilter(XEvent* xevent)
 
119
{
 
120
    /* libsn specifies that all events need to be forwarded to
 
121
       sn_display_process_event but it is not actually necessary.
 
122
       Forwarding only the events of type ClientMessage.
 
123
     */
 
124
    if (xevent->type == ClientMessage) {
 
125
        sn_display_process_event(m_snDisplay, xevent);
 
126
    }
 
127
    return false;
 
128
}
 
129
 
 
130
void
76
131
LauncherApplicationsList::onRemoteEntryUpdated(QString applicationURI, QMap<QString, QVariant> properties)
77
132
{
78
133
    QString desktopFile;
95
150
 
96
151
LauncherApplicationsList::~LauncherApplicationsList()
97
152
{
 
153
    Unity2dApplication::instance()->removeX11EventFilter(this);
 
154
    sn_monitor_context_unref(m_snContext);
 
155
    sn_display_unref(m_snDisplay);
 
156
 
98
157
    qDeleteAll(m_applications);
99
158
    delete m_favorites_list;
100
159
}
117
176
    if (!application->desktop_file().isEmpty()) {
118
177
        m_applicationForDesktopFile.insert(application->desktop_file(), application);
119
178
    }
 
179
    if (!application->executable().isEmpty()) {
 
180
        m_applicationForExecutable.insert(application->executable(), application);
 
181
    }
120
182
    endInsertRows();
121
183
 
122
184
    QObject::connect(application, SIGNAL(closed()), this, SLOT(onApplicationClosed()));
123
185
    QObject::connect(application, SIGNAL(stickyChanged(bool)), this, SLOT(onApplicationStickyChanged(bool)));
 
186
    QObject::connect(application, SIGNAL(launchingChanged(bool)), this, SLOT(onApplicationLaunchingChanged(bool)));
124
187
}
125
188
 
126
189
void
128
191
{
129
192
    int index = m_applications.indexOf(application);
130
193
 
 
194
    if (index == -1) {
 
195
        /* application is not present in m_applications */
 
196
        return;
 
197
    }
 
198
 
131
199
    beginRemoveRows(QModelIndex(), index, index);
132
200
    m_applications.removeAt(index);
133
201
    m_applicationForDesktopFile.remove(application->desktop_file());
 
202
    m_applicationForExecutable.remove(application->executable());
134
203
    endRemoveRows();
135
204
 
136
 
    delete application;
 
205
    /* LauncherApplicationsList::removeApplication might have been called in
 
206
       response to a signal emitted by application itself. Do not delete
 
207
       immediately to cater for this case.
 
208
    */
 
209
    application->deleteLater();
137
210
}
138
211
 
139
212
void LauncherApplicationsList::insertBamfApplication(BamfApplication* bamf_application)
142
215
        return;
143
216
    }
144
217
 
145
 
    LauncherApplication* application;
 
218
    LauncherApplication* matchingApplication = NULL;
 
219
    LauncherApplication* newApplication = new LauncherApplication;
 
220
    newApplication->setBamfApplication(bamf_application);
146
221
 
147
 
    QString desktop_file = bamf_application->desktop_file();
 
222
    QString executable = newApplication->executable();
 
223
    QString desktop_file = newApplication->desktop_file();
148
224
    if (m_applicationForDesktopFile.contains(desktop_file)) {
149
225
        /* A LauncherApplication with the same desktop file already exists */
150
 
        application = m_applicationForDesktopFile[desktop_file];
151
 
        application->setBamfApplication(bamf_application);
 
226
        matchingApplication = m_applicationForDesktopFile[desktop_file];
 
227
    } else if (m_applicationForExecutable.contains(executable)) {
 
228
        /* A LauncherApplication with the same executable already exists */
 
229
        matchingApplication = m_applicationForExecutable[executable];
 
230
    }
 
231
 
 
232
    if (matchingApplication != NULL) {
 
233
        /* A LauncherApplication that corresponds to bamf_application already exists */
 
234
        /* FIXME: this deletion blocks for a long time (around 100ms here) and
 
235
           leads to a visual glitch in the launcher when an application finished
 
236
           starting up. This is due to the deletion of the QFileSystemWatcher
 
237
           belonging to the LauncherApplication. */
 
238
        delete newApplication;
 
239
        matchingApplication->setBamfApplication(bamf_application);
152
240
    } else {
153
 
        /* Create a new LauncherApplication and append it to the list */
154
 
        application = new LauncherApplication;
155
 
        application->setBamfApplication(bamf_application);
156
 
        insertApplication(application);
 
241
        insertApplication(newApplication);
157
242
    }
158
243
}
159
244
 
197
282
}
198
283
 
199
284
void
 
285
LauncherApplicationsList::insertSnStartupSequence(SnStartupSequence* sequence)
 
286
{
 
287
    if (sequence == NULL) {
 
288
        return;
 
289
    }
 
290
 
 
291
    QString executable = sn_startup_sequence_get_binary_name(sequence);
 
292
 
 
293
    if (m_applicationForExecutable.contains(executable)) {
 
294
        /* A LauncherApplication with the same executable already exists */
 
295
        m_applicationForExecutable[executable]->setSnStartupSequence(sequence);
 
296
    } else {
 
297
        /* Create a new LauncherApplication and append it to the list */
 
298
        LauncherApplication* newApplication = new LauncherApplication;
 
299
        newApplication->setSnStartupSequence(sequence);
 
300
        insertApplication(newApplication);
 
301
    }
 
302
}
 
303
 
 
304
void
200
305
LauncherApplicationsList::load()
201
306
{
202
307
    /* Insert favorites */
257
362
}
258
363
 
259
364
void
 
365
LauncherApplicationsList::onApplicationLaunchingChanged(bool launching)
 
366
{
 
367
    LauncherApplication* application = static_cast<LauncherApplication*>(sender());
 
368
 
 
369
    if (!application->sticky() && !application->running() && !application->launching()) {
 
370
        removeApplication(application);
 
371
    }
 
372
}
 
373
 
 
374
void
260
375
LauncherApplicationsList::writeFavoritesToGConf()
261
376
{
262
377
    QStringList favorites;