Merge lp:~fboucault/unity-2d/startup_notification into lp:unity-2d/3.0

Proposed by Florian Boucault
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 484
Merged at revision: 485
Proposed branch: lp:~fboucault/unity-2d/startup_notification
Merge into: lp:unity-2d/3.0
Diff against target: 545 lines (+235/-21)
6 files modified
debian/control (+2/-1)
launcher/UnityApplications/CMakeLists.txt (+4/-1)
launcher/UnityApplications/launcherapplication.cpp (+73/-7)
launcher/UnityApplications/launcherapplication.h (+8/-1)
launcher/UnityApplications/launcherapplicationslist.cpp (+124/-9)
launcher/UnityApplications/launcherapplicationslist.h (+24/-2)
To merge this branch: bzr merge lp:~fboucault/unity-2d/startup_notification
Reviewer Review Type Date Requested Status
Olivier Tilloy (community) Approve
Review via email: mp+54435@code.launchpad.net

Description of the change

[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.

To post a comment you must log in.
Revision history for this message
Olivier Tilloy (osomon) wrote :

The packages’ Build-Depends need to include libstartup-notification0-dev.

review: Needs Fixing (code)
Revision history for this message
Olivier Tilloy (osomon) wrote :

Overall it seems to work fine (for applications that implement the startup notification, which sadly exclude some rather common apps like shotwell or libreoffice).
I bumped into an issue though, here are the steps to reproduce:

 - from the launcher, open up the files place entry
 - from the dash that just opened, click any folder to open it in nautilus

Notice that the icon of the favorite changes from the home icon to the conventional file manager one.

review: Needs Fixing (functional)
Revision history for this message
Olivier Tilloy (osomon) wrote :

In fact simply launching nautilus from the favorite icon in the launcher exhibits the same problem.

Revision history for this message
Olivier Tilloy (osomon) wrote :

Another functional issue: when clicking an application that is not installed in the dash, Software Center is launched, but somehow it doesn’t issue a startup notification, so it doesn’t appear in the launcher until its window shows up. When launched directly (either from the launcher or from the dash), the notification works. This may be a bug in S-C itself, and in any case I don’t think it’s a blocker, we can report it and investigate it later.

Revision history for this message
Olivier Tilloy (osomon) wrote :

/* FIXME: deleting a QFileSystemWatcher can be quite slow (sometimes
   around 100ms on a powerful computer) and can provoke visual glitches
   where the user interface is blocked for a short moment.
 */

Is this a known issue in Qt? Is there something we can do to work around it or fix it? If not, I’d remove the FIXME (and maybe just leave the comment).

Just thinking out loud here: wouldn’t it help to not make the QFileSystemWatcher a child of the LauncherApplication, and in the destructor of LauncherApplication call deleteLater() on the watcher?

Revision history for this message
Olivier Tilloy (osomon) wrote :

In launcher/UnityApplications/launcherapplication.cpp, there are two occurrences of the following line:

    m_launching_timer.start(8000);

It would be better to set the interval of the timer only once, when it’s instantiated, and then only call .start().

review: Needs Fixing (code)
Revision history for this message
Olivier Tilloy (osomon) wrote :

In launcher/UnityApplications/launcherapplicationslist.h:

  /* Startup notification support */
  SnDisplay *m_sn_display;
  SnMonitorContext *m_sn_context;

I know it’s not consistent across the whole code base, but the general trend seems to be that we use m_memberNameInCamelCase as a naming convention for attributes, so those two would be better named m_snDisplay and m_snContext.

This is a style nitpick, however I think it improves readability through improved consistency. Feel free to not apply if in a rush. Bonus points if applied ;)

Revision history for this message
Olivier Tilloy (osomon) wrote :

In launcher/UnityApplications/launcherapplicationslist.h:

  private:
    […]
    /* Startup notification support */
    […]
    bool x11EventFilter(XEvent* xevent);

In the mother class (AbstractX11EventFilter), this method is protected. Shouldn’t it be kept protected here too?

Revision history for this message
Olivier Tilloy (osomon) wrote :

In LauncherApplicationsList::~LauncherApplicationsList(…):

Shouldn’t m_sn_display be unref’ed, just like m_sn_context is unref’ed (there is a sn_display_unref(…) function)?

Revision history for this message
Olivier Tilloy (osomon) wrote :

In LauncherApplicationsList::LauncherApplicationsList(…):

  sn_monitor_context_new(m_sn_display, DefaultScreen (xdisplay),
                         LauncherApplicationsList::snEventHandler,
                         this, NULL);

Instead of DefaultScreen(xdisplay), wouldn’t it be equivalent (or maybe even better in some cases) to use QX11Info::screen() ?

478. By Florian Boucault

Merged from trunk.

479. By Florian Boucault

Added libstartup-notification0-dev to build dependencies.

Revision history for this message
Olivier Tilloy (osomon) wrote :

In LauncherApplicationsList::onApplicationLaunchingChanged(bool launching):

in the if statement, you can replace "application->launching()" by "launching", and put it first in the condition.

review: Needs Fixing (code)
480. By Florian Boucault

LauncherApplication: set the launching timeout interval only once.

481. By Florian Boucault

LauncherApplicationsList: converted m_sn_display and m_sn_context to camel case.

482. By Florian Boucault

LauncherApplicationsList: made x11EventFilter protected.

483. By Florian Boucault

LauncherApplicationsList: unref m_snDisplay upon destruction.

484. By Florian Boucault

LauncherApplicationsList: use the screen where the launcher is displayed.

Revision history for this message
Florian Boucault (fboucault) wrote :

> /* FIXME: deleting a QFileSystemWatcher can be quite slow (sometimes
> around 100ms on a powerful computer) and can provoke visual glitches
> where the user interface is blocked for a short moment.
> */
>
> Is this a known issue in Qt? Is there something we can do to work around it or
> fix it? If not, I’d remove the FIXME (and maybe just leave the comment).
>

I looked a bit through Qt bug reports and it looks like a sort of known issue. I could not figure out the relevant report though. For us it's definitely something we will need to fix as it is visible at the user level. I would therefore keep the FIXME.

> Just thinking out loud here: wouldn’t it help to not make the
> QFileSystemWatcher a child of the LauncherApplication, and in the destructor
> of LauncherApplication call deleteLater() on the watcher?

That was a very good idea though after trying it it did not look like it was better.

Revision history for this message
Olivier Tilloy (osomon) wrote :

> In LauncherApplicationsList::onApplicationLaunchingChanged(bool launching):
>
> in the if statement, you can replace "application->launching()" by
> "launching", and put it first in the condition.

Forget about this, as you pointed out this code should be shared between the three slots (onApplicationClosed, onApplicationStickyChanged and onApplicationLaunchingChanged), but let’s keep the factorization for later.

Revision history for this message
Olivier Tilloy (osomon) wrote :

Apart from the following functional glitches, identified as not blocking for a merge, this code is good to go:

 - Launching nautilus changes the icon of the favorite in the launcher
 - Clicking on not installed applications in the dash launches S-C without a startup notification

As soon as the branch is merged in the trunk, I’ll file bug reports to track those issues, and we’ll hopefully investigate and fix them very soon.

review: Approve
Revision history for this message
Olivier Tilloy (osomon) wrote :

I filed bug #741160 and bug #741168 to track the two issues mentioned above.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2011-03-01 14:14:09 +0000
3+++ debian/control 2011-03-23 16:50:54 +0000
4@@ -7,7 +7,8 @@
5 cmake, bzr, libqt4-dev,
6 libglib2.0-dev, libwnck-dev,
7 libqtgconf-dev, libqtbamf-dev, libqtdee-dev, libdbusmenu-qt-dev,
8- libx11-dev, libindicator-dev, libgtk2.0-dev, libutouch-geis-dev
9+ libx11-dev, libindicator-dev, libgtk2.0-dev, libutouch-geis-dev,
10+ libstartup-notification0-dev
11 Standards-Version: 3.9.1
12 Vcs-Bzr: http://bazaar.launchpad.net/~unity-2d-team/unity-2d/trunk
13
14
15=== modified file 'launcher/UnityApplications/CMakeLists.txt'
16--- launcher/UnityApplications/CMakeLists.txt 2011-03-16 13:50:14 +0000
17+++ launcher/UnityApplications/CMakeLists.txt 2011-03-23 16:50:54 +0000
18@@ -7,6 +7,7 @@
19 pkg_check_modules(GDK REQUIRED gdk-2.0)
20 pkg_check_modules(GIO REQUIRED gio-2.0)
21 pkg_check_modules(WNCK REQUIRED libwnck-1.0)
22+pkg_check_modules(STARTUPNOTIFICATION REQUIRED libstartup-notification-1.0)
23
24 # Sources
25 set(UnityApplications_SRCS
26@@ -49,7 +50,7 @@
27 qt4_wrap_cpp(UnityApplications_MOC_SRCS ${UnityApplications_MOC_HDRS})
28
29 # Build
30-add_definitions(-DWNCK_I_KNOW_THIS_IS_UNSTABLE)
31+add_definitions(-DWNCK_I_KNOW_THIS_IS_UNSTABLE -DSN_API_NOT_YET_FROZEN)
32
33 add_library(UnityApplications SHARED ${UnityApplications_SRCS} ${UnityApplications_MOC_SRCS})
34
35@@ -68,6 +69,7 @@
36 ${GDK_INCLUDE_DIRS}
37 ${GIO_INCLUDE_DIRS}
38 ${WNCK_INCLUDE_DIRS}
39+ ${STARTUPNOTIFICATION_INCLUDE_DIRS}
40 )
41
42 target_link_libraries(UnityApplications
43@@ -83,6 +85,7 @@
44 ${GDK_LDFLAGS}
45 ${GIO_LDFLAGS}
46 ${WNCK_LDFLAGS}
47+ ${STARTUPNOTIFICATION_LDFLAGS}
48 )
49
50 # Install
51
52=== modified file 'launcher/UnityApplications/launcherapplication.cpp'
53--- launcher/UnityApplications/launcherapplication.cpp 2011-03-21 20:59:37 +0000
54+++ launcher/UnityApplications/launcherapplication.cpp 2011-03-23 16:50:54 +0000
55@@ -45,10 +45,15 @@
56 #include <QFile>
57 #include <QFileSystemWatcher>
58
59+extern "C" {
60+#include <libsn/sn.h>
61+}
62+
63 LauncherApplication::LauncherApplication()
64 : m_application(NULL)
65 , m_desktopFileWatcher(NULL)
66 , m_appInfo(NULL)
67+ , m_snStartupSequence(NULL)
68 , m_sticky(false)
69 , m_has_visible_window(false)
70 , m_progress(0), m_progressBarVisible(false)
71@@ -72,6 +77,8 @@
72 client_type_set = true;
73 }
74
75+ m_launching_timer.setSingleShot(true);
76+ m_launching_timer.setInterval(8000);
77 QObject::connect(&m_launching_timer, SIGNAL(timeout()), this, SLOT(onLaunchingTimeouted()));
78 }
79
80@@ -87,7 +94,13 @@
81
82 LauncherApplication::~LauncherApplication()
83 {
84+ if (m_snStartupSequence != NULL) {
85+ sn_startup_sequence_unref(m_snStartupSequence);
86+ m_snStartupSequence = NULL;
87+ }
88+
89 if (m_application != NULL) {
90+ m_application->disconnect(this);
91 m_application = NULL;
92 }
93
94@@ -178,6 +191,10 @@
95 return QString::fromUtf8(g_app_info_get_name((GAppInfo*)m_appInfo));
96 }
97
98+ if (m_snStartupSequence != NULL) {
99+ return QString::fromUtf8(sn_startup_sequence_get_name(m_snStartupSequence));
100+ }
101+
102 return QString("");
103 }
104
105@@ -192,6 +209,10 @@
106 return QString::fromUtf8(g_icon_to_string(g_app_info_get_icon((GAppInfo*)m_appInfo)));
107 }
108
109+ if (m_snStartupSequence != NULL) {
110+ return QString::fromUtf8(sn_startup_sequence_get_icon_name(m_snStartupSequence));
111+ }
112+
113 return QString("");
114 }
115
116@@ -219,6 +240,20 @@
117 return QString("");
118 }
119
120+QString
121+LauncherApplication::executable() const
122+{
123+ if (m_appInfo != NULL) {
124+ return QString::fromUtf8(g_app_info_get_executable((GAppInfo*)m_appInfo));
125+ }
126+
127+ if (m_snStartupSequence != NULL) {
128+ return QString::fromUtf8(sn_startup_sequence_get_binary_name(m_snStartupSequence));
129+ }
130+
131+ return QString("");
132+}
133+
134 void
135 LauncherApplication::setSticky(bool sticky)
136 {
137@@ -248,10 +283,13 @@
138 /* Emit the Changed signal on all properties that can depend on m_appInfo
139 m_application's properties take precedence over m_appInfo's
140 */
141- if (m_application == NULL && m_appInfo != NULL) {
142- emit desktopFileChanged(desktop_file);
143- emit nameChanged(name());
144- emit iconChanged(icon());
145+ if (m_appInfo != NULL) {
146+ if (m_application == NULL) {
147+ Q_EMIT desktopFileChanged(desktop_file);
148+ Q_EMIT nameChanged(name());
149+ Q_EMIT iconChanged(icon());
150+ }
151+ Q_EMIT executableChanged(executable());
152 }
153
154 monitorDesktopFile(this->desktop_file());
155@@ -262,6 +300,10 @@
156 {
157 /* Monitor the desktop file for live changes */
158 if (m_desktopFileWatcher == NULL) {
159+ /* FIXME: deleting a QFileSystemWatcher can be quite slow (sometimes
160+ around 100ms on a powerful computer) and can provoke visual glitches
161+ where the user interface is blocked for a short moment.
162+ */
163 m_desktopFileWatcher = new QFileSystemWatcher(this);
164 connect(m_desktopFileWatcher, SIGNAL(fileChanged(const QString&)),
165 SLOT(onDesktopFileChanged(const QString&)));
166@@ -385,6 +427,31 @@
167 }
168
169 void
170+LauncherApplication::setSnStartupSequence(SnStartupSequence* sequence)
171+{
172+ if (sequence != NULL) {
173+ if (!sn_startup_sequence_get_completed(sequence)) {
174+ /* 'launching' property becomes true for a few seconds */
175+ m_launching_timer.start();
176+ } else {
177+ m_launching_timer.stop();
178+ }
179+ sn_startup_sequence_ref(sequence);
180+ }
181+
182+ if (m_snStartupSequence != NULL) {
183+ sn_startup_sequence_unref(m_snStartupSequence);
184+ }
185+
186+ m_snStartupSequence = sequence;
187+
188+ emit nameChanged(name());
189+ emit iconChanged(icon());
190+ emit executableChanged(executable());
191+ emit launchingChanged(launching());
192+}
193+
194+void
195 LauncherApplication::setIconGeometry(int x, int y, int width, int height, uint xid)
196 {
197 if (m_application == NULL) {
198@@ -565,10 +632,9 @@
199 return false;
200 }
201
202- /* 'launching' property becomes true for a maximum of 8 seconds and becomes
203+ /* 'launching' property becomes true for a few seconds and becomes
204 false as soon as the application is launched */
205- m_launching_timer.setSingleShot(true);
206- m_launching_timer.start(8000);
207+ m_launching_timer.start();
208 emit launchingChanged(true);
209
210 return true;
211
212=== modified file 'launcher/UnityApplications/launcherapplication.h'
213--- launcher/UnityApplications/launcherapplication.h 2011-03-21 13:24:23 +0000
214+++ launcher/UnityApplications/launcherapplication.h 2011-03-23 16:50:54 +0000
215@@ -28,9 +28,11 @@
216 #include <QString>
217 #include <QTimer>
218 #include <QHash>
219+#include <QPointer>
220
221 #include "bamf-application.h"
222
223+struct SnStartupSequence;
224 class DBusMenuImporter;
225 class QFileSystemWatcher;
226
227@@ -42,6 +44,7 @@
228 Q_PROPERTY(bool sticky READ sticky WRITE setSticky NOTIFY stickyChanged)
229 Q_PROPERTY(QString application_type READ application_type NOTIFY applicationTypeChanged)
230 Q_PROPERTY(QString desktop_file READ desktop_file WRITE setDesktopFile NOTIFY desktopFileChanged)
231+ Q_PROPERTY(QString executable READ executable NOTIFY executableChanged)
232 Q_PROPERTY(bool has_visible_window READ has_visible_window NOTIFY hasVisibleWindowChanged)
233 Q_PROPERTY(float progress READ progress NOTIFY progressChanged)
234 Q_PROPERTY(bool progressBarVisible READ progressBarVisible NOTIFY progressBarVisibleChanged)
235@@ -65,6 +68,7 @@
236 virtual QString icon() const;
237 QString application_type() const;
238 QString desktop_file() const;
239+ QString executable() const;
240 virtual bool launching() const;
241 bool has_visible_window() const;
242 float progress() const;
243@@ -78,6 +82,7 @@
244 void setDesktopFile(const QString& desktop_file);
245 void setSticky(bool sticky);
246 void setBamfApplication(BamfApplication *application);
247+ void setSnStartupSequence(SnStartupSequence* sequence);
248
249 /* methods */
250 Q_INVOKABLE virtual void activate();
251@@ -95,6 +100,7 @@
252 void stickyChanged(bool);
253 void applicationTypeChanged(QString);
254 void desktopFileChanged(QString);
255+ void executableChanged(QString);
256 void hasVisibleWindowChanged(bool);
257 void progressBarVisibleChanged(bool);
258 void counterVisibleChanged(bool);
259@@ -132,9 +138,10 @@
260 void endForceUrgent();
261
262 private:
263- BamfApplication *m_application;
264+ QPointer<BamfApplication> m_application;
265 QFileSystemWatcher *m_desktopFileWatcher;
266 GDesktopAppInfo *m_appInfo;
267+ SnStartupSequence *m_snStartupSequence;
268 bool m_sticky;
269 QTimer m_launching_timer;
270 bool m_has_visible_window;
271
272=== modified file 'launcher/UnityApplications/launcherapplicationslist.cpp'
273--- launcher/UnityApplications/launcherapplicationslist.cpp 2011-03-16 13:50:14 +0000
274+++ launcher/UnityApplications/launcherapplicationslist.cpp 2011-03-23 16:50:54 +0000
275@@ -28,6 +28,12 @@
276 #include <QDebug>
277 #include <QDBusConnection>
278 #include <QFileInfo>
279+#include <QX11Info>
280+
281+extern "C" {
282+#include <libsn/sn.h>
283+}
284+
285
286 #define FAVORITES_KEY QString("/desktop/unity-2d/launcher/favorites")
287 #define DBUS_SERVICE_UNITY "com.canonical.Unity"
288@@ -69,10 +75,59 @@
289 }
290 }
291
292+ /* Register the display to receive startup notifications */
293+ Display *xdisplay = QX11Info::display();
294+ m_snDisplay = sn_display_new(xdisplay, NULL, NULL);
295+ m_snContext = sn_monitor_context_new(m_snDisplay, QX11Info::appScreen(),
296+ LauncherApplicationsList::snEventHandler,
297+ this, NULL);
298+ Unity2dApplication::instance()->installX11EventFilter(this);
299+
300 load();
301 }
302
303 void
304+LauncherApplicationsList::snEventHandler(SnMonitorEvent *event, void *user_data)
305+{
306+ /* This method is static and only forwards the event to a non static method. */
307+ ((LauncherApplicationsList*)user_data)->onSnMonitorEventReceived(event);
308+}
309+
310+void
311+LauncherApplicationsList::onSnMonitorEventReceived(SnMonitorEvent *event)
312+{
313+ SnStartupSequence *sequence = sn_monitor_event_get_startup_sequence(event);
314+
315+ switch (sn_monitor_event_get_type (event)) {
316+ case SN_MONITOR_EVENT_INITIATED:
317+ insertSnStartupSequence(sequence);
318+ break;
319+ case SN_MONITOR_EVENT_CHANGED:
320+ case SN_MONITOR_EVENT_COMPLETED:
321+ case SN_MONITOR_EVENT_CANCELED:
322+ /* These events are ignored for now. This is acceptable since the
323+ case of a failed application startup is handled by
324+ LauncherApplication::launching being automatically reset to
325+ false after a timeout. */
326+ break;
327+ }
328+}
329+
330+
331+bool
332+LauncherApplicationsList::x11EventFilter(XEvent* xevent)
333+{
334+ /* libsn specifies that all events need to be forwarded to
335+ sn_display_process_event but it is not actually necessary.
336+ Forwarding only the events of type ClientMessage.
337+ */
338+ if (xevent->type == ClientMessage) {
339+ sn_display_process_event(m_snDisplay, xevent);
340+ }
341+ return false;
342+}
343+
344+void
345 LauncherApplicationsList::onRemoteEntryUpdated(QString applicationURI, QMap<QString, QVariant> properties)
346 {
347 QString desktopFile;
348@@ -95,6 +150,10 @@
349
350 LauncherApplicationsList::~LauncherApplicationsList()
351 {
352+ Unity2dApplication::instance()->removeX11EventFilter(this);
353+ sn_monitor_context_unref(m_snContext);
354+ sn_display_unref(m_snDisplay);
355+
356 qDeleteAll(m_applications);
357 delete m_favorites_list;
358 }
359@@ -117,10 +176,14 @@
360 if (!application->desktop_file().isEmpty()) {
361 m_applicationForDesktopFile.insert(application->desktop_file(), application);
362 }
363+ if (!application->executable().isEmpty()) {
364+ m_applicationForExecutable.insert(application->executable(), application);
365+ }
366 endInsertRows();
367
368 QObject::connect(application, SIGNAL(closed()), this, SLOT(onApplicationClosed()));
369 QObject::connect(application, SIGNAL(stickyChanged(bool)), this, SLOT(onApplicationStickyChanged(bool)));
370+ QObject::connect(application, SIGNAL(launchingChanged(bool)), this, SLOT(onApplicationLaunchingChanged(bool)));
371 }
372
373 void
374@@ -128,12 +191,22 @@
375 {
376 int index = m_applications.indexOf(application);
377
378+ if (index == -1) {
379+ /* application is not present in m_applications */
380+ return;
381+ }
382+
383 beginRemoveRows(QModelIndex(), index, index);
384 m_applications.removeAt(index);
385 m_applicationForDesktopFile.remove(application->desktop_file());
386+ m_applicationForExecutable.remove(application->executable());
387 endRemoveRows();
388
389- delete application;
390+ /* LauncherApplicationsList::removeApplication might have been called in
391+ response to a signal emitted by application itself. Do not delete
392+ immediately to cater for this case.
393+ */
394+ application->deleteLater();
395 }
396
397 void LauncherApplicationsList::insertBamfApplication(BamfApplication* bamf_application)
398@@ -142,18 +215,30 @@
399 return;
400 }
401
402- LauncherApplication* application;
403+ LauncherApplication* matchingApplication = NULL;
404+ LauncherApplication* newApplication = new LauncherApplication;
405+ newApplication->setBamfApplication(bamf_application);
406
407- QString desktop_file = bamf_application->desktop_file();
408+ QString executable = newApplication->executable();
409+ QString desktop_file = newApplication->desktop_file();
410 if (m_applicationForDesktopFile.contains(desktop_file)) {
411 /* A LauncherApplication with the same desktop file already exists */
412- application = m_applicationForDesktopFile[desktop_file];
413- application->setBamfApplication(bamf_application);
414+ matchingApplication = m_applicationForDesktopFile[desktop_file];
415+ } else if (m_applicationForExecutable.contains(executable)) {
416+ /* A LauncherApplication with the same executable already exists */
417+ matchingApplication = m_applicationForExecutable[executable];
418+ }
419+
420+ if (matchingApplication != NULL) {
421+ /* A LauncherApplication that corresponds to bamf_application already exists */
422+ /* FIXME: this deletion blocks for a long time (around 100ms here) and
423+ leads to a visual glitch in the launcher when an application finished
424+ starting up. This is due to the deletion of the QFileSystemWatcher
425+ belonging to the LauncherApplication. */
426+ delete newApplication;
427+ matchingApplication->setBamfApplication(bamf_application);
428 } else {
429- /* Create a new LauncherApplication and append it to the list */
430- application = new LauncherApplication;
431- application->setBamfApplication(bamf_application);
432- insertApplication(application);
433+ insertApplication(newApplication);
434 }
435 }
436
437@@ -197,6 +282,26 @@
438 }
439
440 void
441+LauncherApplicationsList::insertSnStartupSequence(SnStartupSequence* sequence)
442+{
443+ if (sequence == NULL) {
444+ return;
445+ }
446+
447+ QString executable = sn_startup_sequence_get_binary_name(sequence);
448+
449+ if (m_applicationForExecutable.contains(executable)) {
450+ /* A LauncherApplication with the same executable already exists */
451+ m_applicationForExecutable[executable]->setSnStartupSequence(sequence);
452+ } else {
453+ /* Create a new LauncherApplication and append it to the list */
454+ LauncherApplication* newApplication = new LauncherApplication;
455+ newApplication->setSnStartupSequence(sequence);
456+ insertApplication(newApplication);
457+ }
458+}
459+
460+void
461 LauncherApplicationsList::load()
462 {
463 /* Insert favorites */
464@@ -257,6 +362,16 @@
465 }
466
467 void
468+LauncherApplicationsList::onApplicationLaunchingChanged(bool launching)
469+{
470+ LauncherApplication* application = static_cast<LauncherApplication*>(sender());
471+
472+ if (!application->sticky() && !application->running() && !application->launching()) {
473+ removeApplication(application);
474+ }
475+}
476+
477+void
478 LauncherApplicationsList::writeFavoritesToGConf()
479 {
480 QStringList favorites;
481
482=== modified file 'launcher/UnityApplications/launcherapplicationslist.h'
483--- launcher/UnityApplications/launcherapplicationslist.h 2011-03-21 13:24:23 +0000
484+++ launcher/UnityApplications/launcherapplicationslist.h 2011-03-23 16:50:54 +0000
485@@ -26,12 +26,18 @@
486 #include <QtDeclarative/qdeclarative.h>
487 #include <QMap>
488
489+#include <unity2dapplication.h>
490+
491+struct SnDisplay;
492+struct SnMonitorContext;
493+struct SnMonitorEvent;
494+struct SnStartupSequence;
495 class LauncherApplication;
496 class BamfApplication;
497 class BamfView;
498 class GConfItemQmlWrapper;
499
500-class LauncherApplicationsList : public QAbstractListModel
501+class LauncherApplicationsList : public QAbstractListModel, protected AbstractX11EventFilter
502 {
503 Q_OBJECT
504 friend class LauncherApplicationsListDBUS;
505@@ -49,9 +55,13 @@
506 public Q_SLOTS:
507 void move(int from, int to);
508
509+protected:
510+ bool x11EventFilter(XEvent* xevent);
511+
512 private:
513 void load();
514 void insertBamfApplication(BamfApplication* bamf_application);
515+ void insertSnStartupSequence(SnStartupSequence* sequence);
516
517 void insertApplication(LauncherApplication* application);
518 void removeApplication(LauncherApplication* application);
519@@ -68,13 +78,25 @@
520 displayed (m_applications).
521 */
522 QHash<QString, LauncherApplication*> m_applicationForDesktopFile;
523-
524+ /* Hash of application executables to LauncherApplication used to reduce
525+ the algorithmical complexity of merging the list of launching applications
526+ and the list of running applications into the list of applications
527+ displayed (m_applications).
528+ */
529+ QHash<QString, LauncherApplication*> m_applicationForExecutable;
530 GConfItemQmlWrapper* m_favorites_list;
531
532+ /* Startup notification support */
533+ SnDisplay *m_snDisplay;
534+ SnMonitorContext *m_snContext;
535+ static void snEventHandler(SnMonitorEvent *event, void *user_data);
536+ void onSnMonitorEventReceived(SnMonitorEvent *event);
537+
538 private Q_SLOTS:
539 void onApplicationClosed();
540 void onBamfViewOpened(BamfView* bamf_view);
541 void onApplicationStickyChanged(bool sticky);
542+ void onApplicationLaunchingChanged(bool launching);
543 void onRemoteEntryUpdated(QString applicationURI,
544 QMap<QString, QVariant> properties);
545 };

Subscribers

People subscribed via source and target branches