Merge lp:~fboucault/unity-2d/startup_notification into lp:unity-2d/3.0
- startup_notification
- Merge into natty
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Olivier Tilloy (community) | Approve | ||
Review via email: mp+54435@code.launchpad.net |
Commit message
Description of the change
[launcher] Added support for startup notification protocol.
Launcher now depends on libstartup-
New APIs:
- LauncherApplica
- LauncherApplica
LauncherApplica
LauncherApplica
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.
Olivier Tilloy (osomon) wrote : | # |
In fact simply launching nautilus from the favorite icon in the launcher exhibits the same problem.
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.
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 LauncherApplica
Olivier Tilloy (osomon) wrote : | # |
In launcher/
m_launching
It would be better to set the interval of the timer only once, when it’s instantiated, and then only call .start().
Olivier Tilloy (osomon) wrote : | # |
In launcher/
/* 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_memberNameInC
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 ;)
Olivier Tilloy (osomon) wrote : | # |
In launcher/
private:
[…]
/* Startup notification support */
[…]
bool x11EventFilter(
In the mother class (AbstractX11Eve
Olivier Tilloy (osomon) wrote : | # |
In LauncherApplica
Shouldn’t m_sn_display be unref’ed, just like m_sn_context is unref’ed (there is a sn_display_unref(…) function)?
Olivier Tilloy (osomon) wrote : | # |
In LauncherApplica
sn_monitor_
Instead of DefaultScreen(
- 478. By Florian Boucault
-
Merged from trunk.
- 479. By Florian Boucault
-
Added libstartup-
notification0- dev to build dependencies.
Olivier Tilloy (osomon) wrote : | # |
In LauncherApplica
in the if statement, you can replace "application-
- 480. By Florian Boucault
-
LauncherApplica
tion: set the launching timeout interval only once. - 481. By Florian Boucault
-
LauncherApplica
tionsList: converted m_sn_display and m_sn_context to camel case. - 482. By Florian Boucault
-
LauncherApplica
tionsList: made x11EventFilter protected. - 483. By Florian Boucault
-
LauncherApplica
tionsList: unref m_snDisplay upon destruction. - 484. By Florian Boucault
-
LauncherApplica
tionsList: use the screen where the launcher is displayed.
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 LauncherApplica
> 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.
Olivier Tilloy (osomon) wrote : | # |
> In LauncherApplica
>
> in the if statement, you can replace "application-
> "launching", and put it first in the condition.
Forget about this, as you pointed out this code should be shared between the three slots (onApplicationC
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.
Olivier Tilloy (osomon) wrote : | # |
I filed bug #741160 and bug #741168 to track the two issues mentioned above.
Preview Diff
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 | }; |
The packages’ Build-Depends need to include libstartup- notification0- dev.