Merge lp:~ted/libdbusmenu/parse-serializable-menuitem into lp:libdbusmenu/0.5

Proposed by Ted Gould
Status: Superseded
Proposed branch: lp:~ted/libdbusmenu/parse-serializable-menuitem
Merge into: lp:libdbusmenu/0.5
Prerequisite: lp:~ted/libdbusmenu/serializable-menuitem
Diff against target: 1069 lines (+925/-9)
9 files modified
.bzrignore (+4/-0)
libdbusmenu-glib/client.h (+21/-0)
libdbusmenu-gtk/Makefile.am (+3/-0)
libdbusmenu-gtk/parser.c (+698/-0)
libdbusmenu-gtk/parser.h (+37/-0)
libdbusmenu-gtk/serializablemenuitem.c (+5/-5)
libdbusmenu-gtk/serializablemenuitem.h (+9/-2)
tests/Makefile.am (+33/-2)
tests/test-gtk-parser.c (+115/-0)
To merge this branch: bzr merge lp:~ted/libdbusmenu/parse-serializable-menuitem
Reviewer Review Type Date Requested Status
Mikkel Kamstrup Erlandsen Pending
Review via email: mp+47668@code.launchpad.net

This proposal supersedes a proposal from 2011-01-26.

This proposal has been superseded by a proposal from 2011-01-27.

Description of the change

Makes the parser look at serializable menuitems. This is also dependent on the serializable menuitem branch, but I can't be dependent on two. Please ignore that file :)

Resubmitting so it's dependent on serializable-menuitem as the parser is now in trunk. Hopefully will create a better diff.

To post a comment you must log in.
Revision history for this message
Mikkel Kamstrup Erlandsen (kamstrup) wrote : Posted in a previous version of this proposal

How does this branch relate to https://code.launchpad.net/~ted/dbusmenu/serializable-menuitem/+merge/47604 ? They look identical?

review: Needs Information
196. By Ted Gould

Updating to serializeable menuitem branch. Some function prototype changes.

197. By Ted Gould

Fix changing prototypes.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2011-01-27 15:48:01 +0000
+++ .bzrignore 2011-01-27 15:48:01 +0000
@@ -223,3 +223,7 @@
223libdbusmenu-gtk/libdbusmenu_gtk_la-serializablemenuitem.lo223libdbusmenu-gtk/libdbusmenu_gtk_la-serializablemenuitem.lo
224docs/libdbusmenu-gtk/reference/html/DbusmenuGtkSerializableMenuItem.html224docs/libdbusmenu-gtk/reference/html/DbusmenuGtkSerializableMenuItem.html
225docs/libdbusmenu-gtk/reference/tmpl/serializablemenuitem.sgml225docs/libdbusmenu-gtk/reference/tmpl/serializablemenuitem.sgml
226libdbusmenu-gtk/libdbusmenu_gtk_la-parser.lo
227test-gtk-parser
228test-gtk-parser-test
229test-gtk-parser.xml
226230
=== modified file 'libdbusmenu-glib/client.h'
--- libdbusmenu-glib/client.h 2011-01-27 15:48:01 +0000
+++ libdbusmenu-glib/client.h 2011-01-27 15:48:01 +0000
@@ -110,7 +110,28 @@
110 DbusmenuClientPrivate * priv;110 DbusmenuClientPrivate * priv;
111};111};
112112
113/**
114 DbusmenuClientTypeHandler:
115 @newitem: The #DbusmenuMenuitem that was created
116 @parent: The parent of @newitem or #NULL if none
117 @client: A pointer to the #DbusmenuClient
118 @user_data: The data you gave us
119
120 The type handler is called when a dbusmenu item is created
121 with a matching type as setup in #dbusmenu_client_add_type_handler
122*/
113typedef gboolean (*DbusmenuClientTypeHandler) (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data);123typedef gboolean (*DbusmenuClientTypeHandler) (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data);
124
125/**
126 DbusmenuClientTypeDestroyHandler:
127 @client: A pointer to the #DbusmenuClient
128 @type: The type that this handler was registered with
129 @user_data: The data you gave us
130
131 This handler is called when the type becomes unregistered by the
132 client. This is usally caused by the #DbusmenuClient being destroyed
133 and should free memory or unref objects in @user_data.
134*/
114typedef void (*DbusmenuClientTypeDestroyHandler) (DbusmenuClient * client, const gchar * type, gpointer user_data);135typedef void (*DbusmenuClientTypeDestroyHandler) (DbusmenuClient * client, const gchar * type, gpointer user_data);
115136
116GType dbusmenu_client_get_type (void);137GType dbusmenu_client_get_type (void);
117138
=== modified file 'libdbusmenu-gtk/Makefile.am'
--- libdbusmenu-gtk/Makefile.am 2011-01-27 15:48:01 +0000
+++ libdbusmenu-gtk/Makefile.am 2011-01-27 15:48:01 +0000
@@ -24,6 +24,7 @@
24 client.h \24 client.h \
25 menu.h \25 menu.h \
26 menuitem.h \26 menuitem.h \
27 parser.h \
27 serializablemenuitem.h28 serializablemenuitem.h
2829
29libdbusmenu_gtk_la_SOURCES = \30libdbusmenu_gtk_la_SOURCES = \
@@ -35,6 +36,8 @@
35 menu.c \36 menu.c \
36 menuitem.h \37 menuitem.h \
37 menuitem.c \38 menuitem.c \
39 parser.h \
40 parser.c \
38 serializablemenuitem.h \41 serializablemenuitem.h \
39 serializablemenuitem.c42 serializablemenuitem.c
4043
4144
=== added file 'libdbusmenu-gtk/parser.c'
--- libdbusmenu-gtk/parser.c 1970-01-01 00:00:00 +0000
+++ libdbusmenu-gtk/parser.c 2011-01-27 15:48:01 +0000
@@ -0,0 +1,698 @@
1/*
2Parse to take a set of GTK Menus and turn them into something that can
3be sent over the wire.
4
5Copyright 2011 Canonical Ltd.
6
7Authors:
8 Numerous (check Bazaar)
9
10This program is free software: you can redistribute it and/or modify it
11under the terms of either or both of the following licenses:
12
131) the GNU Lesser General Public License version 3, as published by the
14Free Software Foundation; and/or
152) the GNU Lesser General Public License version 2.1, as published by
16the Free Software Foundation.
17
18This program is distributed in the hope that it will be useful, but
19WITHOUT ANY WARRANTY; without even the implied warranties of
20MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
21PURPOSE. See the applicable version of the GNU Lesser General Public
22License for more details.
23
24You should have received a copy of both the GNU Lesser General Public
25License version 3 and version 2.1 along with this program. If not, see
26<http://www.gnu.org/licenses/>
27*/
28
29#include "parser.h"
30#include "menuitem.h"
31#include "serializablemenuitem.h"
32
33#define CACHED_MENUITEM "dbusmenu-gtk-parser-cached-item"
34
35typedef struct _RecurseContext
36{
37 GtkWidget * toplevel;
38 gint count;
39 DbusmenuMenuitem *stack[30];
40} RecurseContext;
41
42static void parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse);
43static DbusmenuMenuitem * construct_dbusmenu_for_widget (GtkWidget * widget);
44static void accel_changed (GtkWidget * widget,
45 gpointer data);
46static gboolean update_stock_item (DbusmenuMenuitem * menuitem,
47 GtkWidget * widget);
48static void checkbox_toggled (GtkWidget * widget,
49 DbusmenuMenuitem * mi);
50static void update_icon_name (DbusmenuMenuitem * menuitem,
51 GtkWidget * widget);
52static GtkWidget * find_menu_label (GtkWidget * widget);
53static void label_notify_cb (GtkWidget * widget,
54 GParamSpec * pspec,
55 gpointer data);
56static void action_notify_cb (GtkAction * action,
57 GParamSpec * pspec,
58 gpointer data);
59static void item_activated (DbusmenuMenuitem * item,
60 guint timestamp,
61 gpointer user_data);
62static gboolean item_about_to_show (DbusmenuMenuitem * item,
63 gpointer user_data);
64static void widget_notify_cb (GtkWidget * widget,
65 GParamSpec * pspec,
66 gpointer data);
67static gboolean should_show_image (GtkImage * image);
68static void menuitem_notify_cb (GtkWidget * widget,
69 GParamSpec * pspec,
70 gpointer data);
71
72DbusmenuMenuitem *
73dbusmenu_gtk_parse_menu_structure (GtkWidget * widget)
74{
75 RecurseContext recurse = {0};
76
77 recurse.count = -1;
78 recurse.toplevel = gtk_widget_get_toplevel(widget);
79
80 parse_menu_structure_helper(widget, &recurse);
81
82 if (recurse.stack[0] != NULL && DBUSMENU_IS_MENUITEM(recurse.stack[0])) {
83 return recurse.stack[0];
84 }
85
86 return NULL;
87}
88
89static void
90dbusmenu_cache_freed (gpointer data, GObject * obj)
91{
92 /* If the dbusmenu item is killed we don't need to remove
93 the weak ref as well. */
94 g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM);
95 return;
96}
97
98static void
99object_cache_freed (gpointer data)
100{
101 g_object_weak_unref(G_OBJECT(data), dbusmenu_cache_freed, data);
102 return;
103}
104
105static void
106parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse)
107{
108 if (GTK_IS_CONTAINER (widget))
109 {
110 gboolean increment = GTK_IS_MENU_SHELL (widget) || GTK_IS_MENU_ITEM (widget);
111
112 if (increment)
113 recurse->count++;
114
115 /* Okay, this is a little janky and all.. but some applications update some
116 * menuitem properties such as sensitivity on the activate callback. This
117 * seems a little weird, but it's not our place to judge when all this code
118 * is so crazy. So we're going to get ever crazier and activate all the
119 * menus that are directly below the menubar and force the applications to
120 * update their sensitivity. The menus won't actually popup in the app
121 * window due to our gtk+ patches.
122 *
123 * Note that this will not force menuitems in submenus to be updated as well.
124 */
125 if (recurse->count == 0 && GTK_IS_MENU_BAR (widget))
126 {
127 GList *children = gtk_container_get_children (GTK_CONTAINER (widget));
128
129 for (; children != NULL; children = children->next)
130 {
131 gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget),
132 children->data,
133 TRUE);
134 }
135
136 g_list_free (children);
137 }
138
139 if (recurse->count > -1 && increment)
140 {
141 gpointer pmi = g_object_get_data(G_OBJECT(widget), CACHED_MENUITEM);
142 DbusmenuMenuitem *dmi = NULL;
143 if (pmi != NULL) dmi = DBUSMENU_MENUITEM(pmi);
144
145 if (dmi != NULL)
146 {
147 if (increment)
148 recurse->count--;
149
150 return;
151 }
152 else
153 {
154 recurse->stack[recurse->count] = construct_dbusmenu_for_widget (widget);
155 g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, recurse->stack[recurse->count], object_cache_freed);
156 g_object_weak_ref(G_OBJECT(recurse->stack[recurse->count]), dbusmenu_cache_freed, widget);
157 }
158
159 if (!gtk_widget_get_visible (widget))
160 {
161 g_signal_connect (G_OBJECT (widget),
162 "notify::visible",
163 G_CALLBACK (menuitem_notify_cb),
164 recurse->toplevel);
165 }
166
167 if (GTK_IS_TEAROFF_MENU_ITEM (widget))
168 {
169 dbusmenu_menuitem_property_set_bool (recurse->stack[recurse->count],
170 DBUSMENU_MENUITEM_PROP_VISIBLE,
171 FALSE);
172 }
173
174 if (recurse->count > 0)
175 {
176 GList *children = NULL;
177 GList *peek = NULL;
178
179 if (recurse->stack[recurse->count - 1])
180 {
181 children = dbusmenu_menuitem_get_children (recurse->stack[recurse->count - 1]);
182
183 if (children)
184 {
185 peek = g_list_find (children, recurse->stack[recurse->count]);
186 }
187
188 if (!peek)
189 {
190 /* Should we set a weak ref on the parent? */
191 g_object_set_data (G_OBJECT (recurse->stack[recurse->count]),
192 "dbusmenu-parent",
193 recurse->stack[recurse->count - 1]);
194 dbusmenu_menuitem_child_append (recurse->stack[recurse->count - 1],
195 recurse->stack[recurse->count]);
196 }
197 }
198 else
199 {
200 DbusmenuMenuitem *item = NULL; /* g_hash_table_lookup (recurse->context->lookup,
201 gtk_widget_get_parent (widget)); */
202
203 if (item)
204 {
205 children = dbusmenu_menuitem_get_children (item);
206
207 if (children)
208 {
209 peek = g_list_find (children, recurse->stack[recurse->count]);
210 }
211
212 if (!peek)
213 {
214 g_object_set_data (G_OBJECT (recurse->stack[recurse->count]),
215 "dbusmenu-parent",
216 recurse->stack[recurse->count - 1]);
217
218 dbusmenu_menuitem_child_append (item, recurse->stack[recurse->count]);
219 }
220 }
221 }
222 }
223 }
224
225 gtk_container_foreach (GTK_CONTAINER (widget),
226 (GtkCallback)parse_menu_structure_helper,
227 recurse);
228
229 if (GTK_IS_MENU_ITEM (widget))
230 {
231 GtkWidget *menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
232
233 if (menu != NULL)
234 {
235 parse_menu_structure_helper (menu, recurse);
236 }
237 }
238
239 if (increment)
240 recurse->count--;
241 }
242}
243
244/* Turn a widget into a dbusmenu item depending on the type of GTK
245 object that it is. */
246static DbusmenuMenuitem *
247construct_dbusmenu_for_widget (GtkWidget * widget)
248{
249 /* If it's a subclass of our serializable menu item then we can
250 use its own build function */
251 if (DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(widget)) {
252 DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(widget);
253 return dbusmenu_gtk_serializable_menu_item_build_menuitem(smi);
254 }
255
256 /* If it's a standard GTK Menu Item we need to do some of our own work */
257 if (GTK_IS_MENU_ITEM (widget))
258 {
259 DbusmenuMenuitem *mi = dbusmenu_menuitem_new ();
260
261 gboolean visible = FALSE;
262 gboolean sensitive = FALSE;
263 if (GTK_IS_SEPARATOR_MENU_ITEM (widget))
264 {
265 dbusmenu_menuitem_property_set (mi,
266 "type",
267 "separator");
268
269 visible = gtk_widget_get_visible (widget);
270 sensitive = gtk_widget_get_sensitive (widget);
271 }
272 else
273 {
274 gboolean label_set = FALSE;
275
276 g_signal_connect (widget,
277 "accel-closures-changed",
278 G_CALLBACK (accel_changed),
279 mi);
280
281 if (GTK_IS_CHECK_MENU_ITEM (widget))
282 {
283 dbusmenu_menuitem_property_set (mi,
284 DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,
285 gtk_check_menu_item_get_draw_as_radio (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_RADIO : DBUSMENU_MENUITEM_TOGGLE_CHECK);
286
287 dbusmenu_menuitem_property_set_int (mi,
288 DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
289 gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
290
291 g_signal_connect (widget,
292 "activate",
293 G_CALLBACK (checkbox_toggled),
294 mi);
295 }
296
297 if (GTK_IS_IMAGE_MENU_ITEM (widget))
298 {
299 GtkWidget *image;
300 GtkImageType image_type;
301
302 image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (widget));
303
304 if (GTK_IS_IMAGE (image))
305 {
306 image_type = gtk_image_get_storage_type (GTK_IMAGE (image));
307
308 if (image_type == GTK_IMAGE_STOCK)
309 {
310 label_set = update_stock_item (mi, image);
311 }
312 else if (image_type == GTK_IMAGE_ICON_NAME)
313 {
314 update_icon_name (mi, image);
315 }
316 else if (image_type == GTK_IMAGE_PIXBUF)
317 {
318 dbusmenu_menuitem_property_set_image (mi,
319 DBUSMENU_MENUITEM_PROP_ICON_DATA,
320 gtk_image_get_pixbuf (GTK_IMAGE (image)));
321 }
322 }
323 }
324
325 GtkWidget *label = find_menu_label (widget);
326
327 dbusmenu_menuitem_property_set (mi,
328 "label",
329 label ? gtk_label_get_text (GTK_LABEL (label)) : NULL);
330
331 if (label)
332 {
333 // Sometimes, an app will directly find and modify the label
334 // (like empathy), so watch the label especially for that.
335 g_signal_connect (G_OBJECT (label),
336 "notify",
337 G_CALLBACK (label_notify_cb),
338 mi);
339 }
340
341 if (GTK_IS_ACTIVATABLE (widget))
342 {
343 GtkActivatable *activatable = GTK_ACTIVATABLE (widget);
344
345 if (gtk_activatable_get_use_action_appearance (activatable))
346 {
347 GtkAction *action = gtk_activatable_get_related_action (activatable);
348
349 if (action)
350 {
351 visible = gtk_action_is_visible (action);
352 sensitive = gtk_action_is_sensitive (action);
353
354 g_signal_connect_object (action, "notify",
355 G_CALLBACK (action_notify_cb),
356 mi,
357 G_CONNECT_AFTER);
358 }
359 }
360 }
361
362 if (!g_object_get_data (G_OBJECT (widget), "gtk-empty-menu-item") && !GTK_IS_TEAROFF_MENU_ITEM (widget))
363 {
364 visible = gtk_widget_get_visible (widget);
365 sensitive = gtk_widget_get_sensitive (widget);
366 }
367
368 dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget));
369
370 g_signal_connect (G_OBJECT (mi),
371 DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
372 G_CALLBACK (item_activated),
373 widget);
374
375 g_signal_connect (G_OBJECT (mi),
376 DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW,
377 G_CALLBACK (item_about_to_show),
378 widget);
379 }
380
381 dbusmenu_menuitem_property_set_bool (mi,
382 DBUSMENU_MENUITEM_PROP_VISIBLE,
383 visible);
384
385 dbusmenu_menuitem_property_set_bool (mi,
386 DBUSMENU_MENUITEM_PROP_ENABLED,
387 sensitive);
388
389 g_signal_connect (widget,
390 "notify",
391 G_CALLBACK (widget_notify_cb),
392 mi);
393 return mi;
394 }
395
396 /* If it's none of those we're going to just create a
397 generic menuitem as a place holder for it. */
398 return dbusmenu_menuitem_new();
399}
400
401static void
402menuitem_notify_cb (GtkWidget *widget,
403 GParamSpec *pspec,
404 gpointer data)
405{
406 if (pspec->name == g_intern_static_string ("visible"))
407 {
408 GtkWidget * new_toplevel = gtk_widget_get_toplevel (widget);
409 GtkWidget * old_toplevel = GTK_WIDGET(data);
410
411 if (new_toplevel == old_toplevel) {
412 /* TODO: Figure this out -> rebuild (context->bridge, window); */
413 }
414
415 /* We only care about this once, so let's disconnect now. */
416 g_signal_handlers_disconnect_by_func (widget,
417 G_CALLBACK (menuitem_notify_cb),
418 data);
419 }
420}
421
422static void
423accel_changed (GtkWidget *widget,
424 gpointer data)
425{
426 DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data;
427 dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget));
428}
429
430static gboolean
431update_stock_item (DbusmenuMenuitem *menuitem,
432 GtkWidget *widget)
433{
434 GtkStockItem stock;
435 GtkImage *image;
436
437 g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
438
439 image = GTK_IMAGE (widget);
440
441 if (gtk_image_get_storage_type (image) != GTK_IMAGE_STOCK)
442 return FALSE;
443
444 gchar * stock_id = NULL;
445 gtk_image_get_stock(image, &stock_id, NULL);
446
447 gtk_stock_lookup (stock_id, &stock);
448
449 if (should_show_image (image))
450 dbusmenu_menuitem_property_set (menuitem,
451 DBUSMENU_MENUITEM_PROP_ICON_NAME,
452 stock_id);
453 else
454 dbusmenu_menuitem_property_remove (menuitem,
455 DBUSMENU_MENUITEM_PROP_ICON_NAME);
456
457 const gchar *label = dbusmenu_menuitem_property_get (menuitem,
458 DBUSMENU_MENUITEM_PROP_LABEL);
459
460 if (stock.label != NULL && label != NULL)
461 {
462 dbusmenu_menuitem_property_set (menuitem,
463 DBUSMENU_MENUITEM_PROP_LABEL,
464 stock.label);
465
466 return TRUE;
467 }
468
469 return FALSE;
470}
471
472static void
473checkbox_toggled (GtkWidget *widget, DbusmenuMenuitem *mi)
474{
475 dbusmenu_menuitem_property_set_int (mi,
476 DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
477 gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
478}
479
480static void
481update_icon_name (DbusmenuMenuitem *menuitem,
482 GtkWidget *widget)
483{
484 GtkImage *image;
485
486 g_return_if_fail (GTK_IS_IMAGE (widget));
487
488 image = GTK_IMAGE (widget);
489
490 if (gtk_image_get_storage_type (image) != GTK_IMAGE_ICON_NAME)
491 return;
492
493 if (should_show_image (image)) {
494 const gchar * icon_name = NULL;
495 gtk_image_get_icon_name(image, &icon_name, NULL);
496 dbusmenu_menuitem_property_set (menuitem,
497 DBUSMENU_MENUITEM_PROP_ICON_NAME,
498 icon_name);
499 } else {
500 dbusmenu_menuitem_property_remove (menuitem,
501 DBUSMENU_MENUITEM_PROP_ICON_NAME);
502 }
503}
504
505static GtkWidget *
506find_menu_label (GtkWidget *widget)
507{
508 GtkWidget *label = NULL;
509
510 if (GTK_IS_LABEL (widget))
511 return widget;
512
513 if (GTK_IS_CONTAINER (widget))
514 {
515 GList *children;
516 GList *l;
517
518 children = gtk_container_get_children (GTK_CONTAINER (widget));
519
520 for (l = children; l; l = l->next)
521 {
522 label = find_menu_label (l->data);
523
524 if (label)
525 break;
526 }
527
528 g_list_free (children);
529 }
530
531 return label;
532}
533
534static void
535label_notify_cb (GtkWidget *widget,
536 GParamSpec *pspec,
537 gpointer data)
538{
539 DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
540
541 if (pspec->name == g_intern_static_string ("label"))
542 {
543 dbusmenu_menuitem_property_set (child,
544 DBUSMENU_MENUITEM_PROP_LABEL,
545 gtk_label_get_text (GTK_LABEL (widget)));
546 }
547}
548
549static void
550action_notify_cb (GtkAction *action,
551 GParamSpec *pspec,
552 gpointer data)
553{
554 DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data;
555
556 if (pspec->name == g_intern_static_string ("sensitive"))
557 {
558 dbusmenu_menuitem_property_set_bool (mi,
559 DBUSMENU_MENUITEM_PROP_ENABLED,
560 gtk_action_is_sensitive (action));
561 }
562 else if (pspec->name == g_intern_static_string ("visible"))
563 {
564 dbusmenu_menuitem_property_set_bool (mi,
565 DBUSMENU_MENUITEM_PROP_VISIBLE,
566 gtk_action_is_visible (action));
567 }
568 else if (pspec->name == g_intern_static_string ("active"))
569 {
570 dbusmenu_menuitem_property_set_bool (mi,
571 DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
572 gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
573 }
574 else if (pspec->name == g_intern_static_string ("label"))
575 {
576 dbusmenu_menuitem_property_set (mi,
577 DBUSMENU_MENUITEM_PROP_LABEL,
578 gtk_action_get_label (action));
579 }
580}
581
582static void
583item_activated (DbusmenuMenuitem *item, guint timestamp, gpointer user_data)
584{
585 GtkWidget *child;
586
587 if (user_data != NULL)
588 {
589 child = (GtkWidget *)user_data;
590
591 if (GTK_IS_MENU_ITEM (child))
592 {
593 gtk_menu_item_activate (GTK_MENU_ITEM (child));
594 }
595 }
596}
597
598static gboolean
599item_about_to_show (DbusmenuMenuitem *item, gpointer user_data)
600{
601 GtkWidget *child;
602
603 if (user_data != NULL)
604 {
605 child = (GtkWidget *)user_data;
606
607 if (GTK_IS_MENU_ITEM (child))
608 {
609 // Only called for items with submens. So we activate it here in
610 // case the program dynamically creates menus (like empathy does)
611 gtk_menu_item_activate (GTK_MENU_ITEM (child));
612 }
613 }
614
615 return TRUE;
616}
617
618static void
619widget_notify_cb (GtkWidget *widget,
620 GParamSpec *pspec,
621 gpointer data)
622{
623 DbusmenuMenuitem *child = (DbusmenuMenuitem *)data;
624
625 if (pspec->name == g_intern_static_string ("sensitive"))
626 {
627 dbusmenu_menuitem_property_set_bool (child,
628 DBUSMENU_MENUITEM_PROP_ENABLED,
629 gtk_widget_get_sensitive (widget));
630 }
631 else if (pspec->name == g_intern_static_string ("label"))
632 {
633 dbusmenu_menuitem_property_set (child,
634 DBUSMENU_MENUITEM_PROP_LABEL,
635 gtk_menu_item_get_label (GTK_MENU_ITEM (widget)));
636 }
637 else if (pspec->name == g_intern_static_string ("visible"))
638 {
639 dbusmenu_menuitem_property_set_bool (child,
640 DBUSMENU_MENUITEM_PROP_VISIBLE,
641 gtk_widget_get_visible (widget));
642 }
643 else if (pspec->name == g_intern_static_string ("stock"))
644 {
645 update_stock_item (child, widget);
646 }
647 else if (pspec->name == g_intern_static_string ("icon-name"))
648 {
649 update_icon_name (child, widget);
650 }
651 else if (pspec->name == g_intern_static_string ("parent"))
652 {
653 /*
654 * We probably should have added a 'remove' method to the
655 * UbuntuMenuProxy early on, but it's late in the cycle now.
656 */
657 if (gtk_widget_get_parent (widget) == NULL)
658 {
659 g_signal_handlers_disconnect_by_func (widget,
660 G_CALLBACK (widget_notify_cb),
661 child);
662
663 DbusmenuMenuitem *parent = g_object_get_data (G_OBJECT (child), "dbusmenu-parent");
664
665 if (DBUSMENU_IS_MENUITEM (parent) && DBUSMENU_IS_MENUITEM (child))
666 {
667 dbusmenu_menuitem_child_delete (parent, child);
668 }
669 }
670 }
671}
672
673static gboolean
674should_show_image (GtkImage *image)
675{
676 GtkWidget *item;
677
678 item = gtk_widget_get_ancestor (GTK_WIDGET (image),
679 GTK_TYPE_IMAGE_MENU_ITEM);
680
681 if (item)
682 {
683 GtkSettings *settings;
684 gboolean gtk_menu_images;
685
686 settings = gtk_widget_get_settings (item);
687
688 g_object_get (settings, "gtk-menu-images", &gtk_menu_images, NULL);
689
690 if (gtk_menu_images)
691 return TRUE;
692
693 return gtk_image_menu_item_get_always_show_image (GTK_IMAGE_MENU_ITEM (item));
694 }
695
696 return FALSE;
697}
698
0699
=== added file 'libdbusmenu-gtk/parser.h'
--- libdbusmenu-gtk/parser.h 1970-01-01 00:00:00 +0000
+++ libdbusmenu-gtk/parser.h 2011-01-27 15:48:01 +0000
@@ -0,0 +1,37 @@
1/*
2Parse to take a set of GTK Menus and turn them into something that can
3be sent over the wire.
4
5Copyright 2011 Canonical Ltd.
6
7Authors:
8 Ted Gould <ted@canonical.com>
9
10This program is free software: you can redistribute it and/or modify it
11under the terms of either or both of the following licenses:
12
131) the GNU Lesser General Public License version 3, as published by the
14Free Software Foundation; and/or
152) the GNU Lesser General Public License version 2.1, as published by
16the Free Software Foundation.
17
18This program is distributed in the hope that it will be useful, but
19WITHOUT ANY WARRANTY; without even the implied warranties of
20MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
21PURPOSE. See the applicable version of the GNU Lesser General Public
22License for more details.
23
24You should have received a copy of both the GNU Lesser General Public
25License version 3 and version 2.1 along with this program. If not, see
26<http://www.gnu.org/licenses/>
27*/
28
29#ifndef DBUSMENU_GTK_PARSER_H__
30#define DBUSMENU_GTK_PARSER_H__
31
32#include <libdbusmenu-glib/menuitem.h>
33#include <gtk/gtk.h>
34
35DbusmenuMenuitem * dbusmenu_gtk_parse_menu_structure (GtkWidget * widget);
36
37#endif /* DBUSMENU_GTK_PARSER_H__ */
038
=== modified file 'libdbusmenu-gtk/serializablemenuitem.c'
--- libdbusmenu-gtk/serializablemenuitem.c 2011-01-27 15:48:01 +0000
+++ libdbusmenu-gtk/serializablemenuitem.c 2011-01-27 15:48:01 +0000
@@ -166,7 +166,7 @@
166}166}
167167
168/**168/**
169 dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem:169 dbusmenu_gtk_serializable_menu_item_build_menuitem:
170 @smi: #DbusmenuGtkSerializableMenuItem to build a #DbusmenuMenuitem mirroring170 @smi: #DbusmenuGtkSerializableMenuItem to build a #DbusmenuMenuitem mirroring
171171
172 This function is for menu items that are instanciated from172 This function is for menu items that are instanciated from
@@ -179,7 +179,7 @@
179 set by this object.179 set by this object.
180*/180*/
181DbusmenuMenuitem *181DbusmenuMenuitem *
182dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi)182dbusmenu_gtk_serializable_menu_item_build_menuitem (DbusmenuGtkSerializableMenuItem * smi)
183{183{
184 g_return_val_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi), NULL);184 g_return_val_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi), NULL);
185185
@@ -207,7 +207,7 @@
207 DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(g_object_new(th->type, NULL));207 DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(g_object_new(th->type, NULL));
208 g_return_val_if_fail(smi != NULL, FALSE);208 g_return_val_if_fail(smi != NULL, FALSE);
209209
210 dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem(smi, newitem);210 dbusmenu_gtk_serializable_menu_item_set_menuitem(smi, newitem);
211 dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(smi), parent);211 dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(smi), parent);
212212
213 return TRUE;213 return TRUE;
@@ -265,7 +265,7 @@
265}265}
266266
267/**267/**
268 dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem:268 dbusmenu_gtk_serializable_menu_item_set_menuitem:
269 @smi: #DbusmenuGtkSerializableMenuItem to set the @DbusmenuGtkSerializableMenuItem::dbusmenu-menuitem of269 @smi: #DbusmenuGtkSerializableMenuItem to set the @DbusmenuGtkSerializableMenuItem::dbusmenu-menuitem of
270 @mi: Menuitem to get the properties from270 @mi: Menuitem to get the properties from
271271
@@ -276,7 +276,7 @@
276 pick up this property being set.276 pick up this property being set.
277*/277*/
278void278void
279dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi)279dbusmenu_gtk_serializable_menu_item_set_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi)
280{280{
281 g_return_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi));281 g_return_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi));
282 g_return_if_fail(mi != NULL);282 g_return_if_fail(mi != NULL);
283283
=== modified file 'libdbusmenu-gtk/serializablemenuitem.h'
--- libdbusmenu-gtk/serializablemenuitem.h 2011-01-27 15:48:01 +0000
+++ libdbusmenu-gtk/serializablemenuitem.h 2011-01-27 15:48:01 +0000
@@ -90,6 +90,13 @@
90 DbusmenuGtkSerializableMenuItem:90 DbusmenuGtkSerializableMenuItem:
91 @parent: Inherit from GtkMenuItem91 @parent: Inherit from GtkMenuItem
92 @priv: Blind structure of private variables92 @priv: Blind structure of private variables
93
94 The Serializable Menuitem provides a way for menu items to be created
95 that can easily be picked up by the Dbusmenu GTK Parser. This way
96 you can create custom items, and transport them across dbusmenu to
97 your menus or the appmenu on the other side of the bus. By providing
98 these function the parser has enough information to both serialize, and
99 deserialize on the other side, the menuitem you've so carefully created.
93*/100*/
94struct _DbusmenuGtkSerializableMenuItem {101struct _DbusmenuGtkSerializableMenuItem {
95 GtkMenuItem parent;102 GtkMenuItem parent;
@@ -99,9 +106,9 @@
99106
100GType dbusmenu_gtk_serializable_menu_item_get_type (void);107GType dbusmenu_gtk_serializable_menu_item_get_type (void);
101108
102DbusmenuMenuitem * dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi);109DbusmenuMenuitem * dbusmenu_gtk_serializable_menu_item_build_menuitem (DbusmenuGtkSerializableMenuItem * smi);
103void dbusmenu_gtk_serializable_menu_item_register_to_client (DbusmenuClient * client, GType item_type);110void dbusmenu_gtk_serializable_menu_item_register_to_client (DbusmenuClient * client, GType item_type);
104void dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi);111void dbusmenu_gtk_serializable_menu_item_set_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi);
105112
106G_END_DECLS113G_END_DECLS
107114
108115
=== modified file 'tests/Makefile.am'
--- tests/Makefile.am 2010-12-08 03:17:43 +0000
+++ tests/Makefile.am 2011-01-27 15:48:01 +0000
@@ -16,7 +16,8 @@
16 test-gtk-label \16 test-gtk-label \
17 test-gtk-shortcut \17 test-gtk-shortcut \
18 test-gtk-reorder \18 test-gtk-reorder \
19 test-gtk-submenu19 test-gtk-submenu \
20 test-gtk-parser-test
2021
21check_PROGRAMS = \22check_PROGRAMS = \
22 glib-server-nomenu \23 glib-server-nomenu \
@@ -42,7 +43,8 @@
42 test-json-client \43 test-json-client \
43 test-json-server \44 test-json-server \
44 test-gtk-submenu-server \45 test-gtk-submenu-server \
45 test-gtk-submenu-client46 test-gtk-submenu-client \
47 test-gtk-parser
4648
47XVFB_RUN=". $(srcdir)/run-xvfb.sh"49XVFB_RUN=". $(srcdir)/run-xvfb.sh"
4850
@@ -384,6 +386,35 @@
384 $(DBUSMENUGLIB_LIBS) \386 $(DBUSMENUGLIB_LIBS) \
385 $(DBUSMENUGTK_LIBS)387 $(DBUSMENUGTK_LIBS)
386388
389######################
390# Test GTK Parser
391######################
392
393GTK_PARSER_XML_REPORT = test-gtk-parser.xml
394
395test-gtk-parser-test: test-gtk-parser Makefile.am
396 @echo "#!/bin/bash" > $@
397 @echo $(XVFB_RUN) >> $@
398 @echo gtester --verbose -k -o $(GTK_PARSER_XML_REPORT) ./test-gtk-parser >> $@
399 @chmod +x $@
400
401test_gtk_parser_SOURCES = \
402 test-gtk-parser.c
403
404test_gtk_parser_CFLAGS = \
405 -I $(srcdir)/.. \
406 $(DBUSMENUGLIB_CFLAGS) \
407 $(DBUSMENUGTK_CFLAGS) \
408 -DSRCDIR="\"$(srcdir)\"" \
409 -Wall -Werror
410
411test_gtk_parser_LDADD = \
412 ../libdbusmenu-glib/libdbusmenu-glib.la \
413 ../libdbusmenu-gtk/libdbusmenu-gtk.la \
414 $(DBUSMENUGLIB_LIBS) \
415 $(DBUSMENUGTK_LIBS)
416
417
387#########################418#########################
388# Test GTK Label419# Test GTK Label
389#########################420#########################
390421
=== added file 'tests/test-gtk-parser.c'
--- tests/test-gtk-parser.c 1970-01-01 00:00:00 +0000
+++ tests/test-gtk-parser.c 2011-01-27 15:48:01 +0000
@@ -0,0 +1,115 @@
1/*
2Testing for the various objects just by themselves.
3
4Copyright 2011 Canonical Ltd.
5
6Authors:
7 Ted Gould <ted@canonical.com>
8
9This program is free software: you can redistribute it and/or modify it
10under the terms of the GNU General Public License version 3, as published
11by the Free Software Foundation.
12
13This program is distributed in the hope that it will be useful, but
14WITHOUT ANY WARRANTY; without even the implied warranties of
15MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
16PURPOSE. See the GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License along
19with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include <libdbusmenu-glib/menuitem-private.h>
23#include <libdbusmenu-gtk/parser.h>
24
25/* Just makes sure we can connect here people */
26static void
27test_parser_runs (void)
28{
29 GtkWidget * gmi = gtk_menu_item_new_with_label("Test Item");
30 g_assert(gmi != NULL);
31 DbusmenuMenuitem * mi = dbusmenu_gtk_parse_menu_structure(gmi);
32 g_assert(mi != NULL);
33
34 g_object_unref(gmi);
35 g_object_unref(mi);
36
37 return;
38}
39
40const gchar * test_parser_children_builder =
41"<?xml version=\"1.0\"?>"
42"<interface>"
43"<requires lib=\"gtk+\" version=\"2.16\"/>"
44/* Start menu bar */
45"<object class=\"GtkMenuBar\" id=\"menubar\"><property name=\"visible\">True</property>"
46/* Child 1 */
47"<child><object class=\"GtkMenuItem\" id=\"child_one\"><property name=\"visible\">True</property><property name=\"label\">Child One</property></object></child>"
48/* Child 2 */
49"<child><object class=\"GtkMenuItem\" id=\"child_two\"><property name=\"visible\">True</property><property name=\"label\">Child Two</property></object></child>"
50/* Child 3 */
51"<child><object class=\"GtkMenuItem\" id=\"child_three\"><property name=\"visible\">True</property><property name=\"label\">Child Three</property></object></child>"
52/* Child 4 */
53"<child><object class=\"GtkMenuItem\" id=\"child_four\"><property name=\"visible\">True</property><property name=\"label\">Child Four</property></object></child>"
54/* Stop menubar */
55"</object>"
56"</interface>";
57
58/* Ensure the parser can find children */
59static void
60test_parser_children (void) {
61 GtkBuilder * builder = gtk_builder_new();
62 g_assert(builder != NULL);
63
64 GError * error = NULL;
65 gtk_builder_add_from_string(builder, test_parser_children_builder, -1, &error);
66 if (error != NULL) {
67 g_error("Unable to parse UI definition: %s", error->message);
68 g_error_free(error);
69 error = NULL;
70 }
71
72 GtkWidget * menu = GTK_WIDGET(gtk_builder_get_object(builder, "menubar"));
73 g_assert(menu != NULL);
74
75 DbusmenuMenuitem * mi = dbusmenu_gtk_parse_menu_structure(menu);
76 g_assert(mi != NULL);
77
78/*
79 GPtrArray * xmlarray = g_ptr_array_new();
80 dbusmenu_menuitem_buildxml(mi, xmlarray);
81 g_debug("XML: %s", g_strjoinv("", (gchar **)xmlarray->pdata));
82*/
83
84 GList * children = dbusmenu_menuitem_get_children(mi);
85 g_assert(children != NULL);
86
87 g_assert(g_list_length(children) == 4);
88
89 g_object_unref(mi);
90 g_object_unref(menu);
91
92 return;
93}
94
95/* Build the test suite */
96static void
97test_gtk_parser_suite (void)
98{
99 g_test_add_func ("/dbusmenu/gtk/parser/base", test_parser_runs);
100 g_test_add_func ("/dbusmenu/gtk/parser/children", test_parser_children);
101 return;
102}
103
104gint
105main (gint argc, gchar * argv[])
106{
107 gtk_init(&argc, &argv);
108 g_test_init(&argc, &argv, NULL);
109
110 /* Test suites */
111 test_gtk_parser_suite();
112
113
114 return g_test_run ();
115}

Subscribers

People subscribed via source and target branches