Merge lp:~attente/unity-gtk-module/gtk-enable-mnemonics into lp:unity-gtk-module/14.04

Proposed by William Hua
Status: Merged
Approved by: Sebastien Bacher
Approved revision: 322
Merged at revision: 315
Proposed branch: lp:~attente/unity-gtk-module/gtk-enable-mnemonics
Merge into: lp:unity-gtk-module/14.04
Diff against target: 403 lines (+190/-48)
5 files modified
lib/unity-gtk-menu-item-private.h (+1/-0)
lib/unity-gtk-menu-item.c (+92/-19)
lib/unity-gtk-menu-shell-private.h (+20/-18)
lib/unity-gtk-menu-shell.c (+76/-11)
lib/unity-gtk-menu-shell.h (+1/-0)
To merge this branch: bzr merge lp:~attente/unity-gtk-module/gtk-enable-mnemonics
Reviewer Review Type Date Requested Status
Sebastien Bacher Approve
PS Jenkins bot (community) continuous-integration Approve
Allison Karlitskaya (community) Needs Fixing
Review via email: mp+207752@code.launchpad.net

Commit message

Filter out mnemonics when the gtk-enable-mnemonics setting is cleared. Workaround for LP: #1282782.

Description of the change

Filter out mnemonics when the gtk-enable-mnemonics setting is cleared. Workaround for LP: #1282782.

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

trying to dynamically handle the settings changing at runtime is maybe a bit insane.... but assuming that indeed you do want to do this:

unity_gtk_menu_shell_handle_item_notify() only uses the pspec to get the name -- why not just modify this function to take the name directly, removing the need to lookup the pspec...

keeping a gtksettings per menuitem is definitely overkill -- it's exceptionally unlikely that we will ever see more than one gtksettings per program. just use the global one. cache it in a static if you really don't trust that it will never change...

since you will just use the global gtksettings, no need to remove/readd the signal handler every time. also: don't bother with handler ids: they don't really make much of an improvement in performance. just disconnect by funcs/data.

finally: you shouldn't try to do this for every single menu item: only for toplevel ones in menubars.

one unrelated note: your underscore removal algorithm's attempt to be correct on non-ascii utf8 strings is not really necessary. all non-ascii utf8 sequences are composed entirely of non-ascii characters (ie: every byte is > 0x80). it is therefore impossible for '_' to appear in the middle of the sequence. just do the naive thing here and it will be correct.

review: Needs Fixing
Revision history for this message
Allison Karlitskaya (desrt) wrote :

about the strdup: the strlen() + 1 on sized new is not necessary with gstring -- it adds the nul internally. maybe skip GString here entirely since you know that the result string will definitely be smaller than the input.

also: with respect to my previous comments, strchr() is your friend.

316. By William Hua

Pass property name directly.

317. By William Hua

Simplify mnemonic removal.

318. By William Hua

Only honour gtk-enable-mnemonics on top-level shells.

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

I added the signal handler connection/disconnection in the unity_gtk_menu_shell_set_menu_shell () function because sometimes the GtkMenuShell can be set to NULL, and it makes sense to no longer watch once that happens. If you're worried about it being connected/disconnected more than once, in practice that function is never called with a non-NULL GtkMenuShell except at initialization.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Allison Karlitskaya (desrt) wrote :

This is better, but still not exactly what I had in mind. I wouldn't block on further review bickering at this point, though.

What I was thinking of (and did a relative poor job of explaining) is one global default GtkSettings watch (using gtk_settings_get_default) for the entire thing. When it fires, then you can iterate the toplevel items and make the tweak.

319. By William Hua

Use only one signal handler for notify::gtk-enable-mnemonics.

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

Reset the label in the label handler.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Allison Karlitskaya (desrt) wrote :

Keeping the global list is really strange -- particularly considering that in practice there will only ever be exactly one menubar. It would have been better to just hook directly up to each (of the one and only) toplevel shell instead of bothering with all of this register stuff...

This is totally fine as-is, though...

321. By William Hua

Don't use a global linked list.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Allison Karlitskaya (desrt) wrote :

Just one more nag: this check will never fail:

+ if (gtk_enable_mnemonics_name == NULL)
282 + gtk_enable_mnemonics_name = g_intern_static_string ("gtk-enable-mnemonics");
283 +
284 + if (g_param_spec_get_name (pspec) == gtk_enable_mnemonics_name)
285 + {

because you already have a detailed signal connection.

322. By William Hua

Don't check pspec name in detailed signal handler.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sebastien Bacher (seb128) wrote :

Seems like that's ready to land, thanks guys for the review/iterations!

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-menu-item-private.h'
2--- lib/unity-gtk-menu-item-private.h 2013-11-28 18:29:27 +0000
3+++ lib/unity-gtk-menu-item-private.h 2014-03-05 17:18:00 +0000
4@@ -53,6 +53,7 @@
5 guchar child_shell_valid : 1;
6 guint item_index;
7 UnityGtkAction *action;
8+ gchar *label;
9 };
10
11 GType unity_gtk_menu_item_get_type (void) G_GNUC_INTERNAL;
12
13=== modified file 'lib/unity-gtk-menu-item.c'
14--- lib/unity-gtk-menu-item.c 2013-11-28 18:29:27 +0000
15+++ lib/unity-gtk-menu-item.c 2014-03-05 17:18:00 +0000
16@@ -19,6 +19,7 @@
17
18 #include "unity-gtk-menu-item-private.h"
19 #include "unity-gtk-action-group-private.h"
20+#include <string.h>
21
22 G_DEFINE_TYPE (UnityGtkMenuItem,
23 unity_gtk_menu_item,
24@@ -307,7 +308,7 @@
25 g_return_if_fail (parent_shell != NULL);
26 g_warn_if_fail (object == menu_item);
27
28- unity_gtk_menu_shell_handle_item_notify (parent_shell, item, pspec);
29+ unity_gtk_menu_shell_handle_item_notify (parent_shell, item, g_param_spec_get_name (pspec));
30 }
31
32 static void
33@@ -368,11 +369,27 @@
34 }
35
36 static void
37+unity_gtk_menu_item_finalize (GObject *object)
38+{
39+ UnityGtkMenuItem *item;
40+
41+ g_return_if_fail (UNITY_GTK_IS_MENU_ITEM (object));
42+
43+ item = UNITY_GTK_MENU_ITEM (object);
44+
45+ g_free (item->label);
46+ item->label = NULL;
47+
48+ G_OBJECT_CLASS (unity_gtk_menu_item_parent_class)->finalize (object);
49+}
50+
51+static void
52 unity_gtk_menu_item_class_init (UnityGtkMenuItemClass *klass)
53 {
54 GObjectClass *object_class = G_OBJECT_CLASS (klass);
55
56 object_class->dispose = unity_gtk_menu_item_dispose;
57+ object_class->finalize = unity_gtk_menu_item_finalize;
58 }
59
60 static void
61@@ -416,7 +433,7 @@
62 GtkWidget *submenu = gtk_menu_item_get_submenu (menu_item);
63
64 if (submenu != NULL)
65- item->child_shell = unity_gtk_menu_shell_new (GTK_MENU_SHELL (submenu));
66+ item->child_shell = unity_gtk_menu_shell_new_internal (GTK_MENU_SHELL (submenu));
67 }
68
69 item->child_shell_valid = TRUE;
70@@ -461,36 +478,92 @@
71 }
72 }
73
74+static gchar *
75+g_strdup_no_mnemonics (const gchar *str)
76+{
77+ if (str != NULL)
78+ {
79+ gchar *string;
80+ gchar *out;
81+ const gchar *in;
82+ gboolean underscore;
83+
84+ string = g_malloc (strlen (str) + 1);
85+ out = string;
86+ underscore = FALSE;
87+
88+ for (in = str; *in != '\0'; in++)
89+ {
90+ if (*in != '_')
91+ {
92+ underscore = FALSE;
93+ *out++ = *in;
94+ }
95+ else
96+ {
97+ if (!underscore)
98+ underscore = TRUE;
99+ else
100+ {
101+ /* double underscores are not accelerator markers */
102+ underscore = FALSE;
103+ *out++ = '_';
104+ *out++ = '_';
105+ }
106+ }
107+ }
108+
109+ /* trailing underscores are not accelerator markers */
110+ if (underscore)
111+ *out++ = '_';
112+
113+ *out++ = '\0';
114+
115+ return string;
116+ }
117+
118+ return NULL;
119+}
120+
121 const gchar *
122 unity_gtk_menu_item_get_label (UnityGtkMenuItem *item)
123 {
124- const gchar *label;
125-
126 g_return_val_if_fail (UNITY_GTK_IS_MENU_ITEM (item), NULL);
127 g_return_val_if_fail (item->menu_item != NULL, NULL);
128
129- label = gtk_menu_item_get_label (item->menu_item);
130-
131- if (label != NULL && label[0] != '\0')
132+ if (item->label == NULL)
133 {
134- if (GTK_IS_IMAGE_MENU_ITEM (item->menu_item))
135+ const gchar *label = gtk_menu_item_get_label (item->menu_item);
136+
137+ if (label != NULL && label[0] != '\0')
138 {
139- GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (item->menu_item);
140-
141- if (gtk_image_menu_item_get_use_stock (image_menu_item))
142+ if (GTK_IS_IMAGE_MENU_ITEM (item->menu_item))
143 {
144- GtkStockItem stock_item;
145-
146- if (gtk_stock_lookup (label, &stock_item))
147- label = stock_item.label;
148+ GtkImageMenuItem *image_menu_item = GTK_IMAGE_MENU_ITEM (item->menu_item);
149+
150+ if (gtk_image_menu_item_get_use_stock (image_menu_item))
151+ {
152+ GtkStockItem stock_item;
153+
154+ if (gtk_stock_lookup (label, &stock_item))
155+ label = stock_item.label;
156+ }
157 }
158 }
159+
160+ if (label == NULL || label[0] == '\0')
161+ label = gtk_menu_item_get_nth_label (item->menu_item, 0);
162+
163+ if (label != NULL && label[0] != '\0')
164+ {
165+ if (item->parent_shell == NULL || item->parent_shell->has_mnemonics)
166+ item->label = g_strdup (label);
167+ else
168+ item->label = g_strdup_no_mnemonics (label);
169+ }
170 }
171
172- if (label == NULL || label[0] == '\0')
173- label = gtk_menu_item_get_nth_label (item->menu_item, 0);
174-
175- return label != NULL && label[0] != '\0' ? label : NULL;
176+ return item->label;
177 }
178
179 GIcon *
180
181=== modified file 'lib/unity-gtk-menu-shell-private.h'
182--- lib/unity-gtk-menu-shell-private.h 2013-11-28 18:29:27 +0000
183+++ lib/unity-gtk-menu-shell-private.h 2014-03-05 17:18:00 +0000
184@@ -26,24 +26,26 @@
185
186 G_BEGIN_DECLS
187
188-UnityGtkMenuItem * unity_gtk_menu_shell_get_item (UnityGtkMenuShell *shell,
189- guint index) G_GNUC_INTERNAL;
190-
191-GSequence * unity_gtk_menu_shell_get_visible_indices (UnityGtkMenuShell *shell) G_GNUC_INTERNAL;
192-
193-GSequence * unity_gtk_menu_shell_get_separator_indices (UnityGtkMenuShell *shell) G_GNUC_INTERNAL;
194-
195-void unity_gtk_menu_shell_handle_item_notify (UnityGtkMenuShell *shell,
196- UnityGtkMenuItem *item,
197- GParamSpec *pspec) G_GNUC_INTERNAL;
198-
199-void unity_gtk_menu_shell_activate_item (UnityGtkMenuShell *shell,
200- UnityGtkMenuItem *item) G_GNUC_INTERNAL;
201-
202-void unity_gtk_menu_shell_print (UnityGtkMenuShell *shell,
203- guint indent) G_GNUC_INTERNAL;
204-
205-gboolean unity_gtk_menu_shell_is_debug (void) G_GNUC_INTERNAL;
206+UnityGtkMenuShell * unity_gtk_menu_shell_new_internal (GtkMenuShell *menu_shell) G_GNUC_INTERNAL;
207+
208+UnityGtkMenuItem * unity_gtk_menu_shell_get_item (UnityGtkMenuShell *shell,
209+ guint index) G_GNUC_INTERNAL;
210+
211+GSequence * unity_gtk_menu_shell_get_visible_indices (UnityGtkMenuShell *shell) G_GNUC_INTERNAL;
212+
213+GSequence * unity_gtk_menu_shell_get_separator_indices (UnityGtkMenuShell *shell) G_GNUC_INTERNAL;
214+
215+void unity_gtk_menu_shell_handle_item_notify (UnityGtkMenuShell *shell,
216+ UnityGtkMenuItem *item,
217+ const gchar *property) G_GNUC_INTERNAL;
218+
219+void unity_gtk_menu_shell_activate_item (UnityGtkMenuShell *shell,
220+ UnityGtkMenuItem *item) G_GNUC_INTERNAL;
221+
222+void unity_gtk_menu_shell_print (UnityGtkMenuShell *shell,
223+ guint indent) G_GNUC_INTERNAL;
224+
225+gboolean unity_gtk_menu_shell_is_debug (void) G_GNUC_INTERNAL;
226
227 G_END_DECLS
228
229
230=== modified file 'lib/unity-gtk-menu-shell.c'
231--- lib/unity-gtk-menu-shell.c 2014-01-13 15:41:42 +0000
232+++ lib/unity-gtk-menu-shell.c 2014-03-05 17:18:00 +0000
233@@ -435,6 +435,13 @@
234 unity_gtk_menu_shell_handle_item_label (UnityGtkMenuShell *shell,
235 UnityGtkMenuItem *item)
236 {
237+ g_return_if_fail (UNITY_GTK_IS_MENU_SHELL (shell));
238+ g_return_if_fail (UNITY_GTK_IS_MENU_ITEM (item));
239+ g_warn_if_fail (item->parent_shell == shell);
240+
241+ g_free (item->label);
242+ item->label = NULL;
243+
244 unity_gtk_menu_shell_update_item (shell, item);
245 }
246
247@@ -654,6 +661,41 @@
248 }
249 }
250
251+static void
252+unity_gtk_menu_shell_set_has_mnemonics (UnityGtkMenuShell *shell,
253+ gboolean has_mnemonics)
254+{
255+ g_return_if_fail (UNITY_GTK_IS_MENU_SHELL (shell));
256+
257+ if (has_mnemonics != shell->has_mnemonics)
258+ {
259+ shell->has_mnemonics = has_mnemonics;
260+
261+ if (shell->items != NULL)
262+ {
263+ guint i;
264+
265+ for (i = 0; i < shell->items->len; i++)
266+ unity_gtk_menu_shell_handle_item_label (shell, g_ptr_array_index (shell->items, i));
267+ }
268+ }
269+}
270+
271+static void
272+unity_gtk_menu_shell_handle_settings_notify (GObject *object,
273+ GParamSpec *pspec,
274+ gpointer user_data)
275+{
276+ gboolean has_mnemonics;
277+
278+ g_return_if_fail (GTK_IS_SETTINGS (object));
279+ g_return_if_fail (UNITY_GTK_IS_MENU_SHELL (user_data));
280+
281+ g_object_get (GTK_SETTINGS (object), "gtk-enable-mnemonics", &has_mnemonics, NULL);
282+
283+ unity_gtk_menu_shell_set_has_mnemonics (UNITY_GTK_MENU_SHELL (user_data), has_mnemonics);
284+}
285+
286 static void unity_gtk_menu_shell_clear_menu_shell (UnityGtkMenuShell *shell);
287
288 static void
289@@ -731,13 +773,18 @@
290 unity_gtk_menu_shell_dispose (GObject *object)
291 {
292 UnityGtkMenuShell *shell;
293+ GtkSettings *settings;
294
295 g_return_if_fail (UNITY_GTK_IS_MENU_SHELL (object));
296
297 shell = UNITY_GTK_MENU_SHELL (object);
298+ settings = gtk_settings_get_default ();
299
300 unity_gtk_menu_shell_set_menu_shell (shell, NULL);
301
302+ if (settings != NULL)
303+ g_signal_handlers_disconnect_by_func (settings, unity_gtk_menu_shell_handle_settings_notify, shell);
304+
305 G_OBJECT_CLASS (unity_gtk_menu_shell_parent_class)->dispose (object);
306 }
307
308@@ -806,6 +853,7 @@
309 static void
310 unity_gtk_menu_shell_init (UnityGtkMenuShell *self)
311 {
312+ self->has_mnemonics = TRUE;
313 }
314
315 /**
316@@ -822,6 +870,23 @@
317 unity_gtk_menu_shell_new (GtkMenuShell *menu_shell)
318 {
319 UnityGtkMenuShell *shell = g_object_new (UNITY_GTK_TYPE_MENU_SHELL, NULL);
320+ GtkSettings *settings = gtk_settings_get_default ();
321+
322+ if (settings != NULL)
323+ {
324+ g_signal_connect (settings, "notify::gtk-enable-mnemonics", G_CALLBACK (unity_gtk_menu_shell_handle_settings_notify), shell);
325+ g_object_get (settings, "gtk-enable-mnemonics", &shell->has_mnemonics, NULL);
326+ }
327+
328+ unity_gtk_menu_shell_set_menu_shell (shell, menu_shell);
329+
330+ return shell;
331+}
332+
333+UnityGtkMenuShell *
334+unity_gtk_menu_shell_new_internal (GtkMenuShell *menu_shell)
335+{
336+ UnityGtkMenuShell *shell = g_object_new (UNITY_GTK_TYPE_MENU_SHELL, NULL);
337
338 unity_gtk_menu_shell_set_menu_shell (shell, menu_shell);
339
340@@ -899,7 +964,7 @@
341 void
342 unity_gtk_menu_shell_handle_item_notify (UnityGtkMenuShell *shell,
343 UnityGtkMenuItem *item,
344- GParamSpec *pspec)
345+ const gchar *property)
346 {
347 static const gchar *visible_name;
348 static const gchar *sensitive_name;
349@@ -909,7 +974,7 @@
350 static const gchar *parent_name;
351 static const gchar *submenu_name;
352
353- const gchar *pspec_name;
354+ const gchar *name;
355
356 g_return_if_fail (UNITY_GTK_IS_MENU_SHELL (shell));
357 g_return_if_fail (UNITY_GTK_IS_MENU_ITEM (item));
358@@ -929,24 +994,24 @@
359 if (submenu_name == NULL)
360 submenu_name = g_intern_static_string ("submenu");
361
362- pspec_name = g_param_spec_get_name (pspec);
363+ name = g_intern_string (property);
364
365 if (unity_gtk_menu_shell_is_debug ())
366- g_print ("%s ((%s *) %p, (%s *) %p { \"%s\" }, %s)\n", G_STRFUNC, G_OBJECT_TYPE_NAME (shell), shell, G_OBJECT_TYPE_NAME (item), item, unity_gtk_menu_item_get_label (item), pspec_name);
367+ g_print ("%s ((%s *) %p, (%s *) %p { \"%s\" }, %s)\n", G_STRFUNC, G_OBJECT_TYPE_NAME (shell), shell, G_OBJECT_TYPE_NAME (item), item, unity_gtk_menu_item_get_label (item), name);
368
369- if (pspec_name == visible_name)
370+ if (name == visible_name)
371 unity_gtk_menu_shell_handle_item_visible (shell, item);
372- else if (pspec_name == sensitive_name)
373+ else if (name == sensitive_name)
374 unity_gtk_menu_shell_handle_item_sensitive (shell, item);
375- else if (pspec_name == label_name)
376+ else if (name == label_name)
377 unity_gtk_menu_shell_handle_item_label (shell, item);
378- else if (pspec_name == accel_path_name)
379+ else if (name == accel_path_name)
380 unity_gtk_menu_shell_handle_item_accel_path (shell, item);
381- else if (pspec_name == active_name)
382+ else if (name == active_name)
383 unity_gtk_menu_shell_handle_item_active (shell, item);
384- else if (pspec_name == parent_name)
385+ else if (name == parent_name)
386 unity_gtk_menu_shell_handle_item_parent (shell, item);
387- else if (pspec_name == submenu_name)
388+ else if (name == submenu_name)
389 unity_gtk_menu_shell_handle_item_submenu (shell, item);
390 }
391
392
393=== modified file 'lib/unity-gtk-menu-shell.h'
394--- lib/unity-gtk-menu-shell.h 2013-02-19 11:55:57 +0000
395+++ lib/unity-gtk-menu-shell.h 2014-03-05 17:18:00 +0000
396@@ -52,6 +52,7 @@
397 /*< private >*/
398 GtkMenuShell *menu_shell;
399 gulong menu_shell_insert_handler_id;
400+ gboolean has_mnemonics;
401 GPtrArray *items;
402 GPtrArray *sections;
403 GSequence *visible_indices;

Subscribers

People subscribed via source and target branches