Merge lp:~ted/libdbusmenu/parse-serializable-menuitem into lp:libdbusmenu/0.5
- parse-serializable-menuitem
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mikkel Kamstrup Erlandsen | Pending | ||
Review via email:
|
This proposal supersedes a proposal from 2011-01-26.
This proposal has been superseded by a proposal from 2011-01-27.
Commit message
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-
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Mikkel Kamstrup Erlandsen (kamstrup) wrote : Posted in a previous version of this proposal | # |
review:
Needs Information
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2011-01-27 15:48:01 +0000 |
3 | +++ .bzrignore 2011-01-27 15:48:01 +0000 |
4 | @@ -223,3 +223,7 @@ |
5 | libdbusmenu-gtk/libdbusmenu_gtk_la-serializablemenuitem.lo |
6 | docs/libdbusmenu-gtk/reference/html/DbusmenuGtkSerializableMenuItem.html |
7 | docs/libdbusmenu-gtk/reference/tmpl/serializablemenuitem.sgml |
8 | +libdbusmenu-gtk/libdbusmenu_gtk_la-parser.lo |
9 | +test-gtk-parser |
10 | +test-gtk-parser-test |
11 | +test-gtk-parser.xml |
12 | |
13 | === modified file 'libdbusmenu-glib/client.h' |
14 | --- libdbusmenu-glib/client.h 2011-01-27 15:48:01 +0000 |
15 | +++ libdbusmenu-glib/client.h 2011-01-27 15:48:01 +0000 |
16 | @@ -110,7 +110,28 @@ |
17 | DbusmenuClientPrivate * priv; |
18 | }; |
19 | |
20 | +/** |
21 | + DbusmenuClientTypeHandler: |
22 | + @newitem: The #DbusmenuMenuitem that was created |
23 | + @parent: The parent of @newitem or #NULL if none |
24 | + @client: A pointer to the #DbusmenuClient |
25 | + @user_data: The data you gave us |
26 | + |
27 | + The type handler is called when a dbusmenu item is created |
28 | + with a matching type as setup in #dbusmenu_client_add_type_handler |
29 | +*/ |
30 | typedef gboolean (*DbusmenuClientTypeHandler) (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data); |
31 | + |
32 | +/** |
33 | + DbusmenuClientTypeDestroyHandler: |
34 | + @client: A pointer to the #DbusmenuClient |
35 | + @type: The type that this handler was registered with |
36 | + @user_data: The data you gave us |
37 | + |
38 | + This handler is called when the type becomes unregistered by the |
39 | + client. This is usally caused by the #DbusmenuClient being destroyed |
40 | + and should free memory or unref objects in @user_data. |
41 | +*/ |
42 | typedef void (*DbusmenuClientTypeDestroyHandler) (DbusmenuClient * client, const gchar * type, gpointer user_data); |
43 | |
44 | GType dbusmenu_client_get_type (void); |
45 | |
46 | === modified file 'libdbusmenu-gtk/Makefile.am' |
47 | --- libdbusmenu-gtk/Makefile.am 2011-01-27 15:48:01 +0000 |
48 | +++ libdbusmenu-gtk/Makefile.am 2011-01-27 15:48:01 +0000 |
49 | @@ -24,6 +24,7 @@ |
50 | client.h \ |
51 | menu.h \ |
52 | menuitem.h \ |
53 | + parser.h \ |
54 | serializablemenuitem.h |
55 | |
56 | libdbusmenu_gtk_la_SOURCES = \ |
57 | @@ -35,6 +36,8 @@ |
58 | menu.c \ |
59 | menuitem.h \ |
60 | menuitem.c \ |
61 | + parser.h \ |
62 | + parser.c \ |
63 | serializablemenuitem.h \ |
64 | serializablemenuitem.c |
65 | |
66 | |
67 | === added file 'libdbusmenu-gtk/parser.c' |
68 | --- libdbusmenu-gtk/parser.c 1970-01-01 00:00:00 +0000 |
69 | +++ libdbusmenu-gtk/parser.c 2011-01-27 15:48:01 +0000 |
70 | @@ -0,0 +1,698 @@ |
71 | +/* |
72 | +Parse to take a set of GTK Menus and turn them into something that can |
73 | +be sent over the wire. |
74 | + |
75 | +Copyright 2011 Canonical Ltd. |
76 | + |
77 | +Authors: |
78 | + Numerous (check Bazaar) |
79 | + |
80 | +This program is free software: you can redistribute it and/or modify it |
81 | +under the terms of either or both of the following licenses: |
82 | + |
83 | +1) the GNU Lesser General Public License version 3, as published by the |
84 | +Free Software Foundation; and/or |
85 | +2) the GNU Lesser General Public License version 2.1, as published by |
86 | +the Free Software Foundation. |
87 | + |
88 | +This program is distributed in the hope that it will be useful, but |
89 | +WITHOUT ANY WARRANTY; without even the implied warranties of |
90 | +MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR |
91 | +PURPOSE. See the applicable version of the GNU Lesser General Public |
92 | +License for more details. |
93 | + |
94 | +You should have received a copy of both the GNU Lesser General Public |
95 | +License version 3 and version 2.1 along with this program. If not, see |
96 | +<http://www.gnu.org/licenses/> |
97 | +*/ |
98 | + |
99 | +#include "parser.h" |
100 | +#include "menuitem.h" |
101 | +#include "serializablemenuitem.h" |
102 | + |
103 | +#define CACHED_MENUITEM "dbusmenu-gtk-parser-cached-item" |
104 | + |
105 | +typedef struct _RecurseContext |
106 | +{ |
107 | + GtkWidget * toplevel; |
108 | + gint count; |
109 | + DbusmenuMenuitem *stack[30]; |
110 | +} RecurseContext; |
111 | + |
112 | +static void parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse); |
113 | +static DbusmenuMenuitem * construct_dbusmenu_for_widget (GtkWidget * widget); |
114 | +static void accel_changed (GtkWidget * widget, |
115 | + gpointer data); |
116 | +static gboolean update_stock_item (DbusmenuMenuitem * menuitem, |
117 | + GtkWidget * widget); |
118 | +static void checkbox_toggled (GtkWidget * widget, |
119 | + DbusmenuMenuitem * mi); |
120 | +static void update_icon_name (DbusmenuMenuitem * menuitem, |
121 | + GtkWidget * widget); |
122 | +static GtkWidget * find_menu_label (GtkWidget * widget); |
123 | +static void label_notify_cb (GtkWidget * widget, |
124 | + GParamSpec * pspec, |
125 | + gpointer data); |
126 | +static void action_notify_cb (GtkAction * action, |
127 | + GParamSpec * pspec, |
128 | + gpointer data); |
129 | +static void item_activated (DbusmenuMenuitem * item, |
130 | + guint timestamp, |
131 | + gpointer user_data); |
132 | +static gboolean item_about_to_show (DbusmenuMenuitem * item, |
133 | + gpointer user_data); |
134 | +static void widget_notify_cb (GtkWidget * widget, |
135 | + GParamSpec * pspec, |
136 | + gpointer data); |
137 | +static gboolean should_show_image (GtkImage * image); |
138 | +static void menuitem_notify_cb (GtkWidget * widget, |
139 | + GParamSpec * pspec, |
140 | + gpointer data); |
141 | + |
142 | +DbusmenuMenuitem * |
143 | +dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) |
144 | +{ |
145 | + RecurseContext recurse = {0}; |
146 | + |
147 | + recurse.count = -1; |
148 | + recurse.toplevel = gtk_widget_get_toplevel(widget); |
149 | + |
150 | + parse_menu_structure_helper(widget, &recurse); |
151 | + |
152 | + if (recurse.stack[0] != NULL && DBUSMENU_IS_MENUITEM(recurse.stack[0])) { |
153 | + return recurse.stack[0]; |
154 | + } |
155 | + |
156 | + return NULL; |
157 | +} |
158 | + |
159 | +static void |
160 | +dbusmenu_cache_freed (gpointer data, GObject * obj) |
161 | +{ |
162 | + /* If the dbusmenu item is killed we don't need to remove |
163 | + the weak ref as well. */ |
164 | + g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM); |
165 | + return; |
166 | +} |
167 | + |
168 | +static void |
169 | +object_cache_freed (gpointer data) |
170 | +{ |
171 | + g_object_weak_unref(G_OBJECT(data), dbusmenu_cache_freed, data); |
172 | + return; |
173 | +} |
174 | + |
175 | +static void |
176 | +parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) |
177 | +{ |
178 | + if (GTK_IS_CONTAINER (widget)) |
179 | + { |
180 | + gboolean increment = GTK_IS_MENU_SHELL (widget) || GTK_IS_MENU_ITEM (widget); |
181 | + |
182 | + if (increment) |
183 | + recurse->count++; |
184 | + |
185 | + /* Okay, this is a little janky and all.. but some applications update some |
186 | + * menuitem properties such as sensitivity on the activate callback. This |
187 | + * seems a little weird, but it's not our place to judge when all this code |
188 | + * is so crazy. So we're going to get ever crazier and activate all the |
189 | + * menus that are directly below the menubar and force the applications to |
190 | + * update their sensitivity. The menus won't actually popup in the app |
191 | + * window due to our gtk+ patches. |
192 | + * |
193 | + * Note that this will not force menuitems in submenus to be updated as well. |
194 | + */ |
195 | + if (recurse->count == 0 && GTK_IS_MENU_BAR (widget)) |
196 | + { |
197 | + GList *children = gtk_container_get_children (GTK_CONTAINER (widget)); |
198 | + |
199 | + for (; children != NULL; children = children->next) |
200 | + { |
201 | + gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget), |
202 | + children->data, |
203 | + TRUE); |
204 | + } |
205 | + |
206 | + g_list_free (children); |
207 | + } |
208 | + |
209 | + if (recurse->count > -1 && increment) |
210 | + { |
211 | + gpointer pmi = g_object_get_data(G_OBJECT(widget), CACHED_MENUITEM); |
212 | + DbusmenuMenuitem *dmi = NULL; |
213 | + if (pmi != NULL) dmi = DBUSMENU_MENUITEM(pmi); |
214 | + |
215 | + if (dmi != NULL) |
216 | + { |
217 | + if (increment) |
218 | + recurse->count--; |
219 | + |
220 | + return; |
221 | + } |
222 | + else |
223 | + { |
224 | + recurse->stack[recurse->count] = construct_dbusmenu_for_widget (widget); |
225 | + g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, recurse->stack[recurse->count], object_cache_freed); |
226 | + g_object_weak_ref(G_OBJECT(recurse->stack[recurse->count]), dbusmenu_cache_freed, widget); |
227 | + } |
228 | + |
229 | + if (!gtk_widget_get_visible (widget)) |
230 | + { |
231 | + g_signal_connect (G_OBJECT (widget), |
232 | + "notify::visible", |
233 | + G_CALLBACK (menuitem_notify_cb), |
234 | + recurse->toplevel); |
235 | + } |
236 | + |
237 | + if (GTK_IS_TEAROFF_MENU_ITEM (widget)) |
238 | + { |
239 | + dbusmenu_menuitem_property_set_bool (recurse->stack[recurse->count], |
240 | + DBUSMENU_MENUITEM_PROP_VISIBLE, |
241 | + FALSE); |
242 | + } |
243 | + |
244 | + if (recurse->count > 0) |
245 | + { |
246 | + GList *children = NULL; |
247 | + GList *peek = NULL; |
248 | + |
249 | + if (recurse->stack[recurse->count - 1]) |
250 | + { |
251 | + children = dbusmenu_menuitem_get_children (recurse->stack[recurse->count - 1]); |
252 | + |
253 | + if (children) |
254 | + { |
255 | + peek = g_list_find (children, recurse->stack[recurse->count]); |
256 | + } |
257 | + |
258 | + if (!peek) |
259 | + { |
260 | + /* Should we set a weak ref on the parent? */ |
261 | + g_object_set_data (G_OBJECT (recurse->stack[recurse->count]), |
262 | + "dbusmenu-parent", |
263 | + recurse->stack[recurse->count - 1]); |
264 | + dbusmenu_menuitem_child_append (recurse->stack[recurse->count - 1], |
265 | + recurse->stack[recurse->count]); |
266 | + } |
267 | + } |
268 | + else |
269 | + { |
270 | + DbusmenuMenuitem *item = NULL; /* g_hash_table_lookup (recurse->context->lookup, |
271 | + gtk_widget_get_parent (widget)); */ |
272 | + |
273 | + if (item) |
274 | + { |
275 | + children = dbusmenu_menuitem_get_children (item); |
276 | + |
277 | + if (children) |
278 | + { |
279 | + peek = g_list_find (children, recurse->stack[recurse->count]); |
280 | + } |
281 | + |
282 | + if (!peek) |
283 | + { |
284 | + g_object_set_data (G_OBJECT (recurse->stack[recurse->count]), |
285 | + "dbusmenu-parent", |
286 | + recurse->stack[recurse->count - 1]); |
287 | + |
288 | + dbusmenu_menuitem_child_append (item, recurse->stack[recurse->count]); |
289 | + } |
290 | + } |
291 | + } |
292 | + } |
293 | + } |
294 | + |
295 | + gtk_container_foreach (GTK_CONTAINER (widget), |
296 | + (GtkCallback)parse_menu_structure_helper, |
297 | + recurse); |
298 | + |
299 | + if (GTK_IS_MENU_ITEM (widget)) |
300 | + { |
301 | + GtkWidget *menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)); |
302 | + |
303 | + if (menu != NULL) |
304 | + { |
305 | + parse_menu_structure_helper (menu, recurse); |
306 | + } |
307 | + } |
308 | + |
309 | + if (increment) |
310 | + recurse->count--; |
311 | + } |
312 | +} |
313 | + |
314 | +/* Turn a widget into a dbusmenu item depending on the type of GTK |
315 | + object that it is. */ |
316 | +static DbusmenuMenuitem * |
317 | +construct_dbusmenu_for_widget (GtkWidget * widget) |
318 | +{ |
319 | + /* If it's a subclass of our serializable menu item then we can |
320 | + use its own build function */ |
321 | + if (DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(widget)) { |
322 | + DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(widget); |
323 | + return dbusmenu_gtk_serializable_menu_item_build_menuitem(smi); |
324 | + } |
325 | + |
326 | + /* If it's a standard GTK Menu Item we need to do some of our own work */ |
327 | + if (GTK_IS_MENU_ITEM (widget)) |
328 | + { |
329 | + DbusmenuMenuitem *mi = dbusmenu_menuitem_new (); |
330 | + |
331 | + gboolean visible = FALSE; |
332 | + gboolean sensitive = FALSE; |
333 | + if (GTK_IS_SEPARATOR_MENU_ITEM (widget)) |
334 | + { |
335 | + dbusmenu_menuitem_property_set (mi, |
336 | + "type", |
337 | + "separator"); |
338 | + |
339 | + visible = gtk_widget_get_visible (widget); |
340 | + sensitive = gtk_widget_get_sensitive (widget); |
341 | + } |
342 | + else |
343 | + { |
344 | + gboolean label_set = FALSE; |
345 | + |
346 | + g_signal_connect (widget, |
347 | + "accel-closures-changed", |
348 | + G_CALLBACK (accel_changed), |
349 | + mi); |
350 | + |
351 | + if (GTK_IS_CHECK_MENU_ITEM (widget)) |
352 | + { |
353 | + dbusmenu_menuitem_property_set (mi, |
354 | + DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, |
355 | + gtk_check_menu_item_get_draw_as_radio (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_RADIO : DBUSMENU_MENUITEM_TOGGLE_CHECK); |
356 | + |
357 | + dbusmenu_menuitem_property_set_int (mi, |
358 | + DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, |
359 | + gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); |
360 | + |
361 | + g_signal_connect (widget, |
362 | + "activate", |
363 | + G_CALLBACK (checkbox_toggled), |
364 | + mi); |
365 | + } |
366 | + |
367 | + if (GTK_IS_IMAGE_MENU_ITEM (widget)) |
368 | + { |
369 | + GtkWidget *image; |
370 | + GtkImageType image_type; |
371 | + |
372 | + image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (widget)); |
373 | + |
374 | + if (GTK_IS_IMAGE (image)) |
375 | + { |
376 | + image_type = gtk_image_get_storage_type (GTK_IMAGE (image)); |
377 | + |
378 | + if (image_type == GTK_IMAGE_STOCK) |
379 | + { |
380 | + label_set = update_stock_item (mi, image); |
381 | + } |
382 | + else if (image_type == GTK_IMAGE_ICON_NAME) |
383 | + { |
384 | + update_icon_name (mi, image); |
385 | + } |
386 | + else if (image_type == GTK_IMAGE_PIXBUF) |
387 | + { |
388 | + dbusmenu_menuitem_property_set_image (mi, |
389 | + DBUSMENU_MENUITEM_PROP_ICON_DATA, |
390 | + gtk_image_get_pixbuf (GTK_IMAGE (image))); |
391 | + } |
392 | + } |
393 | + } |
394 | + |
395 | + GtkWidget *label = find_menu_label (widget); |
396 | + |
397 | + dbusmenu_menuitem_property_set (mi, |
398 | + "label", |
399 | + label ? gtk_label_get_text (GTK_LABEL (label)) : NULL); |
400 | + |
401 | + if (label) |
402 | + { |
403 | + // Sometimes, an app will directly find and modify the label |
404 | + // (like empathy), so watch the label especially for that. |
405 | + g_signal_connect (G_OBJECT (label), |
406 | + "notify", |
407 | + G_CALLBACK (label_notify_cb), |
408 | + mi); |
409 | + } |
410 | + |
411 | + if (GTK_IS_ACTIVATABLE (widget)) |
412 | + { |
413 | + GtkActivatable *activatable = GTK_ACTIVATABLE (widget); |
414 | + |
415 | + if (gtk_activatable_get_use_action_appearance (activatable)) |
416 | + { |
417 | + GtkAction *action = gtk_activatable_get_related_action (activatable); |
418 | + |
419 | + if (action) |
420 | + { |
421 | + visible = gtk_action_is_visible (action); |
422 | + sensitive = gtk_action_is_sensitive (action); |
423 | + |
424 | + g_signal_connect_object (action, "notify", |
425 | + G_CALLBACK (action_notify_cb), |
426 | + mi, |
427 | + G_CONNECT_AFTER); |
428 | + } |
429 | + } |
430 | + } |
431 | + |
432 | + if (!g_object_get_data (G_OBJECT (widget), "gtk-empty-menu-item") && !GTK_IS_TEAROFF_MENU_ITEM (widget)) |
433 | + { |
434 | + visible = gtk_widget_get_visible (widget); |
435 | + sensitive = gtk_widget_get_sensitive (widget); |
436 | + } |
437 | + |
438 | + dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget)); |
439 | + |
440 | + g_signal_connect (G_OBJECT (mi), |
441 | + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, |
442 | + G_CALLBACK (item_activated), |
443 | + widget); |
444 | + |
445 | + g_signal_connect (G_OBJECT (mi), |
446 | + DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW, |
447 | + G_CALLBACK (item_about_to_show), |
448 | + widget); |
449 | + } |
450 | + |
451 | + dbusmenu_menuitem_property_set_bool (mi, |
452 | + DBUSMENU_MENUITEM_PROP_VISIBLE, |
453 | + visible); |
454 | + |
455 | + dbusmenu_menuitem_property_set_bool (mi, |
456 | + DBUSMENU_MENUITEM_PROP_ENABLED, |
457 | + sensitive); |
458 | + |
459 | + g_signal_connect (widget, |
460 | + "notify", |
461 | + G_CALLBACK (widget_notify_cb), |
462 | + mi); |
463 | + return mi; |
464 | + } |
465 | + |
466 | + /* If it's none of those we're going to just create a |
467 | + generic menuitem as a place holder for it. */ |
468 | + return dbusmenu_menuitem_new(); |
469 | +} |
470 | + |
471 | +static void |
472 | +menuitem_notify_cb (GtkWidget *widget, |
473 | + GParamSpec *pspec, |
474 | + gpointer data) |
475 | +{ |
476 | + if (pspec->name == g_intern_static_string ("visible")) |
477 | + { |
478 | + GtkWidget * new_toplevel = gtk_widget_get_toplevel (widget); |
479 | + GtkWidget * old_toplevel = GTK_WIDGET(data); |
480 | + |
481 | + if (new_toplevel == old_toplevel) { |
482 | + /* TODO: Figure this out -> rebuild (context->bridge, window); */ |
483 | + } |
484 | + |
485 | + /* We only care about this once, so let's disconnect now. */ |
486 | + g_signal_handlers_disconnect_by_func (widget, |
487 | + G_CALLBACK (menuitem_notify_cb), |
488 | + data); |
489 | + } |
490 | +} |
491 | + |
492 | +static void |
493 | +accel_changed (GtkWidget *widget, |
494 | + gpointer data) |
495 | +{ |
496 | + DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data; |
497 | + dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget)); |
498 | +} |
499 | + |
500 | +static gboolean |
501 | +update_stock_item (DbusmenuMenuitem *menuitem, |
502 | + GtkWidget *widget) |
503 | +{ |
504 | + GtkStockItem stock; |
505 | + GtkImage *image; |
506 | + |
507 | + g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE); |
508 | + |
509 | + image = GTK_IMAGE (widget); |
510 | + |
511 | + if (gtk_image_get_storage_type (image) != GTK_IMAGE_STOCK) |
512 | + return FALSE; |
513 | + |
514 | + gchar * stock_id = NULL; |
515 | + gtk_image_get_stock(image, &stock_id, NULL); |
516 | + |
517 | + gtk_stock_lookup (stock_id, &stock); |
518 | + |
519 | + if (should_show_image (image)) |
520 | + dbusmenu_menuitem_property_set (menuitem, |
521 | + DBUSMENU_MENUITEM_PROP_ICON_NAME, |
522 | + stock_id); |
523 | + else |
524 | + dbusmenu_menuitem_property_remove (menuitem, |
525 | + DBUSMENU_MENUITEM_PROP_ICON_NAME); |
526 | + |
527 | + const gchar *label = dbusmenu_menuitem_property_get (menuitem, |
528 | + DBUSMENU_MENUITEM_PROP_LABEL); |
529 | + |
530 | + if (stock.label != NULL && label != NULL) |
531 | + { |
532 | + dbusmenu_menuitem_property_set (menuitem, |
533 | + DBUSMENU_MENUITEM_PROP_LABEL, |
534 | + stock.label); |
535 | + |
536 | + return TRUE; |
537 | + } |
538 | + |
539 | + return FALSE; |
540 | +} |
541 | + |
542 | +static void |
543 | +checkbox_toggled (GtkWidget *widget, DbusmenuMenuitem *mi) |
544 | +{ |
545 | + dbusmenu_menuitem_property_set_int (mi, |
546 | + DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, |
547 | + gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); |
548 | +} |
549 | + |
550 | +static void |
551 | +update_icon_name (DbusmenuMenuitem *menuitem, |
552 | + GtkWidget *widget) |
553 | +{ |
554 | + GtkImage *image; |
555 | + |
556 | + g_return_if_fail (GTK_IS_IMAGE (widget)); |
557 | + |
558 | + image = GTK_IMAGE (widget); |
559 | + |
560 | + if (gtk_image_get_storage_type (image) != GTK_IMAGE_ICON_NAME) |
561 | + return; |
562 | + |
563 | + if (should_show_image (image)) { |
564 | + const gchar * icon_name = NULL; |
565 | + gtk_image_get_icon_name(image, &icon_name, NULL); |
566 | + dbusmenu_menuitem_property_set (menuitem, |
567 | + DBUSMENU_MENUITEM_PROP_ICON_NAME, |
568 | + icon_name); |
569 | + } else { |
570 | + dbusmenu_menuitem_property_remove (menuitem, |
571 | + DBUSMENU_MENUITEM_PROP_ICON_NAME); |
572 | + } |
573 | +} |
574 | + |
575 | +static GtkWidget * |
576 | +find_menu_label (GtkWidget *widget) |
577 | +{ |
578 | + GtkWidget *label = NULL; |
579 | + |
580 | + if (GTK_IS_LABEL (widget)) |
581 | + return widget; |
582 | + |
583 | + if (GTK_IS_CONTAINER (widget)) |
584 | + { |
585 | + GList *children; |
586 | + GList *l; |
587 | + |
588 | + children = gtk_container_get_children (GTK_CONTAINER (widget)); |
589 | + |
590 | + for (l = children; l; l = l->next) |
591 | + { |
592 | + label = find_menu_label (l->data); |
593 | + |
594 | + if (label) |
595 | + break; |
596 | + } |
597 | + |
598 | + g_list_free (children); |
599 | + } |
600 | + |
601 | + return label; |
602 | +} |
603 | + |
604 | +static void |
605 | +label_notify_cb (GtkWidget *widget, |
606 | + GParamSpec *pspec, |
607 | + gpointer data) |
608 | +{ |
609 | + DbusmenuMenuitem *child = (DbusmenuMenuitem *)data; |
610 | + |
611 | + if (pspec->name == g_intern_static_string ("label")) |
612 | + { |
613 | + dbusmenu_menuitem_property_set (child, |
614 | + DBUSMENU_MENUITEM_PROP_LABEL, |
615 | + gtk_label_get_text (GTK_LABEL (widget))); |
616 | + } |
617 | +} |
618 | + |
619 | +static void |
620 | +action_notify_cb (GtkAction *action, |
621 | + GParamSpec *pspec, |
622 | + gpointer data) |
623 | +{ |
624 | + DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data; |
625 | + |
626 | + if (pspec->name == g_intern_static_string ("sensitive")) |
627 | + { |
628 | + dbusmenu_menuitem_property_set_bool (mi, |
629 | + DBUSMENU_MENUITEM_PROP_ENABLED, |
630 | + gtk_action_is_sensitive (action)); |
631 | + } |
632 | + else if (pspec->name == g_intern_static_string ("visible")) |
633 | + { |
634 | + dbusmenu_menuitem_property_set_bool (mi, |
635 | + DBUSMENU_MENUITEM_PROP_VISIBLE, |
636 | + gtk_action_is_visible (action)); |
637 | + } |
638 | + else if (pspec->name == g_intern_static_string ("active")) |
639 | + { |
640 | + dbusmenu_menuitem_property_set_bool (mi, |
641 | + DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, |
642 | + gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))); |
643 | + } |
644 | + else if (pspec->name == g_intern_static_string ("label")) |
645 | + { |
646 | + dbusmenu_menuitem_property_set (mi, |
647 | + DBUSMENU_MENUITEM_PROP_LABEL, |
648 | + gtk_action_get_label (action)); |
649 | + } |
650 | +} |
651 | + |
652 | +static void |
653 | +item_activated (DbusmenuMenuitem *item, guint timestamp, gpointer user_data) |
654 | +{ |
655 | + GtkWidget *child; |
656 | + |
657 | + if (user_data != NULL) |
658 | + { |
659 | + child = (GtkWidget *)user_data; |
660 | + |
661 | + if (GTK_IS_MENU_ITEM (child)) |
662 | + { |
663 | + gtk_menu_item_activate (GTK_MENU_ITEM (child)); |
664 | + } |
665 | + } |
666 | +} |
667 | + |
668 | +static gboolean |
669 | +item_about_to_show (DbusmenuMenuitem *item, gpointer user_data) |
670 | +{ |
671 | + GtkWidget *child; |
672 | + |
673 | + if (user_data != NULL) |
674 | + { |
675 | + child = (GtkWidget *)user_data; |
676 | + |
677 | + if (GTK_IS_MENU_ITEM (child)) |
678 | + { |
679 | + // Only called for items with submens. So we activate it here in |
680 | + // case the program dynamically creates menus (like empathy does) |
681 | + gtk_menu_item_activate (GTK_MENU_ITEM (child)); |
682 | + } |
683 | + } |
684 | + |
685 | + return TRUE; |
686 | +} |
687 | + |
688 | +static void |
689 | +widget_notify_cb (GtkWidget *widget, |
690 | + GParamSpec *pspec, |
691 | + gpointer data) |
692 | +{ |
693 | + DbusmenuMenuitem *child = (DbusmenuMenuitem *)data; |
694 | + |
695 | + if (pspec->name == g_intern_static_string ("sensitive")) |
696 | + { |
697 | + dbusmenu_menuitem_property_set_bool (child, |
698 | + DBUSMENU_MENUITEM_PROP_ENABLED, |
699 | + gtk_widget_get_sensitive (widget)); |
700 | + } |
701 | + else if (pspec->name == g_intern_static_string ("label")) |
702 | + { |
703 | + dbusmenu_menuitem_property_set (child, |
704 | + DBUSMENU_MENUITEM_PROP_LABEL, |
705 | + gtk_menu_item_get_label (GTK_MENU_ITEM (widget))); |
706 | + } |
707 | + else if (pspec->name == g_intern_static_string ("visible")) |
708 | + { |
709 | + dbusmenu_menuitem_property_set_bool (child, |
710 | + DBUSMENU_MENUITEM_PROP_VISIBLE, |
711 | + gtk_widget_get_visible (widget)); |
712 | + } |
713 | + else if (pspec->name == g_intern_static_string ("stock")) |
714 | + { |
715 | + update_stock_item (child, widget); |
716 | + } |
717 | + else if (pspec->name == g_intern_static_string ("icon-name")) |
718 | + { |
719 | + update_icon_name (child, widget); |
720 | + } |
721 | + else if (pspec->name == g_intern_static_string ("parent")) |
722 | + { |
723 | + /* |
724 | + * We probably should have added a 'remove' method to the |
725 | + * UbuntuMenuProxy early on, but it's late in the cycle now. |
726 | + */ |
727 | + if (gtk_widget_get_parent (widget) == NULL) |
728 | + { |
729 | + g_signal_handlers_disconnect_by_func (widget, |
730 | + G_CALLBACK (widget_notify_cb), |
731 | + child); |
732 | + |
733 | + DbusmenuMenuitem *parent = g_object_get_data (G_OBJECT (child), "dbusmenu-parent"); |
734 | + |
735 | + if (DBUSMENU_IS_MENUITEM (parent) && DBUSMENU_IS_MENUITEM (child)) |
736 | + { |
737 | + dbusmenu_menuitem_child_delete (parent, child); |
738 | + } |
739 | + } |
740 | + } |
741 | +} |
742 | + |
743 | +static gboolean |
744 | +should_show_image (GtkImage *image) |
745 | +{ |
746 | + GtkWidget *item; |
747 | + |
748 | + item = gtk_widget_get_ancestor (GTK_WIDGET (image), |
749 | + GTK_TYPE_IMAGE_MENU_ITEM); |
750 | + |
751 | + if (item) |
752 | + { |
753 | + GtkSettings *settings; |
754 | + gboolean gtk_menu_images; |
755 | + |
756 | + settings = gtk_widget_get_settings (item); |
757 | + |
758 | + g_object_get (settings, "gtk-menu-images", >k_menu_images, NULL); |
759 | + |
760 | + if (gtk_menu_images) |
761 | + return TRUE; |
762 | + |
763 | + return gtk_image_menu_item_get_always_show_image (GTK_IMAGE_MENU_ITEM (item)); |
764 | + } |
765 | + |
766 | + return FALSE; |
767 | +} |
768 | + |
769 | |
770 | === added file 'libdbusmenu-gtk/parser.h' |
771 | --- libdbusmenu-gtk/parser.h 1970-01-01 00:00:00 +0000 |
772 | +++ libdbusmenu-gtk/parser.h 2011-01-27 15:48:01 +0000 |
773 | @@ -0,0 +1,37 @@ |
774 | +/* |
775 | +Parse to take a set of GTK Menus and turn them into something that can |
776 | +be sent over the wire. |
777 | + |
778 | +Copyright 2011 Canonical Ltd. |
779 | + |
780 | +Authors: |
781 | + Ted Gould <ted@canonical.com> |
782 | + |
783 | +This program is free software: you can redistribute it and/or modify it |
784 | +under the terms of either or both of the following licenses: |
785 | + |
786 | +1) the GNU Lesser General Public License version 3, as published by the |
787 | +Free Software Foundation; and/or |
788 | +2) the GNU Lesser General Public License version 2.1, as published by |
789 | +the Free Software Foundation. |
790 | + |
791 | +This program is distributed in the hope that it will be useful, but |
792 | +WITHOUT ANY WARRANTY; without even the implied warranties of |
793 | +MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR |
794 | +PURPOSE. See the applicable version of the GNU Lesser General Public |
795 | +License for more details. |
796 | + |
797 | +You should have received a copy of both the GNU Lesser General Public |
798 | +License version 3 and version 2.1 along with this program. If not, see |
799 | +<http://www.gnu.org/licenses/> |
800 | +*/ |
801 | + |
802 | +#ifndef DBUSMENU_GTK_PARSER_H__ |
803 | +#define DBUSMENU_GTK_PARSER_H__ |
804 | + |
805 | +#include <libdbusmenu-glib/menuitem.h> |
806 | +#include <gtk/gtk.h> |
807 | + |
808 | +DbusmenuMenuitem * dbusmenu_gtk_parse_menu_structure (GtkWidget * widget); |
809 | + |
810 | +#endif /* DBUSMENU_GTK_PARSER_H__ */ |
811 | |
812 | === modified file 'libdbusmenu-gtk/serializablemenuitem.c' |
813 | --- libdbusmenu-gtk/serializablemenuitem.c 2011-01-27 15:48:01 +0000 |
814 | +++ libdbusmenu-gtk/serializablemenuitem.c 2011-01-27 15:48:01 +0000 |
815 | @@ -166,7 +166,7 @@ |
816 | } |
817 | |
818 | /** |
819 | - dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem: |
820 | + dbusmenu_gtk_serializable_menu_item_build_menuitem: |
821 | @smi: #DbusmenuGtkSerializableMenuItem to build a #DbusmenuMenuitem mirroring |
822 | |
823 | This function is for menu items that are instanciated from |
824 | @@ -179,7 +179,7 @@ |
825 | set by this object. |
826 | */ |
827 | DbusmenuMenuitem * |
828 | -dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi) |
829 | +dbusmenu_gtk_serializable_menu_item_build_menuitem (DbusmenuGtkSerializableMenuItem * smi) |
830 | { |
831 | g_return_val_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi), NULL); |
832 | |
833 | @@ -207,7 +207,7 @@ |
834 | DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(g_object_new(th->type, NULL)); |
835 | g_return_val_if_fail(smi != NULL, FALSE); |
836 | |
837 | - dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem(smi, newitem); |
838 | + dbusmenu_gtk_serializable_menu_item_set_menuitem(smi, newitem); |
839 | dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(smi), parent); |
840 | |
841 | return TRUE; |
842 | @@ -265,7 +265,7 @@ |
843 | } |
844 | |
845 | /** |
846 | - dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem: |
847 | + dbusmenu_gtk_serializable_menu_item_set_menuitem: |
848 | @smi: #DbusmenuGtkSerializableMenuItem to set the @DbusmenuGtkSerializableMenuItem::dbusmenu-menuitem of |
849 | @mi: Menuitem to get the properties from |
850 | |
851 | @@ -276,7 +276,7 @@ |
852 | pick up this property being set. |
853 | */ |
854 | void |
855 | -dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi) |
856 | +dbusmenu_gtk_serializable_menu_item_set_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi) |
857 | { |
858 | g_return_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi)); |
859 | g_return_if_fail(mi != NULL); |
860 | |
861 | === modified file 'libdbusmenu-gtk/serializablemenuitem.h' |
862 | --- libdbusmenu-gtk/serializablemenuitem.h 2011-01-27 15:48:01 +0000 |
863 | +++ libdbusmenu-gtk/serializablemenuitem.h 2011-01-27 15:48:01 +0000 |
864 | @@ -90,6 +90,13 @@ |
865 | DbusmenuGtkSerializableMenuItem: |
866 | @parent: Inherit from GtkMenuItem |
867 | @priv: Blind structure of private variables |
868 | + |
869 | + The Serializable Menuitem provides a way for menu items to be created |
870 | + that can easily be picked up by the Dbusmenu GTK Parser. This way |
871 | + you can create custom items, and transport them across dbusmenu to |
872 | + your menus or the appmenu on the other side of the bus. By providing |
873 | + these function the parser has enough information to both serialize, and |
874 | + deserialize on the other side, the menuitem you've so carefully created. |
875 | */ |
876 | struct _DbusmenuGtkSerializableMenuItem { |
877 | GtkMenuItem parent; |
878 | @@ -99,9 +106,9 @@ |
879 | |
880 | GType dbusmenu_gtk_serializable_menu_item_get_type (void); |
881 | |
882 | -DbusmenuMenuitem * dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi); |
883 | +DbusmenuMenuitem * dbusmenu_gtk_serializable_menu_item_build_menuitem (DbusmenuGtkSerializableMenuItem * smi); |
884 | void dbusmenu_gtk_serializable_menu_item_register_to_client (DbusmenuClient * client, GType item_type); |
885 | -void dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi); |
886 | +void dbusmenu_gtk_serializable_menu_item_set_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi); |
887 | |
888 | G_END_DECLS |
889 | |
890 | |
891 | === modified file 'tests/Makefile.am' |
892 | --- tests/Makefile.am 2010-12-08 03:17:43 +0000 |
893 | +++ tests/Makefile.am 2011-01-27 15:48:01 +0000 |
894 | @@ -16,7 +16,8 @@ |
895 | test-gtk-label \ |
896 | test-gtk-shortcut \ |
897 | test-gtk-reorder \ |
898 | - test-gtk-submenu |
899 | + test-gtk-submenu \ |
900 | + test-gtk-parser-test |
901 | |
902 | check_PROGRAMS = \ |
903 | glib-server-nomenu \ |
904 | @@ -42,7 +43,8 @@ |
905 | test-json-client \ |
906 | test-json-server \ |
907 | test-gtk-submenu-server \ |
908 | - test-gtk-submenu-client |
909 | + test-gtk-submenu-client \ |
910 | + test-gtk-parser |
911 | |
912 | XVFB_RUN=". $(srcdir)/run-xvfb.sh" |
913 | |
914 | @@ -384,6 +386,35 @@ |
915 | $(DBUSMENUGLIB_LIBS) \ |
916 | $(DBUSMENUGTK_LIBS) |
917 | |
918 | +###################### |
919 | +# Test GTK Parser |
920 | +###################### |
921 | + |
922 | +GTK_PARSER_XML_REPORT = test-gtk-parser.xml |
923 | + |
924 | +test-gtk-parser-test: test-gtk-parser Makefile.am |
925 | + @echo "#!/bin/bash" > $@ |
926 | + @echo $(XVFB_RUN) >> $@ |
927 | + @echo gtester --verbose -k -o $(GTK_PARSER_XML_REPORT) ./test-gtk-parser >> $@ |
928 | + @chmod +x $@ |
929 | + |
930 | +test_gtk_parser_SOURCES = \ |
931 | + test-gtk-parser.c |
932 | + |
933 | +test_gtk_parser_CFLAGS = \ |
934 | + -I $(srcdir)/.. \ |
935 | + $(DBUSMENUGLIB_CFLAGS) \ |
936 | + $(DBUSMENUGTK_CFLAGS) \ |
937 | + -DSRCDIR="\"$(srcdir)\"" \ |
938 | + -Wall -Werror |
939 | + |
940 | +test_gtk_parser_LDADD = \ |
941 | + ../libdbusmenu-glib/libdbusmenu-glib.la \ |
942 | + ../libdbusmenu-gtk/libdbusmenu-gtk.la \ |
943 | + $(DBUSMENUGLIB_LIBS) \ |
944 | + $(DBUSMENUGTK_LIBS) |
945 | + |
946 | + |
947 | ######################### |
948 | # Test GTK Label |
949 | ######################### |
950 | |
951 | === added file 'tests/test-gtk-parser.c' |
952 | --- tests/test-gtk-parser.c 1970-01-01 00:00:00 +0000 |
953 | +++ tests/test-gtk-parser.c 2011-01-27 15:48:01 +0000 |
954 | @@ -0,0 +1,115 @@ |
955 | +/* |
956 | +Testing for the various objects just by themselves. |
957 | + |
958 | +Copyright 2011 Canonical Ltd. |
959 | + |
960 | +Authors: |
961 | + Ted Gould <ted@canonical.com> |
962 | + |
963 | +This program is free software: you can redistribute it and/or modify it |
964 | +under the terms of the GNU General Public License version 3, as published |
965 | +by the Free Software Foundation. |
966 | + |
967 | +This program is distributed in the hope that it will be useful, but |
968 | +WITHOUT ANY WARRANTY; without even the implied warranties of |
969 | +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
970 | +PURPOSE. See the GNU General Public License for more details. |
971 | + |
972 | +You should have received a copy of the GNU General Public License along |
973 | +with this program. If not, see <http://www.gnu.org/licenses/>. |
974 | +*/ |
975 | + |
976 | +#include <libdbusmenu-glib/menuitem-private.h> |
977 | +#include <libdbusmenu-gtk/parser.h> |
978 | + |
979 | +/* Just makes sure we can connect here people */ |
980 | +static void |
981 | +test_parser_runs (void) |
982 | +{ |
983 | + GtkWidget * gmi = gtk_menu_item_new_with_label("Test Item"); |
984 | + g_assert(gmi != NULL); |
985 | + DbusmenuMenuitem * mi = dbusmenu_gtk_parse_menu_structure(gmi); |
986 | + g_assert(mi != NULL); |
987 | + |
988 | + g_object_unref(gmi); |
989 | + g_object_unref(mi); |
990 | + |
991 | + return; |
992 | +} |
993 | + |
994 | +const gchar * test_parser_children_builder = |
995 | +"<?xml version=\"1.0\"?>" |
996 | +"<interface>" |
997 | +"<requires lib=\"gtk+\" version=\"2.16\"/>" |
998 | +/* Start menu bar */ |
999 | +"<object class=\"GtkMenuBar\" id=\"menubar\"><property name=\"visible\">True</property>" |
1000 | +/* Child 1 */ |
1001 | +"<child><object class=\"GtkMenuItem\" id=\"child_one\"><property name=\"visible\">True</property><property name=\"label\">Child One</property></object></child>" |
1002 | +/* Child 2 */ |
1003 | +"<child><object class=\"GtkMenuItem\" id=\"child_two\"><property name=\"visible\">True</property><property name=\"label\">Child Two</property></object></child>" |
1004 | +/* Child 3 */ |
1005 | +"<child><object class=\"GtkMenuItem\" id=\"child_three\"><property name=\"visible\">True</property><property name=\"label\">Child Three</property></object></child>" |
1006 | +/* Child 4 */ |
1007 | +"<child><object class=\"GtkMenuItem\" id=\"child_four\"><property name=\"visible\">True</property><property name=\"label\">Child Four</property></object></child>" |
1008 | +/* Stop menubar */ |
1009 | +"</object>" |
1010 | +"</interface>"; |
1011 | + |
1012 | +/* Ensure the parser can find children */ |
1013 | +static void |
1014 | +test_parser_children (void) { |
1015 | + GtkBuilder * builder = gtk_builder_new(); |
1016 | + g_assert(builder != NULL); |
1017 | + |
1018 | + GError * error = NULL; |
1019 | + gtk_builder_add_from_string(builder, test_parser_children_builder, -1, &error); |
1020 | + if (error != NULL) { |
1021 | + g_error("Unable to parse UI definition: %s", error->message); |
1022 | + g_error_free(error); |
1023 | + error = NULL; |
1024 | + } |
1025 | + |
1026 | + GtkWidget * menu = GTK_WIDGET(gtk_builder_get_object(builder, "menubar")); |
1027 | + g_assert(menu != NULL); |
1028 | + |
1029 | + DbusmenuMenuitem * mi = dbusmenu_gtk_parse_menu_structure(menu); |
1030 | + g_assert(mi != NULL); |
1031 | + |
1032 | +/* |
1033 | + GPtrArray * xmlarray = g_ptr_array_new(); |
1034 | + dbusmenu_menuitem_buildxml(mi, xmlarray); |
1035 | + g_debug("XML: %s", g_strjoinv("", (gchar **)xmlarray->pdata)); |
1036 | +*/ |
1037 | + |
1038 | + GList * children = dbusmenu_menuitem_get_children(mi); |
1039 | + g_assert(children != NULL); |
1040 | + |
1041 | + g_assert(g_list_length(children) == 4); |
1042 | + |
1043 | + g_object_unref(mi); |
1044 | + g_object_unref(menu); |
1045 | + |
1046 | + return; |
1047 | +} |
1048 | + |
1049 | +/* Build the test suite */ |
1050 | +static void |
1051 | +test_gtk_parser_suite (void) |
1052 | +{ |
1053 | + g_test_add_func ("/dbusmenu/gtk/parser/base", test_parser_runs); |
1054 | + g_test_add_func ("/dbusmenu/gtk/parser/children", test_parser_children); |
1055 | + return; |
1056 | +} |
1057 | + |
1058 | +gint |
1059 | +main (gint argc, gchar * argv[]) |
1060 | +{ |
1061 | + gtk_init(&argc, &argv); |
1062 | + g_test_init(&argc, &argv, NULL); |
1063 | + |
1064 | + /* Test suites */ |
1065 | + test_gtk_parser_suite(); |
1066 | + |
1067 | + |
1068 | + return g_test_run (); |
1069 | +} |
How does this branch relate to https:/ /code.launchpad .net/~ted/ dbusmenu/ serializable- menuitem/ +merge/ 47604 ? They look identical?