Merge lp:~attente/unity-gtk-module/1208019-2 into lp:unity-gtk-module/14.04

Proposed by William Hua
Status: Merged
Approved by: Iain Lane
Approved revision: 335
Merged at revision: 335
Proposed branch: lp:~attente/unity-gtk-module/1208019-2
Merge into: lp:unity-gtk-module/14.04
Diff against target: 895 lines (+442/-230)
7 files modified
lib/unity-gtk-action-group.c (+269/-161)
lib/unity-gtk-action-private.h (+19/-15)
lib/unity-gtk-action.c (+14/-0)
lib/unity-gtk-menu-item-private.h (+3/-1)
lib/unity-gtk-menu-item.c (+88/-26)
lib/unity-gtk-menu-section.c (+40/-25)
lib/unity-gtk-menu-shell.c (+9/-2)
To merge this branch: bzr merge lp:~attente/unity-gtk-module/1208019-2
Reviewer Review Type Date Requested Status
Ted Gould (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+216964@code.launchpad.net

Commit message

Forward show and hide signals to GTK+ menus.

Description of the change

Forward show and hide signals to GTK+ menus.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
328. By William Hua

Explain what we're doing.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ted Gould (ted) wrote :

I thought we got a signal when menus opened if we defined an action to receive it. Can we use that?

review: Needs Information
Revision history for this message
William Hua (attente) wrote :

The module already exports an action for every menu item (except separators), but it doesn't seem like we get a signal for menu items with a submenu.

Revision history for this message
William Hua (attente) wrote :

I didn't try it in code, this was only by looking through the dbus-monitor logs though.

329. By William Hua

Add submenu actions.

330. By William Hua

Don't eagerly show.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
331. By William Hua

Remove debugging output.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
William Hua (attente) wrote :

We need to backport the GTK+ patch on this bug report for this branch to work properly:

https://bugzilla.gnome.org/show_bug.cgi?id=729820

332. By William Hua

Dispatch hide in idle.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
333. By William Hua

Fix accelerators.

334. By William Hua

Rename label to label_label.

335. By William Hua

Watch contents of menu items.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ted Gould (ted) wrote :

Don't see anything. Feel like I should complain more. Thanks for adjusting this to use the submenu actions, a lot more code, but I think a cleaner solution!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/unity-gtk-action-group.c'
2--- lib/unity-gtk-action-group.c 2014-03-25 21:48:16 +0000
3+++ lib/unity-gtk-action-group.c 2014-05-19 16:34:24 +0000
4@@ -42,6 +42,14 @@
5
6 static gboolean unity_gtk_action_group_debug;
7
8+static gboolean
9+g_signal_emit_hide (gpointer user_data)
10+{
11+ g_signal_emit_by_name (user_data, "hide");
12+
13+ return G_SOURCE_REMOVE;
14+}
15+
16 static void
17 unity_gtk_action_group_handle_group_action_added (GActionGroup *action_group,
18 gchar *action_name,
19@@ -272,54 +280,79 @@
20
21 if (action != NULL)
22 {
23- if (action->items_by_name != NULL)
24+ if (g_strcmp0 (name, action->name) == 0)
25 {
26- if (value != NULL)
27- {
28- const gchar *name;
29- UnityGtkMenuItem *item;
30-
31- g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING));
32-
33- name = g_variant_get_string (value, NULL);
34- item = g_hash_table_lookup (action->items_by_name, name);
35-
36- if (item == NULL || !unity_gtk_menu_item_is_check (item))
37- {
38- g_warn_if_reached ();
39-
40- value = NULL;
41- }
42- else
43- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item->menu_item), TRUE);
44- }
45-
46- if (value == NULL)
47- {
48- GHashTableIter iter;
49- gpointer value;
50-
51- g_hash_table_iter_init (&iter, action->items_by_name);
52- while (g_hash_table_iter_next (&iter, NULL, &value))
53- {
54- UnityGtkMenuItem *item = value;
55-
56- if (unity_gtk_menu_item_is_check (item))
57- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item->menu_item), FALSE);
58- }
59- }
60+ if (action->items_by_name != NULL)
61+ {
62+ if (value != NULL)
63+ {
64+ const gchar *name;
65+ UnityGtkMenuItem *item;
66+
67+ g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING));
68+
69+ name = g_variant_get_string (value, NULL);
70+ item = g_hash_table_lookup (action->items_by_name, name);
71+
72+ if (item == NULL || !unity_gtk_menu_item_is_check (item))
73+ {
74+ g_warn_if_reached ();
75+
76+ value = NULL;
77+ }
78+ else
79+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item->menu_item), TRUE);
80+ }
81+
82+ if (value == NULL)
83+ {
84+ GHashTableIter iter;
85+ gpointer value;
86+
87+ g_hash_table_iter_init (&iter, action->items_by_name);
88+ while (g_hash_table_iter_next (&iter, NULL, &value))
89+ {
90+ UnityGtkMenuItem *item = value;
91+
92+ if (unity_gtk_menu_item_is_check (item))
93+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item->menu_item), FALSE);
94+ }
95+ }
96+ }
97+ else if (action->item != NULL && unity_gtk_menu_item_is_check (action->item))
98+ {
99+ g_return_if_fail (value != NULL && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN));
100+
101+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (action->item->menu_item), g_variant_get_boolean (value));
102+ }
103+ else
104+ g_warn_if_fail (value == NULL);
105+
106+ return;
107 }
108- else if (action->item != NULL && unity_gtk_menu_item_is_check (action->item))
109+ else if (g_strcmp0 (name, action->subname) == 0)
110 {
111+ GtkWidget *submenu;
112+
113 g_return_if_fail (value != NULL && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN));
114-
115- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (action->item->menu_item), g_variant_get_boolean (value));
116+ g_return_if_fail (action->item != NULL && action->item->menu_item != NULL);
117+
118+ submenu = gtk_menu_item_get_submenu (action->item->menu_item);
119+
120+ g_return_if_fail (submenu != NULL);
121+
122+ if (g_variant_get_boolean (value))
123+ g_signal_emit_by_name (submenu, "show");
124+ else
125+ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, g_signal_emit_hide, g_object_ref (submenu), g_object_unref);
126+
127+ return;
128 }
129 else
130- g_warn_if_fail (value == NULL);
131-
132- return;
133+ g_warn_if_reached ();
134 }
135+ else
136+ g_warn_if_reached ();
137 }
138 else
139 g_warn_if_reached ();
140@@ -359,33 +392,40 @@
141
142 if (action != NULL)
143 {
144- if (action->items_by_name != NULL)
145- {
146- const gchar *name;
147- UnityGtkMenuItem *item;
148-
149- g_return_if_fail (parameter != NULL && g_variant_is_of_type (parameter, G_VARIANT_TYPE_STRING));
150-
151- name = g_variant_get_string (parameter, NULL);
152- item = g_hash_table_lookup (action->items_by_name, name);
153-
154- if (item != NULL)
155- unity_gtk_menu_item_activate (item);
156-
157- g_action_group_action_state_changed (G_ACTION_GROUP (group), action->name, parameter);
158- }
159- else if (action->item != NULL)
160- {
161- if (unity_gtk_menu_item_get_draw_as_radio (action->item))
162- g_warn_if_fail (g_variant_is_of_type (parameter, G_VARIANT_TYPE_STRING));
163- else
164- g_warn_if_fail (parameter == NULL);
165-
166- unity_gtk_menu_item_activate (action->item);
167- }
168-
169- return;
170+ if (g_strcmp0 (name, action->name) == 0)
171+ {
172+ if (action->items_by_name != NULL)
173+ {
174+ const gchar *name;
175+ UnityGtkMenuItem *item;
176+
177+ g_return_if_fail (parameter != NULL && g_variant_is_of_type (parameter, G_VARIANT_TYPE_STRING));
178+
179+ name = g_variant_get_string (parameter, NULL);
180+ item = g_hash_table_lookup (action->items_by_name, name);
181+
182+ if (item != NULL)
183+ unity_gtk_menu_item_activate (item);
184+
185+ g_action_group_action_state_changed (G_ACTION_GROUP (group), action->name, parameter);
186+ }
187+ else if (action->item != NULL)
188+ {
189+ if (unity_gtk_menu_item_get_draw_as_radio (action->item))
190+ g_warn_if_fail (g_variant_is_of_type (parameter, G_VARIANT_TYPE_STRING));
191+ else
192+ g_warn_if_fail (parameter == NULL);
193+
194+ unity_gtk_menu_item_activate (action->item);
195+ }
196+
197+ return;
198+ }
199+ else
200+ g_warn_if_reached ();
201 }
202+ else
203+ g_warn_if_reached ();
204 }
205 else
206 g_warn_if_reached ();
207@@ -419,111 +459,142 @@
208
209 if (action != NULL)
210 {
211- if (enabled != NULL)
212+ if (g_strcmp0 (name, action->name) == 0)
213 {
214- if (action->items_by_name != NULL)
215- {
216- GHashTableIter iter;
217- gpointer value;
218-
219- *enabled = FALSE;
220-
221- g_hash_table_iter_init (&iter, action->items_by_name);
222- while (!*enabled && g_hash_table_iter_next (&iter, NULL, &value))
223- *enabled = unity_gtk_menu_item_is_sensitive (value);
224- }
225- else
226- *enabled = action->item != NULL && unity_gtk_menu_item_is_sensitive (action->item);
227+ if (enabled != NULL)
228+ {
229+ if (action->items_by_name != NULL)
230+ {
231+ GHashTableIter iter;
232+ gpointer value;
233+
234+ *enabled = FALSE;
235+
236+ g_hash_table_iter_init (&iter, action->items_by_name);
237+ while (!*enabled && g_hash_table_iter_next (&iter, NULL, &value))
238+ *enabled = unity_gtk_menu_item_is_sensitive (value);
239+ }
240+ else
241+ *enabled = action->item != NULL && unity_gtk_menu_item_is_sensitive (action->item);
242+ }
243+
244+ if (parameter_type != NULL)
245+ {
246+ if (action->items_by_name != NULL || (action->item != NULL && unity_gtk_menu_item_get_draw_as_radio (action->item)))
247+ *parameter_type = G_VARIANT_TYPE_STRING;
248+ else
249+ *parameter_type = NULL;
250+ }
251+
252+ if (state_type != NULL)
253+ {
254+ if (action->items_by_name != NULL || (action->item != NULL && unity_gtk_menu_item_get_draw_as_radio (action->item)))
255+ *state_type = G_VARIANT_TYPE_STRING;
256+ else if (action->item != NULL && unity_gtk_menu_item_is_check (action->item))
257+ *state_type = G_VARIANT_TYPE_BOOLEAN;
258+ else
259+ *state_type = NULL;
260+ }
261+
262+ if (state_hint != NULL)
263+ {
264+ if (action->items_by_name != NULL)
265+ {
266+ GVariantBuilder builder;
267+ GHashTableIter iter;
268+ gpointer key;
269+
270+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
271+
272+ g_hash_table_iter_init (&iter, action->items_by_name);
273+ while (g_hash_table_iter_next (&iter, &key, NULL))
274+ g_variant_builder_add (&builder, "s", key);
275+
276+ *state_hint = g_variant_ref_sink (g_variant_builder_end (&builder));
277+ }
278+ else if (action->item != NULL && unity_gtk_menu_item_is_check (action->item))
279+ {
280+ GVariantBuilder builder;
281+
282+ if (unity_gtk_menu_item_get_draw_as_radio (action->item))
283+ {
284+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
285+ g_variant_builder_add (&builder, "s", action->name);
286+ *state_hint = g_variant_ref_sink (g_variant_builder_end (&builder));
287+ }
288+ else
289+ {
290+ g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
291+ g_variant_builder_add (&builder, "b", FALSE);
292+ g_variant_builder_add (&builder, "b", TRUE);
293+ *state_hint = g_variant_ref_sink (g_variant_builder_end (&builder));
294+ }
295+ }
296+ else
297+ *state_hint = NULL;
298+ }
299+
300+ if (state != NULL)
301+ {
302+ if (action->items_by_name != NULL)
303+ {
304+ GHashTableIter iter;
305+ gpointer key;
306+ gpointer value;
307+
308+ *state = NULL;
309+
310+ g_hash_table_iter_init (&iter, action->items_by_name);
311+ while (*state == NULL && g_hash_table_iter_next (&iter, &key, &value))
312+ if (unity_gtk_menu_item_is_active (value))
313+ *state = g_variant_ref_sink (g_variant_new_string (key));
314+ }
315+ else if (action->item != NULL && unity_gtk_menu_item_is_check (action->item))
316+ {
317+ if (unity_gtk_menu_item_get_draw_as_radio (action->item))
318+ {
319+ if (unity_gtk_menu_item_is_active (action->item))
320+ *state = g_variant_ref_sink (g_variant_new_string (action->name));
321+ else
322+ *state = g_variant_ref_sink (g_variant_new_string (""));
323+ }
324+ else
325+ *state = g_variant_ref_sink (g_variant_new_boolean (unity_gtk_menu_item_is_active (action->item)));
326+ }
327+ else
328+ *state = NULL;
329+ }
330+
331+ return TRUE;
332 }
333+ else if (g_strcmp0 (name, action->subname) == 0)
334+ {
335+ if (enabled != NULL)
336+ *enabled = TRUE;
337
338- if (parameter_type != NULL)
339- {
340- if (action->items_by_name != NULL || (action->item != NULL && unity_gtk_menu_item_get_draw_as_radio (action->item)))
341- *parameter_type = G_VARIANT_TYPE_STRING;
342- else
343+ if (parameter_type != NULL)
344 *parameter_type = NULL;
345- }
346
347- if (state_type != NULL)
348- {
349- if (action->items_by_name != NULL || (action->item != NULL && unity_gtk_menu_item_get_draw_as_radio (action->item)))
350- *state_type = G_VARIANT_TYPE_STRING;
351- else if (action->item != NULL && unity_gtk_menu_item_is_check (action->item))
352+ if (state_type != NULL)
353 *state_type = G_VARIANT_TYPE_BOOLEAN;
354- else
355- *state_type = NULL;
356- }
357
358- if (state_hint != NULL)
359- {
360- if (action->items_by_name != NULL)
361+ if (state_hint != NULL)
362 {
363 GVariantBuilder builder;
364- GHashTableIter iter;
365- gpointer key;
366-
367- g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
368-
369- g_hash_table_iter_init (&iter, action->items_by_name);
370- while (g_hash_table_iter_next (&iter, &key, NULL))
371- g_variant_builder_add (&builder, "s", key);
372-
373+
374+ g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
375+ g_variant_builder_add (&builder, "b", FALSE);
376+ g_variant_builder_add (&builder, "b", TRUE);
377 *state_hint = g_variant_ref_sink (g_variant_builder_end (&builder));
378 }
379- else if (action->item != NULL && unity_gtk_menu_item_is_check (action->item))
380- {
381- GVariantBuilder builder;
382-
383- if (unity_gtk_menu_item_get_draw_as_radio (action->item))
384- {
385- g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
386- g_variant_builder_add (&builder, "s", action->name);
387- *state_hint = g_variant_ref_sink (g_variant_builder_end (&builder));
388- }
389- else
390- {
391- g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
392- g_variant_builder_add (&builder, "b", FALSE);
393- g_variant_builder_add (&builder, "b", TRUE);
394- *state_hint = g_variant_ref_sink (g_variant_builder_end (&builder));
395- }
396- }
397- else
398- *state_hint = NULL;
399- }
400-
401- if (state != NULL)
402- {
403- if (action->items_by_name != NULL)
404- {
405- GHashTableIter iter;
406- gpointer key;
407- gpointer value;
408-
409- *state = NULL;
410-
411- g_hash_table_iter_init (&iter, action->items_by_name);
412- while (*state == NULL && g_hash_table_iter_next (&iter, &key, &value))
413- if (unity_gtk_menu_item_is_active (value))
414- *state = g_variant_ref_sink (g_variant_new_string (key));
415- }
416- else if (action->item != NULL && unity_gtk_menu_item_is_check (action->item))
417- {
418- if (unity_gtk_menu_item_get_draw_as_radio (action->item))
419- {
420- if (unity_gtk_menu_item_is_active (action->item))
421- *state = g_variant_ref_sink (g_variant_new_string (action->name));
422- else
423- *state = g_variant_ref_sink (g_variant_new_string (""));
424- }
425- else
426- *state = g_variant_ref_sink (g_variant_new_boolean (unity_gtk_menu_item_is_active (action->item)));
427- }
428- else
429- *state = NULL;
430- }
431-
432- return TRUE;
433+
434+ if (state != NULL)
435+ *state = g_variant_ref_sink (g_variant_new_boolean (TRUE));
436+
437+ return TRUE;
438+ }
439+ else
440+ g_warn_if_reached ();
441 }
442 }
443 else
444@@ -865,6 +936,21 @@
445 g_warn_if_reached ();
446
447 g_action_group_action_added (G_ACTION_GROUP (group), new_action->name);
448+
449+ /* Add a new submenu action so we can detect opening and closing. */
450+ if (item->menu_item != NULL && gtk_menu_item_get_submenu (item->menu_item) != NULL)
451+ {
452+ gchar *subname = unity_gtk_action_group_get_action_name (group, item);
453+ unity_gtk_action_set_subname (new_action, subname);
454+ g_free (subname);
455+
456+ if (group->actions_by_name != NULL)
457+ g_hash_table_insert (group->actions_by_name, new_action->subname, g_object_ref (new_action));
458+ else
459+ g_warn_if_reached ();
460+
461+ g_action_group_action_added (G_ACTION_GROUP (group), new_action->subname);
462+ }
463 }
464 }
465 }
466@@ -908,6 +994,17 @@
467
468 if (g_hash_table_size (action->items_by_name) == 0)
469 {
470+ /* Remove the submenu action used to detect opening and closing. */
471+ if (action->subname != NULL)
472+ {
473+ if (group->actions_by_name != NULL)
474+ g_hash_table_remove (group->actions_by_name, action->subname);
475+ else
476+ g_warn_if_reached ();
477+
478+ g_action_group_action_removed (G_ACTION_GROUP (group), action->subname);
479+ }
480+
481 if (group->actions_by_name != NULL)
482 g_hash_table_remove (group->actions_by_name, action->name);
483 else
484@@ -924,6 +1021,17 @@
485 }
486 else
487 {
488+ /* Remove the submenu action used to detect opening and closing. */
489+ if (action->subname != NULL)
490+ {
491+ if (group->actions_by_name != NULL)
492+ g_hash_table_remove (group->actions_by_name, action->subname);
493+ else
494+ g_warn_if_reached ();
495+
496+ g_action_group_action_removed (G_ACTION_GROUP (group), action->subname);
497+ }
498+
499 if (group->actions_by_name != NULL)
500 g_hash_table_remove (group->actions_by_name, action->name);
501 else
502
503=== modified file 'lib/unity-gtk-action-private.h'
504--- lib/unity-gtk-action-private.h 2013-02-19 11:55:57 +0000
505+++ lib/unity-gtk-action-private.h 2014-05-19 16:34:24 +0000
506@@ -46,25 +46,29 @@
507
508 /*< private >*/
509 gchar *name;
510+ gchar *subname;
511 UnityGtkMenuItem *item;
512 GHashTable *items_by_name;
513 };
514
515-GType unity_gtk_action_get_type (void) G_GNUC_INTERNAL;
516-
517-UnityGtkAction * unity_gtk_action_new (const gchar *name,
518- UnityGtkMenuItem *item) G_GNUC_INTERNAL;
519-
520-UnityGtkAction * unity_gtk_action_new_radio (const gchar *name) G_GNUC_INTERNAL;
521-
522-void unity_gtk_action_set_name (UnityGtkAction *action,
523- const gchar *name) G_GNUC_INTERNAL;
524-
525-void unity_gtk_action_set_item (UnityGtkAction *action,
526- UnityGtkMenuItem *item) G_GNUC_INTERNAL;
527-
528-void unity_gtk_action_print (UnityGtkAction *action,
529- guint indent) G_GNUC_INTERNAL;
530+GType unity_gtk_action_get_type (void) G_GNUC_INTERNAL;
531+
532+UnityGtkAction * unity_gtk_action_new (const gchar *name,
533+ UnityGtkMenuItem *item) G_GNUC_INTERNAL;
534+
535+UnityGtkAction * unity_gtk_action_new_radio (const gchar *name) G_GNUC_INTERNAL;
536+
537+void unity_gtk_action_set_name (UnityGtkAction *action,
538+ const gchar *name) G_GNUC_INTERNAL;
539+
540+void unity_gtk_action_set_subname (UnityGtkAction *action,
541+ const gchar *subname) G_GNUC_INTERNAL;
542+
543+void unity_gtk_action_set_item (UnityGtkAction *action,
544+ UnityGtkMenuItem *item) G_GNUC_INTERNAL;
545+
546+void unity_gtk_action_print (UnityGtkAction *action,
547+ guint indent) G_GNUC_INTERNAL;
548
549 G_END_DECLS
550
551
552=== modified file 'lib/unity-gtk-action.c'
553--- lib/unity-gtk-action.c 2013-02-19 11:55:57 +0000
554+++ lib/unity-gtk-action.c 2014-05-19 16:34:24 +0000
555@@ -41,6 +41,7 @@
556 }
557
558 unity_gtk_action_set_item (action, NULL);
559+ unity_gtk_action_set_subname (action, NULL);
560 unity_gtk_action_set_name (action, NULL);
561
562 G_OBJECT_CLASS (unity_gtk_action_parent_class)->dispose (object);
563@@ -93,6 +94,16 @@
564 }
565
566 void
567+unity_gtk_action_set_subname (UnityGtkAction *action,
568+ const gchar *subname)
569+{
570+ g_return_if_fail (UNITY_GTK_IS_ACTION (action));
571+
572+ g_free (action->subname);
573+ action->subname = g_strdup (subname);
574+}
575+
576+void
577 unity_gtk_action_set_item (UnityGtkAction *action,
578 UnityGtkMenuItem *item)
579 {
580@@ -132,6 +143,9 @@
581 if (action->name != NULL)
582 g_print ("%s \"%s\"\n", space, action->name);
583
584+ if (action->subname != NULL)
585+ g_print ("%s \"%s\"\n", space, action->subname);
586+
587 if (action->item != NULL)
588 g_print ("%s (%s *) %p\n", space, G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (action->item)), action->item);
589
590
591=== modified file 'lib/unity-gtk-menu-item-private.h'
592--- lib/unity-gtk-menu-item-private.h 2014-03-31 00:40:48 +0000
593+++ lib/unity-gtk-menu-item-private.h 2014-05-19 16:34:24 +0000
594@@ -52,7 +52,9 @@
595 guchar child_shell_valid : 1;
596 guint item_index;
597 UnityGtkAction *action;
598- gchar *label;
599+ GtkLabel *first_label;
600+ GtkLabel *second_label;
601+ gchar *label_label;
602 };
603
604 GType unity_gtk_menu_item_get_type (void) G_GNUC_INTERNAL;
605
606=== modified file 'lib/unity-gtk-menu-item.c'
607--- lib/unity-gtk-menu-item.c 2014-03-31 00:40:48 +0000
608+++ lib/unity-gtk-menu-item.c 2014-05-19 16:34:24 +0000
609@@ -368,6 +368,75 @@
610 }
611
612 static void
613+unity_gtk_menu_item_disconnect_labels (UnityGtkMenuItem *item)
614+{
615+ g_return_if_fail (UNITY_GTK_IS_MENU_ITEM (item));
616+
617+ if (item->second_label != NULL)
618+ {
619+ g_signal_handlers_disconnect_by_data (item->second_label, item);
620+ item->second_label = NULL;
621+ }
622+
623+ if (item->first_label != NULL)
624+ {
625+ g_signal_handlers_disconnect_by_data (item->first_label, item);
626+ item->first_label = NULL;
627+ }
628+}
629+
630+static gboolean
631+unity_gtk_menu_item_connect_labels (UnityGtkMenuItem *item)
632+{
633+ GtkLabel *first_label = NULL;
634+ GtkLabel *second_label = NULL;
635+
636+ g_return_val_if_fail (UNITY_GTK_IS_MENU_ITEM (item), FALSE);
637+
638+ if (item->menu_item != NULL)
639+ {
640+ /* ensure label is available */
641+ gtk_menu_item_get_label (item->menu_item);
642+
643+ first_label = gtk_menu_item_get_nth_label (item->menu_item, 0);
644+ second_label = gtk_menu_item_get_nth_label (item->menu_item, 1);
645+ }
646+
647+ if (first_label != item->first_label || second_label != item->second_label)
648+ {
649+ unity_gtk_menu_item_disconnect_labels (item);
650+
651+ item->first_label = first_label;
652+ item->second_label = second_label;
653+
654+ if (item->first_label != NULL)
655+ g_signal_connect (item->first_label, "notify", G_CALLBACK (unity_gtk_menu_item_handle_label_notify), item);
656+ if (item->second_label != NULL)
657+ g_signal_connect (item->second_label, "notify", G_CALLBACK (unity_gtk_menu_item_handle_label_notify), item);
658+
659+ return TRUE;
660+ }
661+
662+ return FALSE;
663+}
664+
665+static void
666+unity_gtk_menu_item_handle_add_or_remove (GtkContainer *container,
667+ GtkWidget *widget,
668+ gpointer user_data)
669+{
670+ UnityGtkMenuItem *item;
671+
672+ g_return_if_fail (UNITY_GTK_IS_MENU_ITEM (user_data));
673+
674+ item = UNITY_GTK_MENU_ITEM (user_data);
675+
676+ /* just ignore the case when parent_shell is NULL */
677+ if (item->parent_shell != NULL && unity_gtk_menu_item_connect_labels (item))
678+ unity_gtk_menu_shell_handle_item_notify (item->parent_shell, item, "label");
679+}
680+
681+static void
682 unity_gtk_menu_item_handle_accel_closures_changed (GtkWidget *widget,
683 gpointer user_data)
684 {
685@@ -388,23 +457,16 @@
686 unity_gtk_menu_item_set_menu_item (UnityGtkMenuItem *item,
687 GtkMenuItem *menu_item)
688 {
689- GtkLabel *label;
690-
691 g_return_if_fail (UNITY_GTK_IS_MENU_ITEM (item));
692
693 if (menu_item != item->menu_item)
694 {
695 UnityGtkMenuShell *child_shell = item->child_shell;
696
697+ unity_gtk_menu_item_disconnect_labels (item);
698+
699 if (item->menu_item != NULL)
700- {
701- label = gtk_menu_item_get_nth_label (item->menu_item, 0);
702-
703- if (label != NULL)
704- g_signal_handlers_disconnect_by_data (label, item);
705-
706- g_signal_handlers_disconnect_by_data (item->menu_item, item);
707- }
708+ g_signal_handlers_disconnect_by_data (item->menu_item, item);
709
710 if (child_shell != NULL)
711 {
712@@ -419,20 +481,20 @@
713 if (menu_item != NULL)
714 {
715 g_signal_connect (menu_item, "notify", G_CALLBACK (unity_gtk_menu_item_handle_item_notify), item);
716-
717- /* ensure label is available */
718- gtk_menu_item_get_label (menu_item);
719- label = gtk_menu_item_get_nth_label (menu_item, 0);
720-
721- if (label != NULL)
722- g_signal_connect (label, "notify", G_CALLBACK (unity_gtk_menu_item_handle_label_notify), item);
723-
724+ g_signal_connect (menu_item, "add", G_CALLBACK (unity_gtk_menu_item_handle_add_or_remove), item);
725+ g_signal_connect (menu_item, "remove", G_CALLBACK (unity_gtk_menu_item_handle_add_or_remove), item);
726 g_signal_connect (menu_item, "accel-closures-changed", G_CALLBACK (unity_gtk_menu_item_handle_accel_closures_changed), item);
727
728- /* LP: #1208019 */
729+ /*
730+ * LP: #1208019: We do this because Eclipse sets menu item
731+ * accelerators using private API, and there's no way for us to
732+ * detect when they change.
733+ */
734 if (gtk_menu_item_get_submenu (menu_item) != NULL)
735 g_signal_emit_by_name (gtk_menu_item_get_submenu (menu_item), "show");
736 }
737+
738+ unity_gtk_menu_item_connect_labels (item);
739 }
740 }
741
742@@ -470,8 +532,8 @@
743
744 item = UNITY_GTK_MENU_ITEM (object);
745
746- g_free (item->label);
747- item->label = NULL;
748+ g_free (item->label_label);
749+ item->label_label = NULL;
750
751 G_OBJECT_CLASS (unity_gtk_menu_item_parent_class)->finalize (object);
752 }
753@@ -661,7 +723,7 @@
754 g_return_val_if_fail (UNITY_GTK_IS_MENU_ITEM (item), NULL);
755 g_return_val_if_fail (item->menu_item != NULL, NULL);
756
757- if (item->label == NULL)
758+ if (item->label_label == NULL)
759 {
760 const gchar *label_label = gtk_menu_item_get_label (item->menu_item);
761
762@@ -691,16 +753,16 @@
763 if (gtk_label_get_use_underline (label))
764 {
765 if (item->parent_shell == NULL || item->parent_shell->has_mnemonics)
766- item->label = g_strdup (label_label);
767+ item->label_label = g_strdup (label_label);
768 else
769- item->label = g_strdup_no_mnemonics (label_label);
770+ item->label_label = g_strdup_no_mnemonics (label_label);
771 }
772 else
773- item->label = g_strdup_escape_underscores (label_label);
774+ item->label_label = g_strdup_escape_underscores (label_label);
775 }
776 }
777
778- return item->label;
779+ return item->label_label;
780 }
781
782 GIcon *
783
784=== modified file 'lib/unity-gtk-menu-section.c'
785--- lib/unity-gtk-menu-section.c 2014-03-31 00:40:48 +0000
786+++ lib/unity-gtk-menu-section.c 2014-05-19 16:34:24 +0000
787@@ -27,6 +27,10 @@
788 #define G_MENU_ATTRIBUTE_ACCEL_TEXT "x-canonical-accel"
789 #endif
790
791+#ifndef G_MENU_ATTRIBUTE_SUBMENU_ACTION
792+#define G_MENU_ATTRIBUTE_SUBMENU_ACTION "submenu-action"
793+#endif
794+
795 G_DEFINE_TYPE (UnityGtkMenuSection,
796 unity_gtk_menu_section,
797 G_TYPE_MENU_MODEL);
798@@ -136,32 +140,43 @@
799 g_object_unref (icon);
800 }
801
802- if (action != NULL && action->name != NULL)
803+ if (action != NULL)
804 {
805- gchar *name = g_strdup_printf ("unity.%s", action->name);
806- GVariant *variant = g_variant_ref_sink (g_variant_new_string (name));
807-
808- g_hash_table_insert (*attributes, G_MENU_ATTRIBUTE_ACTION, variant);
809-
810- if (action->items_by_name != NULL)
811- {
812- GHashTableIter iter;
813- gpointer key;
814- gpointer value;
815- const gchar *target = NULL;
816-
817- g_hash_table_iter_init (&iter, action->items_by_name);
818- while (target == NULL && g_hash_table_iter_next (&iter, &key, &value))
819- if (value == item)
820- target = key;
821-
822- if (target != NULL)
823- g_hash_table_insert (*attributes, G_MENU_ATTRIBUTE_TARGET, g_variant_ref_sink (g_variant_new_string (target)));
824- }
825- else if (unity_gtk_menu_item_get_draw_as_radio (item))
826- g_hash_table_insert (*attributes, G_MENU_ATTRIBUTE_TARGET, g_variant_ref_sink (g_variant_new_string (action->name)));
827-
828- g_free (name);
829+ if (action->name != NULL)
830+ {
831+ gchar *name = g_strdup_printf ("unity.%s", action->name);
832+ GVariant *variant = g_variant_ref_sink (g_variant_new_string (name));
833+
834+ g_hash_table_insert (*attributes, G_MENU_ATTRIBUTE_ACTION, variant);
835+
836+ if (action->items_by_name != NULL)
837+ {
838+ GHashTableIter iter;
839+ gpointer key;
840+ gpointer value;
841+ const gchar *target = NULL;
842+
843+ g_hash_table_iter_init (&iter, action->items_by_name);
844+ while (target == NULL && g_hash_table_iter_next (&iter, &key, &value))
845+ if (value == item)
846+ target = key;
847+
848+ if (target != NULL)
849+ g_hash_table_insert (*attributes, G_MENU_ATTRIBUTE_TARGET, g_variant_ref_sink (g_variant_new_string (target)));
850+ }
851+ else if (unity_gtk_menu_item_get_draw_as_radio (item))
852+ g_hash_table_insert (*attributes, G_MENU_ATTRIBUTE_TARGET, g_variant_ref_sink (g_variant_new_string (action->name)));
853+
854+ g_free (name);
855+ }
856+
857+ if (action->subname != NULL)
858+ {
859+ gchar *subname = g_strdup_printf ("unity.%s", action->subname);
860+ GVariant *variant = g_variant_ref_sink (g_variant_new_string (subname));
861+ g_hash_table_insert (*attributes, G_MENU_ATTRIBUTE_SUBMENU_ACTION, variant);
862+ g_free (subname);
863+ }
864 }
865
866 if (item->menu_item != NULL)
867
868=== modified file 'lib/unity-gtk-menu-shell.c'
869--- lib/unity-gtk-menu-shell.c 2014-03-27 19:52:20 +0000
870+++ lib/unity-gtk-menu-shell.c 2014-05-19 16:34:24 +0000
871@@ -449,8 +449,8 @@
872 g_return_if_fail (UNITY_GTK_IS_MENU_ITEM (item));
873 g_warn_if_fail (item->parent_shell == shell);
874
875- g_free (item->label);
876- item->label = NULL;
877+ g_free (item->label_label);
878+ item->label_label = NULL;
879
880 unity_gtk_menu_shell_update_item (shell, item);
881 }
882@@ -582,6 +582,13 @@
883 g_return_if_fail (UNITY_GTK_IS_MENU_ITEM (item));
884 g_warn_if_fail (item->parent_shell == shell);
885
886+ if (shell->action_group != NULL)
887+ {
888+ /* If a submenu was added or removed, we need to update the submenu action. */
889+ unity_gtk_action_group_disconnect_item (shell->action_group, item);
890+ unity_gtk_action_group_connect_item (shell->action_group, item);
891+ }
892+
893 if (item->child_shell_valid)
894 {
895 GtkMenuShell *old_submenu = item->child_shell != NULL ? item->child_shell->menu_shell : NULL;

Subscribers

People subscribed via source and target branches