Merge lp:~mterry/appmenu-gtk/misc-fixes into lp:appmenu-gtk/0.4

Proposed by Michael Terry
Status: Merged
Merged at revision: 108
Proposed branch: lp:~mterry/appmenu-gtk/misc-fixes
Merge into: lp:appmenu-gtk/0.4
Diff against target: 338 lines (+98/-117)
1 file modified
src/bridge.c (+98/-117)
To merge this branch: bzr merge lp:~mterry/appmenu-gtk/misc-fixes
Reviewer Review Type Date Requested Status
Canonical Desktop Experience Team Pending
Review via email: mp+47114@code.launchpad.net

Description of the change

This branch does four things, all observed while working with the monster that is empathy.

1) Empathy changes the first label ("Context", "Contact", or "Group") of it's Edit menu by directly changing the label inside the menu item. So we need to watch for such direct edits as well. (this is the addition of label_notify_cb)

2) Empathy directly hides/shows the first label and first separator in its Edit menu on startup directly. It does not modify the backing GtkAction. So when we startup, we should take such possibilities in mind and prefer the visible/sensitive status of the widget directly over the action -- it is always likely to be more correct (though we should and do continue watching action status).

3) Empathy modifies the first label and separator of its Edit menu upon menu activation (a dynamic menu). We need to listen for about-to-show signals from dbusmenu and activate the menu for empathy, so it can modify the menu. There's a race here, because dbusmenu doesn't yet actually block on our being ready, but it works in practice, and is better than nothing right now.

4) Vastly simplify separator logic. There was existing code to monitor the 'smart' mode and tell when it should be shown. But GtkUIManager handles that for us by setting widget visibility state of the item. So instead, we should treat separators a bit more like normal items. So I attach the same notify callback to separators that were for other widgets before (letting me drop the separate child_notify_cb). This fixes issues in Empathy with showing the first separator in the Edit menu as well as the separators in the Help menu.

We still don't fully get the first label of the Edit menu right -- Empathy is actually setting a submenu. I'm working on another branch that watches the "submenu" property and tries to do intelligent things. But this work was splitable, so here it is.

To post a comment you must log in.
Revision history for this message
Michael Terry (mterry) wrote :

Oh, whoops, and I forgot, this includes the approved branch https://code.launchpad.net/~mterry/appmenu-gtk/fix-sensitive-actions/+merge/47056

Revision history for this message
Ted Gould (ted) wrote :

Merged fix-sensitive-actions to trunk. Patch should regenerate shortly.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/bridge.c'
2--- src/bridge.c 2011-01-14 17:25:07 +0000
3+++ src/bridge.c 2011-01-21 21:35:56 +0000
4@@ -88,15 +88,8 @@
5 gint count;
6 gboolean previous;
7 DbusmenuMenuitem *stack[30];
8- gboolean mode[30];
9 } RecurseContext;
10
11-enum {
12- SEPARATOR_MODE_SMART,
13- SEPARATOR_MODE_VISIBLE,
14- SEPARATOR_MODE_HIDDEN
15-};
16-
17 G_DEFINE_DYNAMIC_TYPE(AppMenuBridge, app_menu_bridge, UBUNTU_TYPE_MENU_PROXY)
18
19 static GHashTable *rebuild_ids = NULL;
20@@ -480,17 +473,6 @@
21 return label;
22 }
23
24-static const gchar *
25-get_menu_label_text (GtkWidget *menuitem)
26-{
27- GtkWidget *label = find_menu_label (menuitem);
28-
29- if (label)
30- return gtk_label_get_text (GTK_LABEL (label));
31-
32- return NULL;
33-}
34-
35 static void
36 item_activated (DbusmenuMenuitem *item, guint timestamp, gpointer user_data)
37 {
38@@ -508,6 +490,26 @@
39 }
40
41 static gboolean
42+item_about_to_show (DbusmenuMenuitem *item, gpointer user_data)
43+{
44+ GtkWidget *child;
45+
46+ if (user_data != NULL)
47+ {
48+ child = (GtkWidget *)user_data;
49+
50+ if (GTK_IS_MENU_ITEM (child))
51+ {
52+ // Only called for items with submens. So we activate it here in
53+ // case the program dynamically creates menus (like empathy does)
54+ gtk_menu_item_activate (GTK_MENU_ITEM (child));
55+ }
56+ }
57+
58+ return TRUE;
59+}
60+
61+static gboolean
62 should_show_image (GtkImage *image)
63 {
64 GtkWidget *item;
65@@ -627,6 +629,41 @@
66 {
67 update_icon_name (child, widget);
68 }
69+ else if (pspec->name == g_intern_static_string ("parent"))
70+ {
71+ /*
72+ * We probably should have added a 'remove' method to the
73+ * UbuntuMenuProxy early on, but it's late in the cycle now.
74+ */
75+ if (gtk_widget_get_parent (widget) == NULL)
76+ {
77+ g_signal_handlers_disconnect_by_func (widget,
78+ G_CALLBACK (widget_notify_cb),
79+ child);
80+
81+ DbusmenuMenuitem *parent = g_object_get_data (G_OBJECT (child), "dbusmenu-parent");
82+
83+ if (DBUSMENU_IS_MENUITEM (parent) && DBUSMENU_IS_MENUITEM (child))
84+ {
85+ dbusmenu_menuitem_child_delete (parent, child);
86+ }
87+ }
88+ }
89+}
90+
91+static void
92+label_notify_cb (GtkWidget *widget,
93+ GParamSpec *pspec,
94+ gpointer data)
95+{
96+ DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
97+
98+ if (pspec->name == g_intern_static_string ("label"))
99+ {
100+ dbusmenu_menuitem_property_set (child,
101+ DBUSMENU_MENUITEM_PROP_LABEL,
102+ gtk_label_get_text (GTK_LABEL (widget)));
103+ }
104 }
105
106 static void
107@@ -682,6 +719,12 @@
108 {
109 dbusmenu_menuitem_property_set_bool (mi,
110 DBUSMENU_MENUITEM_PROP_ENABLED,
111+ gtk_action_is_sensitive (action));
112+ }
113+ else if (pspec->name == g_intern_static_string ("visible"))
114+ {
115+ dbusmenu_menuitem_property_set_bool (mi,
116+ DBUSMENU_MENUITEM_PROP_VISIBLE,
117 gtk_action_is_visible (action));
118 }
119 else if (pspec->name == g_intern_static_string ("active"))
120@@ -698,56 +741,26 @@
121 }
122 }
123
124-/*
125- * We probably should have added a 'remove' method to the UbuntuMenuProxy early on,
126- * but it's late in the cycle now.
127- */
128-static void
129-child_notify_cb (GtkWidget *widget,
130- GParamSpec *pspec,
131- DbusmenuMenuitem *mi)
132-{
133- if (pspec->name == g_intern_static_string ("parent"))
134- {
135- if (gtk_widget_get_parent (widget) == NULL)
136- {
137- g_signal_handlers_disconnect_by_func (widget,
138- G_CALLBACK (child_notify_cb),
139- mi);
140-
141- DbusmenuMenuitem *parent = g_object_get_data (G_OBJECT (mi), "dbusmenu-parent");
142-
143- if (DBUSMENU_IS_MENUITEM (parent) && DBUSMENU_IS_MENUITEM (mi))
144- {
145- dbusmenu_menuitem_child_delete (parent, mi);
146- }
147- }
148- }
149-}
150-
151 static DbusmenuMenuitem *
152-construct_dbusmenu_for_widget (GtkWidget *widget, gboolean previous_separator)
153+construct_dbusmenu_for_widget (GtkWidget *widget)
154 {
155 DbusmenuMenuitem *mi = dbusmenu_menuitem_new ();
156
157 if (GTK_IS_MENU_ITEM (widget))
158 {
159+ gboolean visible = FALSE;
160+ gboolean sensitive = FALSE;
161 if (GTK_IS_SEPARATOR_MENU_ITEM (widget))
162 {
163 dbusmenu_menuitem_property_set (mi,
164 "type",
165 "separator");
166
167- gint mode = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "gtk-separator-mode"));
168-
169- dbusmenu_menuitem_property_set_bool (mi,
170- DBUSMENU_MENUITEM_PROP_VISIBLE,
171- mode == SEPARATOR_MODE_SMART && !previous_separator);
172+ visible = gtk_widget_get_visible (widget);
173+ sensitive = gtk_widget_get_sensitive (widget);
174 }
175 else
176 {
177- gboolean visible = FALSE;
178- gboolean sensitive = FALSE;
179 gboolean label_set = FALSE;
180
181 g_signal_connect (widget,
182@@ -799,23 +812,22 @@
183 }
184 }
185
186+ GtkWidget *label = find_menu_label (widget);
187+
188 dbusmenu_menuitem_property_set (mi,
189 "label",
190- get_menu_label_text (widget));
191+ label ? gtk_label_get_text (GTK_LABEL (label)) : NULL);
192
193- if (!g_object_get_data (G_OBJECT (widget), "gtk-empty-menu-item") && !GTK_IS_TEAROFF_MENU_ITEM (widget))
194+ if (label)
195 {
196- visible = gtk_widget_get_visible (widget);
197- sensitive = gtk_widget_get_sensitive (widget);
198+ // Sometimes, an app will directly find and modify the label
199+ // (like empathy), so watch the label especially for that.
200+ g_signal_connect (G_OBJECT (label),
201+ "notify",
202+ G_CALLBACK (label_notify_cb),
203+ mi);
204 }
205
206- dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget));
207-
208- g_signal_connect (G_OBJECT (widget),
209- "notify",
210- G_CALLBACK (widget_notify_cb),
211- mi);
212-
213 if (GTK_IS_ACTIVATABLE (widget))
214 {
215 GtkActivatable *activatable = GTK_ACTIVATABLE (widget);
216@@ -837,23 +849,36 @@
217 }
218 }
219
220- dbusmenu_menuitem_property_set_bool (mi,
221- DBUSMENU_MENUITEM_PROP_VISIBLE,
222- visible);
223+ if (!g_object_get_data (G_OBJECT (widget), "gtk-empty-menu-item") && !GTK_IS_TEAROFF_MENU_ITEM (widget))
224+ {
225+ visible = gtk_widget_get_visible (widget);
226+ sensitive = gtk_widget_get_sensitive (widget);
227+ }
228
229- dbusmenu_menuitem_property_set_bool (mi,
230- DBUSMENU_MENUITEM_PROP_ENABLED,
231- sensitive);
232+ dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget));
233
234 g_signal_connect (G_OBJECT (mi),
235 DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
236 G_CALLBACK (item_activated),
237 widget);
238+
239+ g_signal_connect (G_OBJECT (mi),
240+ DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW,
241+ G_CALLBACK (item_about_to_show),
242+ widget);
243 }
244
245+ dbusmenu_menuitem_property_set_bool (mi,
246+ DBUSMENU_MENUITEM_PROP_VISIBLE,
247+ visible);
248+
249+ dbusmenu_menuitem_property_set_bool (mi,
250+ DBUSMENU_MENUITEM_PROP_ENABLED,
251+ sensitive);
252+
253 g_signal_connect (widget,
254 "notify",
255- G_CALLBACK (child_notify_cb),
256+ G_CALLBACK (widget_notify_cb),
257 mi);
258 }
259
260@@ -867,7 +892,6 @@
261 if (GTK_IS_CONTAINER (widget))
262 {
263 gboolean increment = GTK_IS_MENU_BAR (widget) || GTK_IS_MENU_ITEM (widget);
264- gboolean previous_separator = FALSE;
265
266 if (increment)
267 recurse->count++;
268@@ -898,34 +922,6 @@
269
270 if (recurse->count > -1 && increment)
271 {
272- /* If this is a separator, find out if we've already displayed a visible separator during
273- * this run. GtkUIManager internally defines the following separator modes:
274- *
275- * SEPARATOR_MODE_SMART
276- * SEPARATOR_MODE_VISIBLE
277- * SEPARATOR_MODE_HIDDEN
278- *
279- * construct_dbusmenu_for_widget() will mark a smart separator as visible in a run of
280- * separators unless it is following another smart separator anywhere in that run.
281- */
282- if (GTK_IS_SEPARATOR_MENU_ITEM (widget))
283- {
284- if (recurse->stack[recurse->count] != NULL)
285- {
286- const gchar *type = dbusmenu_menuitem_property_get (recurse->stack[recurse->count],
287- DBUSMENU_MENUITEM_PROP_TYPE);
288-
289- if (g_strcmp0 (type, "separator") == 0)
290- {
291- /* Get the previous separator mode. */
292- gint mode = recurse->mode[recurse->count];
293-
294- if (mode == SEPARATOR_MODE_SMART)
295- previous_separator = TRUE;
296- }
297- }
298- }
299-
300 DbusmenuMenuitem *dmi = g_hash_table_lookup (recurse->context->lookup, widget);
301 if (dmi != NULL)
302 {
303@@ -936,25 +932,10 @@
304 }
305 else
306 {
307- recurse->stack[recurse->count] = construct_dbusmenu_for_widget (widget, previous_separator);
308+ recurse->stack[recurse->count] = construct_dbusmenu_for_widget (widget);
309 g_hash_table_insert (recurse->context->lookup, widget, recurse->stack[recurse->count]);
310 }
311
312- if (GTK_IS_SEPARATOR_MENU_ITEM (widget))
313- {
314- /* If the previous separator was mode 1, let's pretend that this separator is also mode 1.
315- * That means for the remainder of this run of separators, all will be marked as mode 1.
316- */
317- if (previous_separator)
318- {
319- recurse->mode[recurse->count] = SEPARATOR_MODE_SMART;
320- }
321- else
322- {
323- recurse->mode[recurse->count] = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "gtk-separator-mode"));
324- }
325- }
326-
327 if (!gtk_widget_get_visible (widget))
328 {
329 g_signal_connect (G_OBJECT (widget),
330@@ -1335,7 +1316,7 @@
331
332 if (mi != NULL)
333 {
334- DbusmenuMenuitem *child_dmi = construct_dbusmenu_for_widget (child, FALSE);
335+ DbusmenuMenuitem *child_dmi = construct_dbusmenu_for_widget (child);
336
337 g_object_set_data (G_OBJECT (child_dmi), "dbusmenu-parent", mi);
338 dbusmenu_menuitem_child_add_position (mi,

Subscribers

People subscribed via source and target branches