Merge lp:~3v1n0/unity/quicklist-hide-fix into lp:unity

Proposed by Marco Trevisan (Treviño)
Status: Merged
Approved by: Gord Allott
Approved revision: no longer in the source branch.
Merged at revision: 1514
Proposed branch: lp:~3v1n0/unity/quicklist-hide-fix
Merge into: lp:unity
Diff against target: 513 lines (+200/-114)
3 files modified
plugins/unityshell/src/BamfLauncherIcon.cpp (+193/-113)
plugins/unityshell/src/BamfLauncherIcon.h (+4/-1)
plugins/unityshell/src/LauncherIcon.cpp (+3/-0)
To merge this branch: bzr merge lp:~3v1n0/unity/quicklist-hide-fix
Reviewer Review Type Date Requested Status
Gord Allott (community) Approve
Review via email: mp+74371@code.launchpad.net

Description of the change

This branch includes various fixes for the QuickList handling such as:
 - Correct hiding of quicklist items and quicklist roots (including not showing unneeded separators, see more at bug #843425).
 - Support for monitoring .desktop file changes to dynamically update the "static" quicklist generated using the launcher .desktop file
 - Some memory optimizations and fix of memory leaks
 - Fixed a bug causing unity to crash if removing launcher with an open quicklist (bug #801413)

To post a comment you must log in.
Revision history for this message
Gord Allott (gordallott) wrote :

+1 thanks!

Revision history for this message
Gord Allott (gordallott) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/unityshell/src/BamfLauncherIcon.cpp'
2--- plugins/unityshell/src/BamfLauncherIcon.cpp 2011-08-30 16:48:12 +0000
3+++ plugins/unityshell/src/BamfLauncherIcon.cpp 2011-09-07 09:42:19 +0000
4@@ -144,6 +144,7 @@
5 _dnd_hovered = false;
6 _launcher = IconManager;
7 _menu_desktop_shortcuts = NULL;
8+ _on_desktop_file_changed_handler_id = 0;
9 char* icon_name = bamf_view_get_icon(BAMF_VIEW(m_App));
10
11 tooltip_text = BamfName();
12@@ -173,17 +174,7 @@
13 EnsureWindowState();
14 UpdateMenus();
15
16- // add a file watch to the desktop file so that if/when the app is removed we can remove ourself from the launcher.
17- GFile* _desktop_file = g_file_new_for_path(DesktopFile());
18- _desktop_file_monitor = g_file_monitor_file(_desktop_file,
19- G_FILE_MONITOR_NONE,
20- NULL,
21- NULL);
22-
23- _on_desktop_file_changed_handler_id = g_signal_connect(_desktop_file_monitor,
24- "changed",
25- G_CALLBACK(&BamfLauncherIcon::OnDesktopFileChanged),
26- this);
27+ UpdateDesktopFile();
28
29 WindowManager::Default()->window_minimized.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnWindowMinimized));
30 WindowManager::Default()->compiz_screen_viewport_switch_ended.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnViewPortSwitchEnded));
31@@ -192,7 +183,7 @@
32
33 // hack
34 SetProgress(0.0f);
35-
36+
37 // Calls when there are no higher priority events pending to the default main loop.
38 _fill_supported_types_id = g_idle_add((GSourceFunc)FillSupportedTypes, this);
39
40@@ -203,22 +194,40 @@
41 g_object_set_qdata(G_OBJECT(m_App), g_quark_from_static_string("unity-seen"), GINT_TO_POINTER(0));
42
43 // We might not have created the menu items yet
44+ for (auto it = _menu_clients.begin(); it != _menu_clients.end(); it++)
45+ {
46+ g_object_unref(G_OBJECT(it->second));
47+ }
48+
49 if (_menu_items.find("Pin") != _menu_items.end())
50 {
51- g_signal_handler_disconnect((gpointer) _menu_items["Pin"],
52+ g_signal_handler_disconnect(G_OBJECT(_menu_items["Pin"]),
53 _menu_callbacks["Pin"]);
54 }
55
56 if (_menu_items.find("Quit") != _menu_items.end())
57 {
58- g_signal_handler_disconnect((gpointer) _menu_items["Quit"],
59+ g_signal_handler_disconnect(G_OBJECT(_menu_items["Quit"]),
60 _menu_callbacks["Quit"]);
61 }
62
63+ for (auto it = _menu_items.begin(); it != _menu_items.end(); it++)
64+ {
65+ g_object_unref(G_OBJECT(it->second));
66+ }
67+
68+ for (auto it = _menu_items_extra.begin(); it != _menu_items_extra.end(); it++)
69+ {
70+ g_object_unref(G_OBJECT(it->second));
71+ }
72+
73+ if (G_IS_OBJECT(_menu_desktop_shortcuts))
74+ g_object_unref(G_OBJECT(_menu_desktop_shortcuts));
75+
76 if (_on_desktop_file_changed_handler_id != 0)
77- g_signal_handler_disconnect((gpointer) _desktop_file_monitor,
78+ g_signal_handler_disconnect(G_OBJECT(_desktop_file_monitor),
79 _on_desktop_file_changed_handler_id);
80-
81+
82 if (_fill_supported_types_id != 0)
83 g_source_remove(_fill_supported_types_id);
84
85@@ -322,19 +331,40 @@
86 return bamf_view_is_sticky(BAMF_VIEW(m_App));
87 }
88
89-const char* BamfLauncherIcon::DesktopFile()
90+void BamfLauncherIcon::UpdateDesktopFile()
91 {
92 char* filename = NULL;
93 filename = (char*) bamf_application_get_desktop_file(m_App);
94
95- if (filename != NULL)
96+ if (filename != NULL && g_strcmp0(_cached_desktop_file, filename) != 0)
97 {
98 if (_cached_desktop_file != NULL)
99 g_free(_cached_desktop_file);
100
101 _cached_desktop_file = g_strdup(filename);
102+
103+ // add a file watch to the desktop file so that if/when the app is removed
104+ // we can remove ourself from the launcher and when it's changed
105+ // we can update the quicklist.
106+
107+ if (_on_desktop_file_changed_handler_id != 0)
108+ g_signal_handler_disconnect(G_OBJECT(_desktop_file_monitor),
109+ _on_desktop_file_changed_handler_id);
110+
111+ GFile* desktop_file = g_file_new_for_path(DesktopFile());
112+ _desktop_file_monitor = g_file_monitor_file(desktop_file, G_FILE_MONITOR_NONE,
113+ NULL, NULL);
114+ g_file_monitor_set_rate_limit (_desktop_file_monitor, 1000);
115+ _on_desktop_file_changed_handler_id = g_signal_connect(_desktop_file_monitor,
116+ "changed",
117+ G_CALLBACK(&BamfLauncherIcon::OnDesktopFileChanged),
118+ this);
119 }
120+}
121
122+const char* BamfLauncherIcon::DesktopFile()
123+{
124+ UpdateDesktopFile();
125 return _cached_desktop_file;
126 }
127
128@@ -357,7 +387,7 @@
129 {
130 LauncherIcon::AddProperties(builder);
131
132- g_variant_builder_add(builder, "{sv}", "desktop-file", g_variant_new_string(bamf_application_get_desktop_file(m_App)));
133+ g_variant_builder_add(builder, "{sv}", "desktop-file", g_variant_new_string(DesktopFile()));
134
135 GList* children, *l;
136 BamfView* view;
137@@ -414,7 +444,7 @@
138 GDesktopAppInfo* appInfo;
139 GError* error = NULL;
140
141- appInfo = g_desktop_app_info_new_from_filename(bamf_application_get_desktop_file(BAMF_APPLICATION(m_App)));
142+ appInfo = g_desktop_app_info_new_from_filename(DesktopFile());
143
144 if (g_app_info_supports_uris(G_APP_INFO(appInfo)))
145 {
146@@ -613,10 +643,83 @@
147 self->EnsureWindowState();
148 }
149
150+void BamfLauncherIcon::UpdateDesktopQuickList()
151+{
152+ IndicatorDesktopShortcuts* desktop_shortcuts;
153+ GKeyFile* keyfile;
154+ GError* error = NULL;
155+ const char *desktop_file;
156+
157+ desktop_file = DesktopFile();
158+
159+ if (!desktop_file || g_strcmp0(desktop_file, "") == 0)
160+ return;
161+
162+ // check that we have the X-Ayatana-Desktop-Shortcuts flag
163+ // not sure if we should do this or if libindicator should shut up
164+ // and not report errors when it can't find the key.
165+ // so FIXME when ted is around
166+ keyfile = g_key_file_new();
167+ g_key_file_load_from_file(keyfile, desktop_file, G_KEY_FILE_NONE, &error);
168+
169+ if (error != NULL)
170+ {
171+ g_warning("Could not load desktop file for: %s", desktop_file);
172+ g_key_file_free(keyfile);
173+ g_error_free(error);
174+ return;
175+ }
176+
177+ if (g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP,
178+ "X-Ayatana-Desktop-Shortcuts", NULL))
179+ {
180+ DbusmenuMenuitem* root = dbusmenu_menuitem_new();
181+ dbusmenu_menuitem_set_root(root, TRUE);
182+ desktop_shortcuts = indicator_desktop_shortcuts_new(desktop_file, "Unity");
183+ const gchar** nicks = indicator_desktop_shortcuts_get_nicks(desktop_shortcuts);
184+
185+ int index = 0;
186+ if (nicks)
187+ {
188+ while (((gpointer*) nicks)[index])
189+ {
190+ gchar* name;
191+ DbusmenuMenuitem* item;
192+ name = indicator_desktop_shortcuts_nick_get_name(desktop_shortcuts,
193+ nicks[index]);
194+ ShortcutData* data = g_slice_new0(ShortcutData);
195+ data->self = this;
196+ data->shortcuts = INDICATOR_DESKTOP_SHORTCUTS(g_object_ref(desktop_shortcuts));
197+ data->nick = g_strdup(nicks[index]);
198+
199+ item = dbusmenu_menuitem_new();
200+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name);
201+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
202+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
203+ g_signal_connect_data(item, "item-activated",
204+ (GCallback) shortcut_activated, (gpointer) data,
205+ (GClosureNotify) shortcut_data_destroy, (GConnectFlags)0);
206+
207+ dbusmenu_menuitem_child_append(root, item);
208+
209+ index++;
210+
211+ g_free(name);
212+ }
213+ }
214+
215+ if (G_IS_OBJECT(_menu_desktop_shortcuts))
216+ g_object_unref(G_OBJECT(_menu_desktop_shortcuts));
217+
218+ _menu_desktop_shortcuts = root;
219+ }
220+
221+ g_key_file_free(keyfile);
222+}
223+
224 void BamfLauncherIcon::UpdateMenus()
225 {
226 GList* children, *l;
227- IndicatorDesktopShortcuts* desktop_shortcuts;
228
229 children = bamf_view_get_children(BAMF_VIEW(m_App));
230 for (l = children; l; l = l->next)
231@@ -639,73 +742,15 @@
232
233 // add dynamic quicklist
234 if (_menuclient_dynamic_quicklist != NULL)
235- _menu_clients["dynamicquicklist"] = _menuclient_dynamic_quicklist;
236+ {
237+ auto menu_client = DBUSMENU_CLIENT(g_object_ref(_menuclient_dynamic_quicklist));
238+ _menu_clients["dynamicquicklist"] = menu_client;
239+ }
240
241 // make a client for desktop file actions
242- if (!DBUSMENU_IS_MENUITEM(_menu_desktop_shortcuts) &&
243- g_strcmp0(DesktopFile(), """"))
244+ if (!DBUSMENU_IS_MENUITEM(_menu_desktop_shortcuts))
245 {
246- GKeyFile* keyfile;
247- GError* error = NULL;
248-
249- // check that we have the X-Ayatana-Desktop-Shortcuts flag
250- // not sure if we should do this or if libindicator should shut up
251- // and not report errors when it can't find the key.
252- // so FIXME when ted is around
253- keyfile = g_key_file_new();
254- g_key_file_load_from_file(keyfile, DesktopFile(), G_KEY_FILE_NONE, &error);
255-
256- if (error != NULL)
257- {
258- g_warning("Could not load desktop file for: %s" , DesktopFile());
259- g_error_free(error);
260- return;
261- }
262-
263- if (g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP,
264- "X-Ayatana-Desktop-Shortcuts", NULL))
265- {
266- DbusmenuMenuitem* root = dbusmenu_menuitem_new();
267- dbusmenu_menuitem_set_root(root, TRUE);
268- desktop_shortcuts = indicator_desktop_shortcuts_new(bamf_application_get_desktop_file(m_App),
269- "Unity");
270- const gchar** nicks = indicator_desktop_shortcuts_get_nicks(desktop_shortcuts);
271-
272- int index = 0;
273- if (nicks)
274- {
275- while (((gpointer*) nicks)[index])
276- {
277- gchar* name;
278- DbusmenuMenuitem* item;
279- name = indicator_desktop_shortcuts_nick_get_name(desktop_shortcuts,
280- nicks[index]);
281- ShortcutData* data = g_slice_new0(ShortcutData);
282- data->self = this;
283- data->shortcuts = INDICATOR_DESKTOP_SHORTCUTS(g_object_ref(desktop_shortcuts));
284- data->nick = g_strdup(nicks[index]);
285-
286- item = dbusmenu_menuitem_new();
287- dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name);
288- dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
289- dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
290- g_signal_connect_data(item, "item-activated",
291- (GCallback) shortcut_activated, (gpointer) data,
292- (GClosureNotify) shortcut_data_destroy, (GConnectFlags)0);
293-
294- dbusmenu_menuitem_child_append(root, item);
295-
296- index++;
297-
298- g_free(name);
299- }
300- }
301-
302- // TODO: check unref prior to assign, and add unref to destructor.
303- _menu_desktop_shortcuts = root;
304- g_key_file_free(keyfile);
305-
306- }
307+ UpdateDesktopQuickList();
308 }
309
310 }
311@@ -738,7 +783,7 @@
312 if (!bamf_view_is_sticky(view))
313 return;
314
315- const gchar* desktop_file = bamf_application_get_desktop_file(this->m_App);
316+ const gchar* desktop_file = DesktopFile();
317 bamf_view_set_sticky(view, false);
318 if (bamf_view_is_closed(view))
319 this->Remove();
320@@ -751,7 +796,7 @@
321 {
322 BamfView* view = BAMF_VIEW(self->m_App);
323 bool sticky = bamf_view_is_sticky(view);
324- const gchar* desktop_file = bamf_application_get_desktop_file(self->m_App);
325+ const gchar* desktop_file = self->DesktopFile();
326
327 if (sticky)
328 {
329@@ -774,7 +819,6 @@
330 if (_menu_items.find("Pin") == _menu_items.end())
331 {
332 menu_item = dbusmenu_menuitem_new();
333- g_object_ref(menu_item);
334
335 dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_CHECK);
336 dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Keep in launcher"));
337@@ -797,7 +841,6 @@
338 if (_menu_items.find("Quit") == _menu_items.end())
339 {
340 menu_item = dbusmenu_menuitem_new();
341- g_object_ref(menu_item);
342
343 dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit"));
344 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
345@@ -838,16 +881,22 @@
346 DbusmenuClient* client = (*it).second;
347 DbusmenuMenuitem* root = dbusmenu_client_get_root(client);
348
349+ if (!root || !dbusmenu_menuitem_property_get_bool(root, DBUSMENU_MENUITEM_PROP_VISIBLE))
350+ continue;
351+
352 for (child = dbusmenu_menuitem_get_children(root); child != NULL; child = g_list_next(child))
353 {
354 DbusmenuMenuitem* item = (DbusmenuMenuitem*) child->data;
355
356- if (!item)
357+ if (!item || !DBUSMENU_IS_MENUITEM(item))
358 continue;
359
360- first_separator_needed = true;
361+ if (dbusmenu_menuitem_property_get_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE))
362+ {
363+ first_separator_needed = true;
364
365- result.push_back(item);
366+ result.push_back(item);
367+ }
368 }
369 }
370
371@@ -872,31 +921,59 @@
372
373 if (first_separator_needed)
374 {
375+ auto first_sep = _menu_items_extra.find("FirstSeparator");
376+ if (first_sep != _menu_items_extra.end())
377+ {
378+ item = first_sep->second;
379+ }
380+ else
381+ {
382+ item = dbusmenu_menuitem_new();
383+ dbusmenu_menuitem_property_set(item,
384+ DBUSMENU_MENUITEM_PROP_TYPE,
385+ DBUSMENU_CLIENT_TYPES_SEPARATOR);
386+ _menu_items_extra["FirstSeparator"] = item;
387+ }
388+ result.push_back(item);
389+ }
390+
391+ auto app_name_item = _menu_items_extra.find("AppName");
392+ if (app_name_item != _menu_items_extra.end())
393+ {
394+ item = app_name_item->second;
395+ }
396+ else
397+ {
398+ gchar* app_name;
399+ app_name = g_markup_escape_text(BamfName(), -1);
400+
401+ item = dbusmenu_menuitem_new();
402+ dbusmenu_menuitem_property_set(item,
403+ DBUSMENU_MENUITEM_PROP_LABEL,
404+ app_name);
405+ dbusmenu_menuitem_property_set_bool(item,
406+ DBUSMENU_MENUITEM_PROP_ENABLED,
407+ true);
408+ g_signal_connect(item, "item-activated", (GCallback) OnAppLabelActivated, this);
409+ g_free(app_name);
410+
411+ _menu_items_extra["AppName"] = item;
412+ }
413+ result.push_back(item);
414+
415+ auto second_sep = _menu_items_extra.find("SecondSeparator");
416+ if (second_sep != _menu_items_extra.end())
417+ {
418+ item = second_sep->second;
419+ }
420+ else
421+ {
422 item = dbusmenu_menuitem_new();
423 dbusmenu_menuitem_property_set(item,
424 DBUSMENU_MENUITEM_PROP_TYPE,
425 DBUSMENU_CLIENT_TYPES_SEPARATOR);
426- result.push_back(item);
427+ _menu_items_extra["SecondSeparator"] = item;
428 }
429-
430- gchar* app_name;
431- app_name = g_markup_escape_text(BamfName(), -1);
432-
433- item = dbusmenu_menuitem_new();
434- dbusmenu_menuitem_property_set(item,
435- DBUSMENU_MENUITEM_PROP_LABEL,
436- app_name);
437- dbusmenu_menuitem_property_set_bool(item,
438- DBUSMENU_MENUITEM_PROP_ENABLED,
439- true);
440- g_signal_connect(item, "item-activated", (GCallback) OnAppLabelActivated, this);
441- result.push_back(item);
442- g_free(app_name);
443-
444- item = dbusmenu_menuitem_new();
445- dbusmenu_menuitem_property_set(item,
446- DBUSMENU_MENUITEM_PROP_TYPE,
447- DBUSMENU_CLIENT_TYPES_SEPARATOR);
448 result.push_back(item);
449
450 EnsureMenuItemsReady();
451@@ -978,7 +1055,7 @@
452 {
453 if (!_remote_uri)
454 {
455- const gchar* desktop_file = bamf_application_get_desktop_file(BAMF_APPLICATION(m_App));
456+ const gchar* desktop_file = DesktopFile();
457 gchar* basename = g_path_get_basename(desktop_file);
458
459 _remote_uri = g_strdup_printf("application://%s", basename);
460@@ -1053,6 +1130,9 @@
461 case G_FILE_MONITOR_EVENT_DELETED:
462 self->UnStick();
463 break;
464+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
465+ self->UpdateDesktopQuickList();
466+ break;
467 default:
468 break;
469 }
470
471=== modified file 'plugins/unityshell/src/BamfLauncherIcon.h'
472--- plugins/unityshell/src/BamfLauncherIcon.h 2011-08-30 16:48:12 +0000
473+++ plugins/unityshell/src/BamfLauncherIcon.h 2011-09-07 09:42:19 +0000
474@@ -81,6 +81,7 @@
475 Launcher* _launcher;
476 std::map<std::string, DbusmenuClient*> _menu_clients;
477 std::map<std::string, DbusmenuMenuitem*> _menu_items;
478+ std::map<std::string, DbusmenuMenuitem*> _menu_items_extra;
479 std::map<std::string, gulong> _menu_callbacks;
480 DbusmenuMenuitem* _menu_desktop_shortcuts;
481 gchar* _remote_uri;
482@@ -92,14 +93,16 @@
483
484 GFileMonitor* _desktop_file_monitor;
485 gulong _on_desktop_file_changed_handler_id;
486-
487+
488 std::set<std::string> _supported_types;
489 bool _supported_types_filled;
490 guint _fill_supported_types_id;
491
492 void EnsureWindowState();
493
494+ void UpdateDesktopFile();
495 void UpdateMenus();
496+ void UpdateDesktopQuickList();
497
498 void OpenInstanceWithUris(std::set<std::string> uris);
499 void Focus();
500
501=== modified file 'plugins/unityshell/src/LauncherIcon.cpp'
502--- plugins/unityshell/src/LauncherIcon.cpp 2011-09-01 01:55:36 +0000
503+++ plugins/unityshell/src/LauncherIcon.cpp 2011-09-07 09:42:19 +0000
504@@ -763,6 +763,9 @@
505 void
506 LauncherIcon::Remove()
507 {
508+ if (_quicklist->IsVisible())
509+ _quicklist->Hide();
510+
511 SetQuirk(QUIRK_VISIBLE, false);
512 remove.emit(this);
513 }