Merge lp:~bratsche/libdbusmenu/accel-keys into lp:libdbusmenu/0.5

Proposed by Cody Russell
Status: Merged
Merged at revision: 116
Proposed branch: lp:~bratsche/libdbusmenu/accel-keys
Merge into: lp:libdbusmenu/0.5
Diff against target: 1044 lines (+811/-4)
12 files modified
.bzrignore (+6/-0)
libdbusmenu-glib/menuitem.h (+6/-0)
libdbusmenu-gtk/client.c (+179/-0)
libdbusmenu-gtk/client.h (+3/-0)
libdbusmenu-gtk/genericmenuitem.c (+4/-1)
libdbusmenu-gtk/menuitem.c (+208/-0)
libdbusmenu-gtk/menuitem.h (+7/-0)
tests/Makefile.am (+77/-2)
tests/run-xvfb.sh (+1/-1)
tests/test-gtk-objects.c (+145/-0)
tests/test-gtk-shortcut-client.c (+76/-0)
tests/test-gtk-shortcut-server.c (+99/-0)
To merge this branch: bzr merge lp:~bratsche/libdbusmenu/accel-keys
Reviewer Review Type Date Requested Status
DBus Menu Team Pending
Review via email: mp+28104@code.launchpad.net

This proposal supersedes a proposal from 2010-06-21.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2010-06-08 18:12:32 +0000
3+++ .bzrignore 2010-06-21 19:48:28 +0000
4@@ -71,6 +71,12 @@
5 libdbusmenu-gtk/DbusmenuGtk-0.2.tmp.gir
6 libdbusmenu-gtk/DbusmenuGtk-0.2.typelib
7 libdbusmenu-gtk/DbusmenuGtk-0.2.vapi
8+tests/test-gtk-objects
9+tests/test-gtk-objects-test
10+tests/test-gtk-objects.xml
11+tests/test-gtk-shortcut
12+tests/test-gtk-shortcut-client
13+tests/test-gtk-shortcut-server
14 tests/test-glib-submenu
15 tests/test-glib-submenu-client
16 tests/test-glib-submenu-server
17
18=== modified file 'libdbusmenu-glib/menuitem.h'
19--- libdbusmenu-glib/menuitem.h 2010-06-17 19:58:28 +0000
20+++ libdbusmenu-glib/menuitem.h 2010-06-21 19:48:28 +0000
21@@ -58,6 +58,7 @@
22 #define DBUSMENU_MENUITEM_PROP_ICON_DATA "icon-data"
23 #define DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE "toggle-type"
24 #define DBUSMENU_MENUITEM_PROP_TOGGLE_STATE "toggle-state"
25+#define DBUSMENU_MENUITEM_PROP_SHORTCUT "shortcut"
26 #define DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY "children-display"
27
28 #define DBUSMENU_MENUITEM_TOGGLE_CHECK "checkmark"
29@@ -69,6 +70,11 @@
30
31 #define DBUSMENU_MENUITEM_ICON_NAME_BLANK "blank-icon"
32
33+#define DBUSMENU_MENUITEM_SHORTCUT_CONTROL "Control"
34+#define DBUSMENU_MENUITEM_SHORTCUT_ALT "Alt"
35+#define DBUSMENU_MENUITEM_SHORTCUT_SHIFT "Shift"
36+#define DBUSMENU_MENUITEM_SHORTCUT_SUPER "Super"
37+
38 #define DBUSMENU_MENUITEM_CHILD_DISPLAY_SUBMENU "submenu"
39
40 /**
41
42=== modified file 'libdbusmenu-gtk/client.c'
43--- libdbusmenu-gtk/client.c 2010-05-26 22:18:29 +0000
44+++ libdbusmenu-gtk/client.c 2010-06-21 19:48:28 +0000
45@@ -36,6 +36,15 @@
46 #include "menuitem.h"
47 #include "genericmenuitem.h"
48
49+/* Private */
50+typedef struct _DbusmenuGtkClientPrivate DbusmenuGtkClientPrivate;
51+struct _DbusmenuGtkClientPrivate {
52+ GtkAccelGroup * agroup;
53+};
54+
55+#define DBUSMENU_GTKCLIENT_GET_PRIVATE(o) \
56+(G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUSMENU_GTKCLIENT_TYPE, DbusmenuGtkClientPrivate))
57+
58 /* Prototypes */
59 static void dbusmenu_gtkclient_class_init (DbusmenuGtkClientClass *klass);
60 static void dbusmenu_gtkclient_init (DbusmenuGtkClient *self);
61@@ -62,6 +71,8 @@
62 {
63 GObjectClass *object_class = G_OBJECT_CLASS (klass);
64
65+ g_type_class_add_private (klass, sizeof (DbusmenuGtkClientPrivate));
66+
67 object_class->dispose = dbusmenu_gtkclient_dispose;
68 object_class->finalize = dbusmenu_gtkclient_finalize;
69
70@@ -73,6 +84,10 @@
71 static void
72 dbusmenu_gtkclient_init (DbusmenuGtkClient *self)
73 {
74+ DbusmenuGtkClientPrivate * priv = DBUSMENU_GTKCLIENT_GET_PRIVATE(self);
75+
76+ priv->agroup = NULL;
77+
78 dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_DEFAULT, new_item_normal);
79 dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_SEPARATOR, new_item_seperator);
80
81@@ -85,6 +100,12 @@
82 static void
83 dbusmenu_gtkclient_dispose (GObject *object)
84 {
85+ DbusmenuGtkClientPrivate * priv = DBUSMENU_GTKCLIENT_GET_PRIVATE(object);
86+
87+ if (priv->agroup != NULL) {
88+ g_object_unref(priv->agroup);
89+ priv->agroup = NULL;
90+ }
91
92 G_OBJECT_CLASS (dbusmenu_gtkclient_parent_class)->dispose (object);
93 return;
94@@ -99,6 +120,151 @@
95 return;
96 }
97
98+/* Structure for passing data to swap_agroup */
99+typedef struct _swap_agroup_t swap_agroup_t;
100+struct _swap_agroup_t {
101+ DbusmenuGtkClient * client;
102+ GtkAccelGroup * old_agroup;
103+ GtkAccelGroup * new_agroup;
104+};
105+
106+/* Looks at the old version of the accelerator group and
107+ the new one and makes the state proper. */
108+static gboolean
109+do_swap_agroup (DbusmenuMenuitem * mi, gpointer userdata) {
110+ swap_agroup_t * data = (swap_agroup_t *)userdata;
111+
112+ /* If we don't have a shortcut we don't care */
113+ if (!dbusmenu_menuitem_property_exist(mi, DBUSMENU_MENUITEM_PROP_SHORTCUT)) {
114+ return FALSE;
115+ }
116+
117+ guint key = 0;
118+ GdkModifierType modifiers = 0;
119+
120+ dbusmenu_menuitem_property_get_shortcut(mi, &key, &modifiers);
121+
122+ g_debug("Setting shortcut on '%s': %d %X", dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL), key, modifiers);
123+
124+ if (key == 0) {
125+ return FALSE;
126+ }
127+
128+ GtkMenuItem * gmi = dbusmenu_gtkclient_menuitem_get(data->client, mi);
129+ if (gmi == NULL) {
130+ return FALSE;
131+ }
132+
133+ const gchar * accel_path = gtk_menu_item_get_accel_path(gmi);
134+
135+ if (accel_path != NULL) {
136+ gtk_accel_map_change_entry(accel_path, key, modifiers, TRUE /* replace */);
137+ } else {
138+ gchar * accel_path = g_strdup_printf("<Appmenus>/Generated/%X/%d", GPOINTER_TO_UINT(data->client), dbusmenu_menuitem_get_id(mi));
139+
140+ gtk_accel_map_add_entry(accel_path, key, modifiers);
141+ gtk_widget_set_accel_path(GTK_WIDGET(gmi), accel_path, data->new_agroup);
142+ g_free(accel_path);
143+ }
144+
145+ GtkMenu * submenu = dbusmenu_gtkclient_menuitem_get_submenu(data->client, mi);
146+ if (submenu != NULL) {
147+ gtk_menu_set_accel_group(submenu, data->new_agroup);
148+ }
149+
150+ return TRUE;
151+}
152+
153+static void
154+swap_agroup (DbusmenuMenuitem *mi, gpointer userdata) {
155+ do_swap_agroup (mi, userdata);
156+
157+ return; /* See what I did here, Ted? :) */
158+}
159+
160+/* Refresh the shortcut for an entry */
161+static void
162+refresh_shortcut (DbusmenuGtkClient * client, DbusmenuMenuitem * mi)
163+{
164+ g_return_if_fail(DBUSMENU_IS_GTKCLIENT(client));
165+ g_return_if_fail(DBUSMENU_IS_MENUITEM(mi));
166+
167+ DbusmenuGtkClientPrivate * priv = DBUSMENU_GTKCLIENT_GET_PRIVATE(client);
168+
169+ swap_agroup_t data;
170+ data.client = client;
171+ data.old_agroup = priv->agroup;
172+ data.new_agroup = priv->agroup;
173+
174+ if (do_swap_agroup(mi, &data)) {
175+ guint key;
176+ GdkModifierType mod;
177+ GtkMenuItem *gmi = dbusmenu_gtkclient_menuitem_get (client, mi);
178+
179+ dbusmenu_menuitem_property_get_shortcut (mi, &key, &mod);
180+
181+ gtk_widget_add_accelerator (GTK_WIDGET (gmi), "activate", priv->agroup, key, mod, GTK_ACCEL_VISIBLE);
182+ }
183+
184+ return;
185+}
186+
187+
188+/**
189+ dbusmenu_gtkclient_set_accel_group:
190+ @client: To set the group on
191+ @agroup: The new acceleration group
192+
193+ Sets the acceleration group for the menu items with accelerators
194+ on this client.
195+*/
196+void
197+dbusmenu_gtkclient_set_accel_group (DbusmenuGtkClient * client, GtkAccelGroup * agroup)
198+{
199+ g_return_if_fail(DBUSMENU_IS_GTKCLIENT(client));
200+ g_return_if_fail(GTK_IS_ACCEL_GROUP(agroup));
201+
202+ DbusmenuGtkClientPrivate * priv = DBUSMENU_GTKCLIENT_GET_PRIVATE(client);
203+
204+ DbusmenuMenuitem * root = dbusmenu_client_get_root(DBUSMENU_CLIENT(client));
205+ if (root != NULL) {
206+ swap_agroup_t data;
207+ data.client = client;
208+ data.old_agroup = priv->agroup;
209+ data.new_agroup = agroup;
210+
211+ dbusmenu_menuitem_foreach(root, swap_agroup, &data);
212+ }
213+
214+ if (priv->agroup != NULL) {
215+ g_object_unref(priv->agroup);
216+ priv->agroup = NULL;
217+ }
218+
219+ priv->agroup = agroup;
220+
221+ return;
222+}
223+
224+/**
225+ dbusmenu_gtkclient_get_accel_group:
226+ @client: Client to query for an accelerator group
227+
228+ Gets the accel group for this client.
229+
230+ Return value: Either a valid group or #NULL on error or
231+ none set.
232+*/
233+GtkAccelGroup *
234+dbusmenu_gtkclient_get_accel_group (DbusmenuGtkClient * client)
235+{
236+ g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), NULL);
237+
238+ DbusmenuGtkClientPrivate * priv = DBUSMENU_GTKCLIENT_GET_PRIVATE(client);
239+
240+ return priv->agroup;
241+}
242+
243 /* Internal Functions */
244
245 static const gchar * data_menuitem = "dbusmenugtk-data-gtkmenuitem";
246@@ -225,6 +391,17 @@
247 return;
248 }
249
250+/* Special handler for the shortcut changing as we need to have the
251+ client for that one to get the accel group. */
252+static void
253+menu_shortcut_change_cb (DbusmenuMenuitem * mi, gchar * prop, GValue * value, DbusmenuGtkClient * client)
254+{
255+ if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_SHORTCUT)) {
256+ refresh_shortcut(client, mi);
257+ }
258+ return;
259+}
260+
261 /* Call back that happens when the DbusmenuMenuitem
262 is destroyed. We're making sure to clean up everything
263 else down the pipe. */
264@@ -291,6 +468,7 @@
265
266 /* DbusmenuMenuitem signals */
267 g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menu_prop_change_cb), gmi);
268+ g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menu_shortcut_change_cb), client);
269 g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(delete_child), client);
270 g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED, G_CALLBACK(move_child), client);
271
272@@ -305,6 +483,7 @@
273 process_sensitive(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_ENABLED));
274 process_toggle_type(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE));
275 process_toggle_state(item, gmi, dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE));
276+ refresh_shortcut(client, item);
277
278 /* Oh, we're a child, let's deal with that */
279 if (parent != NULL) {
280
281=== modified file 'libdbusmenu-gtk/client.h'
282--- libdbusmenu-gtk/client.h 2010-05-26 22:18:29 +0000
283+++ libdbusmenu-gtk/client.h 2010-06-21 19:48:28 +0000
284@@ -79,6 +79,9 @@
285 GtkMenuItem * dbusmenu_gtkclient_menuitem_get (DbusmenuGtkClient * client, DbusmenuMenuitem * item);
286 GtkMenu * dbusmenu_gtkclient_menuitem_get_submenu (DbusmenuGtkClient * client, DbusmenuMenuitem * item);
287
288+void dbusmenu_gtkclient_set_accel_group (DbusmenuGtkClient * client, GtkAccelGroup * agroup);
289+GtkAccelGroup * dbusmenu_gtkclient_get_accel_group (DbusmenuGtkClient * client);
290+
291 void dbusmenu_gtkclient_newitem_base (DbusmenuGtkClient * client, DbusmenuMenuitem * item, GtkMenuItem * gmi, DbusmenuMenuitem * parent);
292
293 /**
294
295=== modified file 'libdbusmenu-gtk/genericmenuitem.c'
296--- libdbusmenu-gtk/genericmenuitem.c 2010-01-12 06:19:14 +0000
297+++ libdbusmenu-gtk/genericmenuitem.c 2010-06-21 19:48:28 +0000
298@@ -158,6 +158,8 @@
299 static void
300 set_label (GtkMenuItem * menu_item, const gchar * label)
301 {
302+ if (label == NULL) return;
303+
304 GtkWidget * child = gtk_bin_get_child(GTK_BIN(menu_item));
305 GtkLabel * labelw = NULL;
306 gboolean suppress_update = FALSE;
307@@ -191,9 +193,10 @@
308 update the one that we already have. */
309 if (labelw == NULL) {
310 /* Build it */
311- labelw = GTK_LABEL(gtk_label_new(label));
312+ labelw = GTK_LABEL(gtk_accel_label_new(label));
313 gtk_label_set_use_underline(GTK_LABEL(labelw), TRUE);
314 gtk_misc_set_alignment(GTK_MISC(labelw), 0.0, 0.5);
315+ gtk_accel_label_set_accel_widget(GTK_ACCEL_LABEL(labelw), GTK_WIDGET(menu_item));
316 gtk_widget_show(GTK_WIDGET(labelw));
317
318 /* Check to see if it needs to be in the bin for this
319
320=== modified file 'libdbusmenu-gtk/menuitem.c'
321--- libdbusmenu-gtk/menuitem.c 2009-09-03 20:32:17 +0000
322+++ libdbusmenu-gtk/menuitem.c 2010-06-21 19:48:28 +0000
323@@ -27,6 +27,8 @@
324 */
325
326 #include "menuitem.h"
327+#include <gdk/gdk.h>
328+#include <gtk/gtk.h>
329
330 /**
331 dbusmenu_menuitem_property_set_image:
332@@ -128,3 +130,209 @@
333 return icon;
334 }
335
336+/**
337+ dbusmenu_menuitem_property_set_shortcut_string:
338+ @menuitem: The #DbusmenuMenuitem to set the shortcut on
339+ @shortcut: String describing the shortcut
340+
341+ This function takes a GTK shortcut string as defined in
342+ #gtk_accelerator_parse and turns that into the information
343+ required to send it over DBusmenu.
344+
345+ Return value: Whether it was successful at setting the property.
346+*/
347+gboolean
348+dbusmenu_menuitem_property_set_shortcut_string (DbusmenuMenuitem * menuitem, const gchar * shortcut)
349+{
350+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(menuitem), FALSE);
351+ g_return_val_if_fail(shortcut != NULL, FALSE);
352+
353+ guint key = 0;
354+ GdkModifierType modifier = 0;
355+
356+ gtk_accelerator_parse(shortcut, &key, &modifier);
357+
358+ if (key == 0) {
359+ g_warning("Unable to parse shortcut string '%s'", shortcut);
360+ return FALSE;
361+ }
362+
363+ return dbusmenu_menuitem_property_set_shortcut(menuitem, key, modifier);
364+}
365+
366+/* Append strings to an g_value_array */
367+static void
368+_g_value_array_append_string (GValueArray * array, const gchar * string)
369+{
370+ GValue value = {0};
371+ g_value_init(&value, G_TYPE_STRING);
372+ g_value_set_string(&value, string);
373+ g_value_array_append(array, &value);
374+ return;
375+}
376+
377+/**
378+ dbusmenu_menuitem_property_set_shortcut:
379+ @menuitem: The #DbusmenuMenuitem to set the shortcut on
380+ @key: The keycode of the key to send
381+ @modifier: A bitmask of modifiers used to activate the item
382+
383+ Takes the modifer described by @key and @modifier and places that into
384+ the format sending across Dbus for shortcuts.
385+
386+ Return value: Whether it was successful at setting the property.
387+*/
388+gboolean
389+dbusmenu_menuitem_property_set_shortcut (DbusmenuMenuitem * menuitem, guint key, GdkModifierType modifier)
390+{
391+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(menuitem), FALSE);
392+ g_return_val_if_fail(gtk_accelerator_valid(key, modifier), FALSE);
393+
394+ GValueArray * array = g_value_array_new(4); /* Four seems like the max we'd need, plus it's still small */
395+
396+ if (modifier & GDK_CONTROL_MASK) {
397+ _g_value_array_append_string(array, DBUSMENU_MENUITEM_SHORTCUT_CONTROL);
398+ }
399+ if (modifier & GDK_MOD1_MASK) {
400+ _g_value_array_append_string(array, DBUSMENU_MENUITEM_SHORTCUT_ALT);
401+ }
402+ if (modifier & GDK_SHIFT_MASK) {
403+ _g_value_array_append_string(array, DBUSMENU_MENUITEM_SHORTCUT_SHIFT);
404+ }
405+ if (modifier & GDK_SUPER_MASK) {
406+ _g_value_array_append_string(array, DBUSMENU_MENUITEM_SHORTCUT_SUPER);
407+ }
408+
409+ _g_value_array_append_string(array, gdk_keyval_name(key));
410+
411+ GValueArray * wrapper = g_value_array_new(1);
412+ GValue wrap_val = {0};
413+ g_value_init(&wrap_val, G_TYPE_VALUE_ARRAY);
414+ g_value_set_boxed(&wrap_val, array);
415+ g_value_array_append(wrapper, &wrap_val);
416+
417+ GValue value = {0};
418+ g_value_init(&value, G_TYPE_VALUE_ARRAY);
419+ g_value_set_boxed(&value, wrapper);
420+
421+ dbusmenu_menuitem_property_set_value(menuitem, DBUSMENU_MENUITEM_PROP_SHORTCUT, &value);
422+
423+ return TRUE;
424+}
425+
426+/* Look at the closures in an accel group and find
427+ the one that matches the one we've been passed */
428+static gboolean
429+find_closure (GtkAccelKey * key, GClosure * closure, gpointer user_data)
430+{
431+ return closure == user_data;
432+}
433+
434+/**
435+ dbusmenu_menuitem_property_set_shortcut_menuitem:
436+ @menuitem: The #DbusmenuMenuitem to set the shortcut on
437+ @gmi: A menu item to steal the shortcut off of
438+
439+ Takes the shortcut that is installed on a menu item and calls
440+ #dbusmenu_menuitem_property_set_shortcut with it. It also sets
441+ up listeners to watch it change.
442+
443+ Return value: Whether it was successful at setting the property.
444+*/
445+gboolean
446+dbusmenu_menuitem_property_set_shortcut_menuitem (DbusmenuMenuitem * menuitem, const GtkMenuItem * gmi)
447+{
448+ g_return_val_if_fail(DBUSMENU_IS_MENUITEM(menuitem), FALSE);
449+ g_return_val_if_fail(GTK_IS_MENU_ITEM(gmi), FALSE);
450+
451+ GClosure * closure = NULL;
452+ GList * clist;
453+
454+ clist = gtk_widget_list_accel_closures(GTK_WIDGET(gmi));
455+ if (clist == NULL) {
456+ g_warning("Menuitem does not have any closures.");
457+ return FALSE;
458+ }
459+
460+ closure = (GClosure *)clist->data;
461+ g_list_free(clist);
462+
463+ GtkAccelGroup * group = gtk_accel_group_from_accel_closure(closure);
464+
465+ /* Seriously, if this returns NULL something is seriously
466+ wrong in GTK. */
467+ g_return_val_if_fail(group != NULL, FALSE);
468+
469+ GtkAccelKey * key = gtk_accel_group_find(group, find_closure, closure);
470+ /* Again, not much we can do except complain loudly. */
471+ g_return_val_if_fail(key != NULL, FALSE);
472+
473+ return dbusmenu_menuitem_property_set_shortcut(menuitem, key->accel_key, key->accel_mods);
474+}
475+
476+/**
477+ dbusmenu_menuitem_property_get_shortcut:
478+ @menuitem: The #DbusmenuMenuitem to get the shortcut off
479+ @key: Location to put the key value
480+ @modifier: Location to put the modifier mask
481+
482+ This function gets a GTK shortcut as a key and a mask
483+ for use to set the accelerators.
484+*/
485+void
486+dbusmenu_menuitem_property_get_shortcut (DbusmenuMenuitem * menuitem, guint * key, GdkModifierType * modifier)
487+{
488+ *key = 0;
489+ *modifier = 0;
490+
491+ g_return_if_fail(DBUSMENU_IS_MENUITEM(menuitem));
492+
493+ const GValue * wrapper = dbusmenu_menuitem_property_get_value(menuitem, DBUSMENU_MENUITEM_PROP_SHORTCUT);
494+ if (wrapper == NULL) {
495+ return;
496+ }
497+
498+ GValueArray * wrapperarray = (GValueArray *)g_value_get_boxed(wrapper);
499+ if (wrapperarray->n_values == 0) {
500+ return;
501+ }
502+
503+ if (wrapperarray->n_values != 1) {
504+ g_warning("Shortcut is more than one entry. Which we don't currently support. Taking the first.");
505+ }
506+
507+ GValue * ventryarray = g_value_array_get_nth(wrapperarray, 0);
508+ GValueArray * entryarray = (GValueArray *)g_value_get_boxed(ventryarray);
509+ if (entryarray->n_values == 0) {
510+ /* Seems a little odd, but really, we're saying that it isn't a
511+ shortcut, so I'm comfortable with exiting silently. */
512+ return;
513+ }
514+
515+ /* Parse through modifiers */
516+ int i;
517+ for (i = 0; i < entryarray->n_values - 1; i++) {
518+ if (g_strcmp0(g_value_get_string(g_value_array_get_nth(entryarray, i)), DBUSMENU_MENUITEM_SHORTCUT_CONTROL) == 0) {
519+ *modifier |= GDK_CONTROL_MASK;
520+ continue;
521+ }
522+ if (g_strcmp0(g_value_get_string(g_value_array_get_nth(entryarray, i)), DBUSMENU_MENUITEM_SHORTCUT_ALT) == 0) {
523+ *modifier |= GDK_MOD1_MASK;
524+ continue;
525+ }
526+ if (g_strcmp0(g_value_get_string(g_value_array_get_nth(entryarray, i)), DBUSMENU_MENUITEM_SHORTCUT_SHIFT) == 0) {
527+ *modifier |= GDK_SHIFT_MASK;
528+ continue;
529+ }
530+ if (g_strcmp0(g_value_get_string(g_value_array_get_nth(entryarray, i)), DBUSMENU_MENUITEM_SHORTCUT_SUPER) == 0) {
531+ *modifier |= GDK_SUPER_MASK;
532+ continue;
533+ }
534+ }
535+
536+ GdkModifierType tempmod;
537+
538+ gtk_accelerator_parse(g_value_get_string(g_value_array_get_nth(entryarray, entryarray->n_values - 1)), key, &tempmod);
539+
540+ return;
541+}
542
543=== modified file 'libdbusmenu-gtk/menuitem.h'
544--- libdbusmenu-gtk/menuitem.h 2009-09-02 18:29:01 +0000
545+++ libdbusmenu-gtk/menuitem.h 2010-06-21 19:48:28 +0000
546@@ -32,8 +32,15 @@
547 #include <glib.h>
548 #include <gdk-pixbuf/gdk-pixbuf.h>
549 #include <libdbusmenu-glib/menuitem.h>
550+#include <gdk/gdk.h>
551+#include <gtk/gtk.h>
552
553 gboolean dbusmenu_menuitem_property_set_image (DbusmenuMenuitem * menuitem, const gchar * property, const GdkPixbuf * data);
554 GdkPixbuf * dbusmenu_menuitem_property_get_image (DbusmenuMenuitem * menuitem, const gchar * property);
555
556+gboolean dbusmenu_menuitem_property_set_shortcut (DbusmenuMenuitem * menuitem, guint key, GdkModifierType modifier);
557+gboolean dbusmenu_menuitem_property_set_shortcut_string (DbusmenuMenuitem * menuitem, const gchar * shortcut);
558+gboolean dbusmenu_menuitem_property_set_shortcut_menuitem (DbusmenuMenuitem * menuitem, const GtkMenuItem * gmi);
559+void dbusmenu_menuitem_property_get_shortcut (DbusmenuMenuitem * menuitem, guint * key, GdkModifierType * modifiers);
560+
561 #endif
562
563=== modified file 'tests/Makefile.am'
564--- tests/Makefile.am 2010-06-08 18:12:12 +0000
565+++ tests/Makefile.am 2010-06-21 19:48:28 +0000
566@@ -7,8 +7,10 @@
567 test-glib-properties \
568 test-glib-proxy \
569 test-glib-simple-items \
570+ test-gtk-objects-test \
571 test-glib-submenu \
572 test-gtk-label \
573+ test-gtk-shortcut \
574 test-gtk-reorder
575
576 check_PROGRAMS = \
577@@ -21,10 +23,13 @@
578 test-glib-proxy-client \
579 test-glib-proxy-server \
580 test-glib-proxy-proxy \
581+ test-gtk-objects \
582 test-glib-submenu-client \
583 test-glib-submenu-server \
584 test-gtk-label-client \
585 test-gtk-label-server \
586+ test-gtk-shortcut-client \
587+ test-gtk-shortcut-server \
588 test-glib-simple-items \
589 test-gtk-reorder-server
590
591@@ -119,7 +124,7 @@
592
593 test-glib-objects-test: test-glib-objects Makefile.am
594 @echo "#!/bin/bash" > $@
595- @echo $(DBUS_RUNNER) --task gtester --parameter --verbose --parameter -k --parameter -o --parameter $(OBJECT_XML_REPORT) --parameter ./test-glib-objects >> $@
596+ @echo $(DBUS_RUNNER) --task gtester --task-name test --parameter --verbose --parameter -k --parameter -o --parameter $(OBJECT_XML_REPORT) --parameter ./test-glib-objects >> $@
597 @chmod +x $@
598
599 test_glib_objects_SOURCES = \
600@@ -231,6 +236,34 @@
601 ../libdbusmenu-glib/libdbusmenu-glib.la \
602 $(DBUSMENUGLIB_LIBS)
603
604+######################
605+# Test GTK Object
606+######################
607+
608+GTK_OBJECT_XML_REPORT = test-gtk-objects.xml
609+
610+test-gtk-objects-test: test-gtk-objects Makefile.am
611+ @echo "#!/bin/bash" > $@
612+ @echo $(XVFB_RUN) >> $@
613+ @echo $(DBUS_RUNNER) --task gtester --task-name test --parameter --verbose --parameter -k --parameter -o --parameter $(GTK_OBJECT_XML_REPORT) --parameter ./test-gtk-objects >> $@
614+ @chmod +x $@
615+
616+test_gtk_objects_SOURCES = \
617+ test-gtk-objects.c
618+
619+test_gtk_objects_CFLAGS = \
620+ -I $(srcdir)/.. \
621+ $(DBUSMENUGLIB_CFLAGS) \
622+ $(DBUSMENUGTK_CFLAGS) \
623+ -DSRCDIR="\"$(srcdir)\"" \
624+ -Wall -Werror
625+
626+test_gtk_objects_LDADD = \
627+ ../libdbusmenu-glib/libdbusmenu-glib.la \
628+ ../libdbusmenu-gtk/libdbusmenu-gtk.la \
629+ $(DBUSMENUGLIB_LIBS) \
630+ $(DBUSMENUGTK_LIBS)
631+
632 #########################
633 # Test GTK Label
634 #########################
635@@ -272,6 +305,46 @@
636 $(DBUSMENUTESTS_LIBS)
637
638 #########################
639+# Test GTK Shortcut
640+#########################
641+
642+test-gtk-shortcut: test-gtk-shortcut-client test-gtk-shortcut-server Makefile.am
643+ @echo "#!/bin/bash" > $@
644+ @echo $(XVFB_RUN) >> $@
645+ @echo $(DBUS_RUNNER) --task ./test-gtk-shortcut-client --task-name Client --task ./test-gtk-shortcut-server --task-name Server --ignore-return >> $@
646+ @chmod +x $@
647+
648+test_gtk_shortcut_server_SOURCES = \
649+ test-gtk-shortcut-server.c
650+
651+test_gtk_shortcut_server_CFLAGS = \
652+ -I $(srcdir)/.. \
653+ $(DBUSMENUGTK_CFLAGS) \
654+ $(DBUSMENUTESTS_CFLAGS) \
655+ $(DBUSMENUGLIB_CFLAGS) -Wall -Werror
656+
657+test_gtk_shortcut_server_LDADD = \
658+ ../libdbusmenu-glib/libdbusmenu-glib.la \
659+ ../libdbusmenu-gtk/libdbusmenu-gtk.la \
660+ $(DBUSMENUGTK_LIBS) \
661+ $(DBUSMENUTESTS_LIBS)
662+
663+test_gtk_shortcut_client_SOURCES = \
664+ test-gtk-shortcut-client.c
665+
666+test_gtk_shortcut_client_CFLAGS = \
667+ -I $(srcdir)/.. \
668+ $(DBUSMENUGTK_CFLAGS) \
669+ $(DBUSMENUTESTS_CFLAGS) \
670+ $(DBUSMENUGLIB_CFLAGS) -Wall -Werror
671+
672+test_gtk_shortcut_client_LDADD = \
673+ ../libdbusmenu-glib/libdbusmenu-glib.la \
674+ ../libdbusmenu-gtk/libdbusmenu-gtk.la \
675+ $(DBUSMENUGTK_LIBS) \
676+ $(DBUSMENUTESTS_LIBS)
677+
678+#########################
679 # Test GTK Reorder
680 #########################
681
682@@ -329,6 +402,7 @@
683 $(examples_DATA) \
684 run-xvfb.sh \
685 $(json_DATA) \
686+ test-gtk-objects.jpg \
687 dbusmenu-gtk/dbusMenuTest \
688 dbusmenu-gtk/mago_tests/dbusmenu.xml \
689 dbusmenu-gtk/mago_tests/dbusmenu.py \
690@@ -357,5 +431,6 @@
691
692 DISTCLEANFILES = \
693 $(TESTS) \
694- $(OBJECT_XML_REPORT)
695+ $(OBJECT_XML_REPORT) \
696+ $(GTK_OBJECT_XML_REPORT)
697
698
699=== modified file 'tests/run-xvfb.sh'
700--- tests/run-xvfb.sh 2009-11-20 00:03:49 +0000
701+++ tests/run-xvfb.sh 2010-06-21 19:48:28 +0000
702@@ -1,4 +1,4 @@
703-if [ "$DISPLAY" == "" ]; then
704+if [ "x$DISPLAY" == "x" ]; then
705 Xvfb -ac -noreset -screen 0 800x600x16 -help 2>/dev/null 1>&2
706 XID=`for id in 101 102 103 104 105 106 107 197 199 211 223 227 293 307 308 309 310 311 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 4703 4721 4723 4729 4733 4751 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 ; do test -e /tmp/.X$id-lock || { echo $id; exit 0; }; done; exit 1`
707 { Xvfb -ac -noreset -screen 0 800x600x16 :$XID -screen 0 800x600x16 -nolisten tcp -auth /dev/null >/dev/null 2>&1 & trap "kill -15 $! " 0 HUP INT QUIT TRAP USR1 PIPE TERM ; } || { echo "Gtk+Tests:ERROR: Failed to start Xvfb environment for X11 target tests."; exit 1; }
708
709=== added file 'tests/test-gtk-objects.c'
710--- tests/test-gtk-objects.c 1970-01-01 00:00:00 +0000
711+++ tests/test-gtk-objects.c 2010-06-21 19:48:28 +0000
712@@ -0,0 +1,145 @@
713+/*
714+Testing for the various objects just by themselves.
715+
716+Copyright 2010 Canonical Ltd.
717+
718+Authors:
719+ Ted Gould <ted@canonical.com>
720+
721+This program is free software: you can redistribute it and/or modify it
722+under the terms of the GNU General Public License version 3, as published
723+by the Free Software Foundation.
724+
725+This program is distributed in the hope that it will be useful, but
726+WITHOUT ANY WARRANTY; without even the implied warranties of
727+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
728+PURPOSE. See the GNU General Public License for more details.
729+
730+You should have received a copy of the GNU General Public License along
731+with this program. If not, see <http://www.gnu.org/licenses/>.
732+*/
733+
734+#include <libdbusmenu-glib/menuitem.h>
735+#include <libdbusmenu-gtk/menuitem.h>
736+#include <gdk/gdkkeysyms.h>
737+
738+#define TEST_IMAGE SRCDIR "/" "test-gtk-objects.jpg"
739+
740+/* Building the basic menu item, make sure we didn't break
741+ any core GObject stuff */
742+static void
743+test_object_menuitem (void)
744+{
745+ /* Build a menu item */
746+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
747+
748+ /* Test to make sure it's a happy object */
749+ g_assert(item != NULL);
750+ g_assert(G_IS_OBJECT(item));
751+ g_assert(DBUSMENU_IS_MENUITEM(item));
752+
753+ /* Set up a check to make sure it gets destroyed on unref */
754+ g_object_add_weak_pointer(G_OBJECT(item), (gpointer *)&item);
755+ g_object_unref(item);
756+
757+ /* Did it go away? */
758+ g_assert(item == NULL);
759+
760+ return;
761+}
762+
763+/* Setting and getting a pixbuf */
764+static void
765+test_object_prop_pixbuf (void)
766+{
767+ const gchar * prop_name = "image-test";
768+
769+ /* Build a menu item */
770+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
771+
772+ /* Test to make sure it's a happy object */
773+ g_assert(item != NULL);
774+ g_assert(G_IS_OBJECT(item));
775+ g_assert(DBUSMENU_IS_MENUITEM(item));
776+
777+ /* Load our image */
778+ GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file(TEST_IMAGE, NULL);
779+ g_assert(pixbuf != NULL);
780+
781+ /* Set the property */
782+ gboolean success = dbusmenu_menuitem_property_set_image(item, prop_name, pixbuf);
783+ g_assert(success);
784+ g_object_unref(pixbuf);
785+
786+ /* Check to see if it's set */
787+ const GValue * val = dbusmenu_menuitem_property_get_value(item, prop_name);
788+ g_assert(val != NULL);
789+
790+ /* Get the pixbuf back! */
791+ GdkPixbuf * newpixbuf = dbusmenu_menuitem_property_get_image(item, prop_name);
792+ g_assert(newpixbuf != NULL);
793+ g_object_unref(newpixbuf);
794+
795+ g_object_unref(item);
796+
797+ return;
798+}
799+
800+/* Setting and getting a shortcut */
801+static void
802+test_object_prop_shortcut (void)
803+{
804+ /* Build a menu item */
805+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
806+
807+ /* Test to make sure it's a happy object */
808+ g_assert(item != NULL);
809+ g_assert(G_IS_OBJECT(item));
810+ g_assert(DBUSMENU_IS_MENUITEM(item));
811+
812+ guint key = GDK_c;
813+ GdkModifierType modifier = GDK_CONTROL_MASK;
814+
815+ /* Set a shortcut */
816+ gboolean success = dbusmenu_menuitem_property_set_shortcut(item, key, modifier);
817+ g_assert(success);
818+
819+ /* Check for value */
820+ const GValue * val = dbusmenu_menuitem_property_get_value(item, DBUSMENU_MENUITEM_PROP_SHORTCUT);
821+ g_assert(val != NULL);
822+
823+ /* Check to see if we love it */
824+ guint newkey = 0;
825+ GdkModifierType newmodifier = 0;
826+ dbusmenu_menuitem_property_get_shortcut(item, &newkey, &newmodifier);
827+
828+ g_assert(key == newkey);
829+ g_assert(newmodifier == modifier);
830+
831+ g_object_unref(item);
832+
833+ return;
834+}
835+
836+/* Build the test suite */
837+static void
838+test_gtk_objects_suite (void)
839+{
840+ g_test_add_func ("/dbusmenu/gtk/objects/menuitem/base", test_object_menuitem);
841+ g_test_add_func ("/dbusmenu/gtk/objects/menuitem/prop_pixbuf", test_object_prop_pixbuf);
842+ g_test_add_func ("/dbusmenu/gtk/objects/menuitem/prop_shortcut", test_object_prop_shortcut);
843+ return;
844+}
845+
846+gint
847+main (gint argc, gchar * argv[])
848+{
849+ gtk_init(&argc, &argv);
850+
851+ g_test_init(&argc, &argv, NULL);
852+
853+ /* Test suites */
854+ test_gtk_objects_suite();
855+
856+ return g_test_run ();
857+}
858
859=== added file 'tests/test-gtk-objects.jpg'
860Binary files tests/test-gtk-objects.jpg 1970-01-01 00:00:00 +0000 and tests/test-gtk-objects.jpg 2010-06-21 19:48:28 +0000 differ
861=== added file 'tests/test-gtk-shortcut-client.c'
862--- tests/test-gtk-shortcut-client.c 1970-01-01 00:00:00 +0000
863+++ tests/test-gtk-shortcut-client.c 2010-06-21 19:48:28 +0000
864@@ -0,0 +1,76 @@
865+/*
866+A test for libdbusmenu to ensure its quality.
867+
868+Copyright 2009 Canonical Ltd.
869+
870+Authors:
871+ Ted Gould <ted@canonical.com>
872+
873+This program is free software: you can redistribute it and/or modify it
874+under the terms of the GNU General Public License version 3, as published
875+by the Free Software Foundation.
876+
877+This program is distributed in the hope that it will be useful, but
878+WITHOUT ANY WARRANTY; without even the implied warranties of
879+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
880+PURPOSE. See the GNU General Public License for more details.
881+
882+You should have received a copy of the GNU General Public License along
883+with this program. If not, see <http://www.gnu.org/licenses/>.
884+*/
885+
886+#include <gtk/gtk.h>
887+#include <libdbusmenu-gtk/menu.h>
888+#include <libdbusmenu-gtk/client.h>
889+
890+static GMainLoop * mainloop = NULL;
891+static gboolean passed = TRUE;
892+static guint death_timer = 0;
893+
894+static gboolean
895+timer_func (gpointer data)
896+{
897+ passed = TRUE;
898+ g_main_loop_quit(mainloop);
899+ return FALSE;
900+}
901+
902+int
903+main (int argc, char ** argv)
904+{
905+ gtk_init(&argc, &argv);
906+
907+ g_debug("Building Window");
908+ GtkWidget * window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
909+ GtkWidget * menubar = gtk_menu_bar_new();
910+ GtkWidget * menuitem = gtk_menu_item_new_with_label("Test");
911+
912+ DbusmenuGtkMenu * dmenu = dbusmenu_gtkmenu_new ("glib.label.test", "/org/test");
913+ DbusmenuGtkClient * dclient = dbusmenu_gtkmenu_get_client(dmenu);
914+
915+ GtkAccelGroup * agroup = gtk_accel_group_new();
916+ dbusmenu_gtkclient_set_accel_group(dclient, agroup);
917+
918+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), GTK_WIDGET(dmenu));
919+ gtk_widget_show(menuitem);
920+ gtk_menu_bar_append(menubar, menuitem);
921+ gtk_widget_show(menubar);
922+ gtk_container_add(GTK_CONTAINER(window), menubar);
923+ gtk_window_set_title(GTK_WINDOW(window), "libdbusmenu-gtk test");
924+ gtk_window_add_accel_group(GTK_WINDOW(window), agroup);
925+ gtk_widget_show(window);
926+
927+ death_timer = g_timeout_add_seconds(10, timer_func, window);
928+
929+ g_debug("Entering Mainloop");
930+ mainloop = g_main_loop_new(NULL, FALSE);
931+ g_main_loop_run(mainloop);
932+
933+ if (passed) {
934+ g_debug("Quiting");
935+ return 0;
936+ } else {
937+ g_debug("Quiting as we're a failure");
938+ return 1;
939+ }
940+}
941
942=== added file 'tests/test-gtk-shortcut-server.c'
943--- tests/test-gtk-shortcut-server.c 1970-01-01 00:00:00 +0000
944+++ tests/test-gtk-shortcut-server.c 2010-06-21 19:48:28 +0000
945@@ -0,0 +1,99 @@
946+/*
947+A test for libdbusmenu to ensure its quality.
948+
949+Copyright 2009 Canonical Ltd.
950+
951+Authors:
952+ Ted Gould <ted@canonical.com>
953+
954+This program is free software: you can redistribute it and/or modify it
955+under the terms of the GNU General Public License version 3, as published
956+by the Free Software Foundation.
957+
958+This program is distributed in the hope that it will be useful, but
959+WITHOUT ANY WARRANTY; without even the implied warranties of
960+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
961+PURPOSE. See the GNU General Public License for more details.
962+
963+You should have received a copy of the GNU General Public License along
964+with this program. If not, see <http://www.gnu.org/licenses/>.
965+*/
966+
967+#include <glib.h>
968+#include <gdk/gdkkeysyms.h>
969+
970+#include <dbus/dbus.h>
971+#include <dbus/dbus-glib.h>
972+#include <dbus/dbus-glib-lowlevel.h>
973+#include <dbus/dbus-glib-bindings.h>
974+
975+#include <libdbusmenu-glib/menuitem.h>
976+#include <libdbusmenu-glib/server.h>
977+#include <libdbusmenu-gtk/menuitem.h>
978+
979+GMainLoop * mainloop = NULL;
980+DbusmenuServer * server = NULL;
981+
982+gboolean
983+timer_func (gpointer userdata)
984+{
985+ g_main_loop_quit(mainloop);
986+ return FALSE;
987+}
988+
989+void
990+build_menu (void)
991+{
992+ DbusmenuMenuitem * item;
993+
994+ DbusmenuMenuitem * root = dbusmenu_menuitem_new();
995+
996+ item = dbusmenu_menuitem_new();
997+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, "Control-L");
998+ dbusmenu_menuitem_property_set_shortcut(item, GDK_l, GDK_CONTROL_MASK);
999+ dbusmenu_menuitem_child_append(root, item);
1000+ g_object_unref(item);
1001+
1002+
1003+ dbusmenu_server_set_root(server, root);
1004+ g_object_unref(root);
1005+
1006+ return;
1007+}
1008+
1009+int
1010+main (int argc, char ** argv)
1011+{
1012+ GError * error = NULL;
1013+
1014+ g_type_init();
1015+
1016+ DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
1017+ g_debug("DBus ID: %s", dbus_connection_get_server_id(dbus_g_connection_get_connection(dbus_g_bus_get(DBUS_BUS_SESSION, NULL))));
1018+
1019+ DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
1020+ guint nameret = 0;
1021+
1022+ if (!org_freedesktop_DBus_request_name(bus_proxy, "glib.label.test", 0, &nameret, &error)) {
1023+ g_error("Unable to call to request name");
1024+ return 1;
1025+ }
1026+
1027+ if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
1028+ g_error("Unable to get name");
1029+ return 1;
1030+ }
1031+
1032+ server = dbusmenu_server_new("/org/test");
1033+ build_menu();
1034+
1035+ g_timeout_add_seconds(10, timer_func, NULL);
1036+
1037+ mainloop = g_main_loop_new(NULL, FALSE);
1038+ g_main_loop_run(mainloop);
1039+
1040+ g_debug("Quiting");
1041+
1042+ return 0;
1043+}
1044+

Subscribers

People subscribed via source and target branches