Merge lp:~ted/libdbusmenu/parse-serializable-menuitem into lp:libdbusmenu/0.5
- parse-serializable-menuitem
- Merge into trunk
Proposed by
Ted Gould
Status: | Merged |
---|---|
Merged at revision: | 198 |
Proposed branch: | lp:~ted/libdbusmenu/parse-serializable-menuitem |
Merge into: | lp:libdbusmenu/0.5 |
Prerequisite: | lp:~ted/libdbusmenu/serializable-menuitem |
Diff against target: |
857 lines (+743/-7) (has conflicts) 6 files modified
.bzrignore (+4/-0) libdbusmenu-glib/client.h (+21/-0) libdbusmenu-gtk/Makefile.am (+3/-0) libdbusmenu-gtk/parser.c (+701/-0) libdbusmenu-gtk/serializablemenuitem.c (+5/-5) libdbusmenu-gtk/serializablemenuitem.h (+9/-2) Text conflict in .bzrignore Text conflict in libdbusmenu-gtk/Makefile.am Text conflict in libdbusmenu-gtk/parser.c |
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: mp+47710@code.launchpad.net |
This proposal supersedes 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
Mikkel Kamstrup Erlandsen (kamstrup) wrote : Posted in a previous version of this proposal | # |
review:
Needs Information
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 19:48:12 +0000 |
3 | +++ .bzrignore 2011-01-27 19:48:12 +0000 |
4 | @@ -229,4 +229,8 @@ |
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 | >>>>>>> MERGE-SOURCE |
13 | |
14 | === modified file 'libdbusmenu-glib/client.h' |
15 | --- libdbusmenu-glib/client.h 2011-01-27 19:48:12 +0000 |
16 | +++ libdbusmenu-glib/client.h 2011-01-27 19:48:12 +0000 |
17 | @@ -110,7 +110,28 @@ |
18 | DbusmenuClientPrivate * priv; |
19 | }; |
20 | |
21 | +/** |
22 | + DbusmenuClientTypeHandler: |
23 | + @newitem: The #DbusmenuMenuitem that was created |
24 | + @parent: The parent of @newitem or #NULL if none |
25 | + @client: A pointer to the #DbusmenuClient |
26 | + @user_data: The data you gave us |
27 | + |
28 | + The type handler is called when a dbusmenu item is created |
29 | + with a matching type as setup in #dbusmenu_client_add_type_handler |
30 | +*/ |
31 | typedef gboolean (*DbusmenuClientTypeHandler) (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data); |
32 | + |
33 | +/** |
34 | + DbusmenuClientTypeDestroyHandler: |
35 | + @client: A pointer to the #DbusmenuClient |
36 | + @type: The type that this handler was registered with |
37 | + @user_data: The data you gave us |
38 | + |
39 | + This handler is called when the type becomes unregistered by the |
40 | + client. This is usally caused by the #DbusmenuClient being destroyed |
41 | + and should free memory or unref objects in @user_data. |
42 | +*/ |
43 | typedef void (*DbusmenuClientTypeDestroyHandler) (DbusmenuClient * client, const gchar * type, gpointer user_data); |
44 | |
45 | GType dbusmenu_client_get_type (void); |
46 | |
47 | === modified file 'libdbusmenu-gtk/Makefile.am' |
48 | --- libdbusmenu-gtk/Makefile.am 2011-01-27 19:48:12 +0000 |
49 | +++ libdbusmenu-gtk/Makefile.am 2011-01-27 19:48:12 +0000 |
50 | @@ -28,6 +28,7 @@ |
51 | parser.h |
52 | ======= |
53 | menuitem.h \ |
54 | + parser.h \ |
55 | serializablemenuitem.h |
56 | >>>>>>> MERGE-SOURCE |
57 | |
58 | @@ -45,6 +46,8 @@ |
59 | parser.c |
60 | ======= |
61 | menuitem.c \ |
62 | + parser.h \ |
63 | + parser.c \ |
64 | serializablemenuitem.h \ |
65 | serializablemenuitem.c |
66 | >>>>>>> MERGE-SOURCE |
67 | |
68 | === modified file 'libdbusmenu-gtk/parser.c' |
69 | --- libdbusmenu-gtk/parser.c 2011-01-27 14:50:24 +0000 |
70 | +++ libdbusmenu-gtk/parser.c 2011-01-27 19:48:12 +0000 |
71 | @@ -1,3 +1,4 @@ |
72 | +<<<<<<< TREE |
73 | /* |
74 | Parse to take a set of GTK Menus and turn them into something that can |
75 | be sent over the wire. |
76 | @@ -665,3 +666,703 @@ |
77 | return FALSE; |
78 | } |
79 | |
80 | +======= |
81 | +/* |
82 | +Parse to take a set of GTK Menus and turn them into something that can |
83 | +be sent over the wire. |
84 | + |
85 | +Copyright 2011 Canonical Ltd. |
86 | + |
87 | +Authors: |
88 | + Numerous (check Bazaar) |
89 | + |
90 | +This program is free software: you can redistribute it and/or modify it |
91 | +under the terms of either or both of the following licenses: |
92 | + |
93 | +1) the GNU Lesser General Public License version 3, as published by the |
94 | +Free Software Foundation; and/or |
95 | +2) the GNU Lesser General Public License version 2.1, as published by |
96 | +the Free Software Foundation. |
97 | + |
98 | +This program is distributed in the hope that it will be useful, but |
99 | +WITHOUT ANY WARRANTY; without even the implied warranties of |
100 | +MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR |
101 | +PURPOSE. See the applicable version of the GNU Lesser General Public |
102 | +License for more details. |
103 | + |
104 | +You should have received a copy of both the GNU Lesser General Public |
105 | +License version 3 and version 2.1 along with this program. If not, see |
106 | +<http://www.gnu.org/licenses/> |
107 | +*/ |
108 | + |
109 | +#include "parser.h" |
110 | +#include "menuitem.h" |
111 | +#include "serializablemenuitem.h" |
112 | + |
113 | +#define CACHED_MENUITEM "dbusmenu-gtk-parser-cached-item" |
114 | + |
115 | +typedef struct _RecurseContext |
116 | +{ |
117 | + GtkWidget * toplevel; |
118 | + gint count; |
119 | + DbusmenuMenuitem *stack[30]; |
120 | +} RecurseContext; |
121 | + |
122 | +static void parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse); |
123 | +static DbusmenuMenuitem * construct_dbusmenu_for_widget (GtkWidget * widget); |
124 | +static void accel_changed (GtkWidget * widget, |
125 | + gpointer data); |
126 | +static gboolean update_stock_item (DbusmenuMenuitem * menuitem, |
127 | + GtkWidget * widget); |
128 | +static void checkbox_toggled (GtkWidget * widget, |
129 | + DbusmenuMenuitem * mi); |
130 | +static void update_icon_name (DbusmenuMenuitem * menuitem, |
131 | + GtkWidget * widget); |
132 | +static GtkWidget * find_menu_label (GtkWidget * widget); |
133 | +static void label_notify_cb (GtkWidget * widget, |
134 | + GParamSpec * pspec, |
135 | + gpointer data); |
136 | +static void action_notify_cb (GtkAction * action, |
137 | + GParamSpec * pspec, |
138 | + gpointer data); |
139 | +static void item_activated (DbusmenuMenuitem * item, |
140 | + guint timestamp, |
141 | + gpointer user_data); |
142 | +static gboolean item_about_to_show (DbusmenuMenuitem * item, |
143 | + gpointer user_data); |
144 | +static void widget_notify_cb (GtkWidget * widget, |
145 | + GParamSpec * pspec, |
146 | + gpointer data); |
147 | +static gboolean should_show_image (GtkImage * image); |
148 | +static void menuitem_notify_cb (GtkWidget * widget, |
149 | + GParamSpec * pspec, |
150 | + gpointer data); |
151 | + |
152 | +DbusmenuMenuitem * |
153 | +dbusmenu_gtk_parse_menu_structure (GtkWidget * widget) |
154 | +{ |
155 | + RecurseContext recurse = {0}; |
156 | + |
157 | + recurse.count = -1; |
158 | + recurse.toplevel = gtk_widget_get_toplevel(widget); |
159 | + |
160 | + parse_menu_structure_helper(widget, &recurse); |
161 | + |
162 | + if (recurse.stack[0] != NULL && DBUSMENU_IS_MENUITEM(recurse.stack[0])) { |
163 | + return recurse.stack[0]; |
164 | + } |
165 | + |
166 | + return NULL; |
167 | +} |
168 | + |
169 | +static void |
170 | +dbusmenu_cache_freed (gpointer data, GObject * obj) |
171 | +{ |
172 | + /* If the dbusmenu item is killed we don't need to remove |
173 | + the weak ref as well. */ |
174 | + g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM); |
175 | + return; |
176 | +} |
177 | + |
178 | +static void |
179 | +object_cache_freed (gpointer data) |
180 | +{ |
181 | + g_object_weak_unref(G_OBJECT(data), dbusmenu_cache_freed, data); |
182 | + return; |
183 | +} |
184 | + |
185 | +static void |
186 | +parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse) |
187 | +{ |
188 | + if (GTK_IS_CONTAINER (widget)) |
189 | + { |
190 | + gboolean increment = GTK_IS_MENU_SHELL (widget) || GTK_IS_MENU_ITEM (widget); |
191 | + |
192 | + if (increment) |
193 | + recurse->count++; |
194 | + |
195 | + /* Okay, this is a little janky and all.. but some applications update some |
196 | + * menuitem properties such as sensitivity on the activate callback. This |
197 | + * seems a little weird, but it's not our place to judge when all this code |
198 | + * is so crazy. So we're going to get ever crazier and activate all the |
199 | + * menus that are directly below the menubar and force the applications to |
200 | + * update their sensitivity. The menus won't actually popup in the app |
201 | + * window due to our gtk+ patches. |
202 | + * |
203 | + * Note that this will not force menuitems in submenus to be updated as well. |
204 | + */ |
205 | + if (recurse->count == 0 && GTK_IS_MENU_BAR (widget)) |
206 | + { |
207 | + GList *children = gtk_container_get_children (GTK_CONTAINER (widget)); |
208 | + |
209 | + for (; children != NULL; children = children->next) |
210 | + { |
211 | + gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget), |
212 | + children->data, |
213 | + TRUE); |
214 | + } |
215 | + |
216 | + g_list_free (children); |
217 | + } |
218 | + |
219 | + if (recurse->count > -1 && increment) |
220 | + { |
221 | + gpointer pmi = g_object_get_data(G_OBJECT(widget), CACHED_MENUITEM); |
222 | + DbusmenuMenuitem *dmi = NULL; |
223 | + if (pmi != NULL) dmi = DBUSMENU_MENUITEM(pmi); |
224 | + |
225 | + if (dmi != NULL) |
226 | + { |
227 | + if (increment) |
228 | + recurse->count--; |
229 | + |
230 | + return; |
231 | + } |
232 | + else |
233 | + { |
234 | + recurse->stack[recurse->count] = construct_dbusmenu_for_widget (widget); |
235 | + g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, recurse->stack[recurse->count], object_cache_freed); |
236 | + g_object_weak_ref(G_OBJECT(recurse->stack[recurse->count]), dbusmenu_cache_freed, widget); |
237 | + } |
238 | + |
239 | + if (!gtk_widget_get_visible (widget)) |
240 | + { |
241 | + g_signal_connect (G_OBJECT (widget), |
242 | + "notify::visible", |
243 | + G_CALLBACK (menuitem_notify_cb), |
244 | + recurse->toplevel); |
245 | + } |
246 | + |
247 | + if (GTK_IS_TEAROFF_MENU_ITEM (widget)) |
248 | + { |
249 | + dbusmenu_menuitem_property_set_bool (recurse->stack[recurse->count], |
250 | + DBUSMENU_MENUITEM_PROP_VISIBLE, |
251 | + FALSE); |
252 | + } |
253 | + |
254 | + if (recurse->count > 0) |
255 | + { |
256 | + GList *children = NULL; |
257 | + GList *peek = NULL; |
258 | + |
259 | + if (recurse->stack[recurse->count - 1]) |
260 | + { |
261 | + children = dbusmenu_menuitem_get_children (recurse->stack[recurse->count - 1]); |
262 | + |
263 | + if (children) |
264 | + { |
265 | + peek = g_list_find (children, recurse->stack[recurse->count]); |
266 | + } |
267 | + |
268 | + if (!peek) |
269 | + { |
270 | + /* Should we set a weak ref on the parent? */ |
271 | + g_object_set_data (G_OBJECT (recurse->stack[recurse->count]), |
272 | + "dbusmenu-parent", |
273 | + recurse->stack[recurse->count - 1]); |
274 | + dbusmenu_menuitem_child_append (recurse->stack[recurse->count - 1], |
275 | + recurse->stack[recurse->count]); |
276 | + } |
277 | + } |
278 | + else |
279 | + { |
280 | + DbusmenuMenuitem *item = NULL; /* g_hash_table_lookup (recurse->context->lookup, |
281 | + gtk_widget_get_parent (widget)); */ |
282 | + |
283 | + if (item) |
284 | + { |
285 | + children = dbusmenu_menuitem_get_children (item); |
286 | + |
287 | + if (children) |
288 | + { |
289 | + peek = g_list_find (children, recurse->stack[recurse->count]); |
290 | + } |
291 | + |
292 | + if (!peek) |
293 | + { |
294 | + g_object_set_data (G_OBJECT (recurse->stack[recurse->count]), |
295 | + "dbusmenu-parent", |
296 | + recurse->stack[recurse->count - 1]); |
297 | + |
298 | + dbusmenu_menuitem_child_append (item, recurse->stack[recurse->count]); |
299 | + } |
300 | + } |
301 | + } |
302 | + } |
303 | + } |
304 | + |
305 | + gtk_container_foreach (GTK_CONTAINER (widget), |
306 | + (GtkCallback)parse_menu_structure_helper, |
307 | + recurse); |
308 | + |
309 | + if (GTK_IS_MENU_ITEM (widget)) |
310 | + { |
311 | + GtkWidget *menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)); |
312 | + |
313 | + if (menu != NULL) |
314 | + { |
315 | + parse_menu_structure_helper (menu, recurse); |
316 | + } |
317 | + } |
318 | + |
319 | + if (increment) |
320 | + recurse->count--; |
321 | + } |
322 | +} |
323 | + |
324 | +/* Turn a widget into a dbusmenu item depending on the type of GTK |
325 | + object that it is. */ |
326 | +static DbusmenuMenuitem * |
327 | +construct_dbusmenu_for_widget (GtkWidget * widget) |
328 | +{ |
329 | + /* If it's a subclass of our serializable menu item then we can |
330 | + use its own build function */ |
331 | + if (DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(widget)) { |
332 | + DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(widget); |
333 | + return dbusmenu_gtk_serializable_menu_item_build_menuitem(smi); |
334 | + } |
335 | + |
336 | + /* If it's a standard GTK Menu Item we need to do some of our own work */ |
337 | + if (GTK_IS_MENU_ITEM (widget)) |
338 | + { |
339 | + DbusmenuMenuitem *mi = dbusmenu_menuitem_new (); |
340 | + |
341 | + gboolean visible = FALSE; |
342 | + gboolean sensitive = FALSE; |
343 | + if (GTK_IS_SEPARATOR_MENU_ITEM (widget)) |
344 | + { |
345 | + dbusmenu_menuitem_property_set (mi, |
346 | + "type", |
347 | + "separator"); |
348 | + |
349 | + visible = gtk_widget_get_visible (widget); |
350 | + sensitive = gtk_widget_get_sensitive (widget); |
351 | + } |
352 | + else |
353 | + { |
354 | + gboolean label_set = FALSE; |
355 | + |
356 | + g_signal_connect (widget, |
357 | + "accel-closures-changed", |
358 | + G_CALLBACK (accel_changed), |
359 | + mi); |
360 | + |
361 | + if (GTK_IS_CHECK_MENU_ITEM (widget)) |
362 | + { |
363 | + dbusmenu_menuitem_property_set (mi, |
364 | + DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, |
365 | + gtk_check_menu_item_get_draw_as_radio (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_RADIO : DBUSMENU_MENUITEM_TOGGLE_CHECK); |
366 | + |
367 | + dbusmenu_menuitem_property_set_int (mi, |
368 | + DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, |
369 | + gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); |
370 | + |
371 | + g_signal_connect (widget, |
372 | + "activate", |
373 | + G_CALLBACK (checkbox_toggled), |
374 | + mi); |
375 | + } |
376 | + |
377 | + if (GTK_IS_IMAGE_MENU_ITEM (widget)) |
378 | + { |
379 | + GtkWidget *image; |
380 | + GtkImageType image_type; |
381 | + |
382 | + image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (widget)); |
383 | + |
384 | + if (GTK_IS_IMAGE (image)) |
385 | + { |
386 | + image_type = gtk_image_get_storage_type (GTK_IMAGE (image)); |
387 | + |
388 | + if (image_type == GTK_IMAGE_STOCK) |
389 | + { |
390 | + label_set = update_stock_item (mi, image); |
391 | + } |
392 | + else if (image_type == GTK_IMAGE_ICON_NAME) |
393 | + { |
394 | + update_icon_name (mi, image); |
395 | + } |
396 | + else if (image_type == GTK_IMAGE_PIXBUF) |
397 | + { |
398 | + dbusmenu_menuitem_property_set_image (mi, |
399 | + DBUSMENU_MENUITEM_PROP_ICON_DATA, |
400 | + gtk_image_get_pixbuf (GTK_IMAGE (image))); |
401 | + } |
402 | + } |
403 | + } |
404 | + |
405 | + GtkWidget *label = find_menu_label (widget); |
406 | + |
407 | + dbusmenu_menuitem_property_set (mi, |
408 | + "label", |
409 | + label ? gtk_label_get_text (GTK_LABEL (label)) : NULL); |
410 | + |
411 | + if (label) |
412 | + { |
413 | + // Sometimes, an app will directly find and modify the label |
414 | + // (like empathy), so watch the label especially for that. |
415 | + g_signal_connect (G_OBJECT (label), |
416 | + "notify", |
417 | + G_CALLBACK (label_notify_cb), |
418 | + mi); |
419 | + } |
420 | + |
421 | + if (GTK_IS_ACTIVATABLE (widget)) |
422 | + { |
423 | + GtkActivatable *activatable = GTK_ACTIVATABLE (widget); |
424 | + |
425 | + if (gtk_activatable_get_use_action_appearance (activatable)) |
426 | + { |
427 | + GtkAction *action = gtk_activatable_get_related_action (activatable); |
428 | + |
429 | + if (action) |
430 | + { |
431 | + visible = gtk_action_is_visible (action); |
432 | + sensitive = gtk_action_is_sensitive (action); |
433 | + |
434 | + g_signal_connect_object (action, "notify", |
435 | + G_CALLBACK (action_notify_cb), |
436 | + mi, |
437 | + G_CONNECT_AFTER); |
438 | + } |
439 | + } |
440 | + } |
441 | + |
442 | + if (!g_object_get_data (G_OBJECT (widget), "gtk-empty-menu-item") && !GTK_IS_TEAROFF_MENU_ITEM (widget)) |
443 | + { |
444 | + visible = gtk_widget_get_visible (widget); |
445 | + sensitive = gtk_widget_get_sensitive (widget); |
446 | + } |
447 | + |
448 | + dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget)); |
449 | + |
450 | + g_signal_connect (G_OBJECT (mi), |
451 | + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, |
452 | + G_CALLBACK (item_activated), |
453 | + widget); |
454 | + |
455 | + g_signal_connect (G_OBJECT (mi), |
456 | + DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW, |
457 | + G_CALLBACK (item_about_to_show), |
458 | + widget); |
459 | + } |
460 | + |
461 | + dbusmenu_menuitem_property_set_bool (mi, |
462 | + DBUSMENU_MENUITEM_PROP_VISIBLE, |
463 | + visible); |
464 | + |
465 | + dbusmenu_menuitem_property_set_bool (mi, |
466 | + DBUSMENU_MENUITEM_PROP_ENABLED, |
467 | + sensitive); |
468 | + |
469 | + g_signal_connect (widget, |
470 | + "notify", |
471 | + G_CALLBACK (widget_notify_cb), |
472 | + mi); |
473 | + return mi; |
474 | + } |
475 | + |
476 | + /* If it's none of those we're going to just create a |
477 | + generic menuitem as a place holder for it. */ |
478 | + return dbusmenu_menuitem_new(); |
479 | +} |
480 | + |
481 | +static void |
482 | +menuitem_notify_cb (GtkWidget *widget, |
483 | + GParamSpec *pspec, |
484 | + gpointer data) |
485 | +{ |
486 | + if (pspec->name == g_intern_static_string ("visible")) |
487 | + { |
488 | + GtkWidget * new_toplevel = gtk_widget_get_toplevel (widget); |
489 | + GtkWidget * old_toplevel = GTK_WIDGET(data); |
490 | + |
491 | + if (new_toplevel == old_toplevel) { |
492 | + /* TODO: Figure this out -> rebuild (context->bridge, window); */ |
493 | + } |
494 | + |
495 | + /* We only care about this once, so let's disconnect now. */ |
496 | + g_signal_handlers_disconnect_by_func (widget, |
497 | + G_CALLBACK (menuitem_notify_cb), |
498 | + data); |
499 | + } |
500 | +} |
501 | + |
502 | +static void |
503 | +accel_changed (GtkWidget *widget, |
504 | + gpointer data) |
505 | +{ |
506 | + DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data; |
507 | + dbusmenu_menuitem_property_set_shortcut_menuitem (mi, GTK_MENU_ITEM (widget)); |
508 | +} |
509 | + |
510 | +static gboolean |
511 | +update_stock_item (DbusmenuMenuitem *menuitem, |
512 | + GtkWidget *widget) |
513 | +{ |
514 | + GtkStockItem stock; |
515 | + GtkImage *image; |
516 | + |
517 | + g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE); |
518 | + |
519 | + image = GTK_IMAGE (widget); |
520 | + |
521 | + if (gtk_image_get_storage_type (image) != GTK_IMAGE_STOCK) |
522 | + return FALSE; |
523 | + |
524 | + gchar * stock_id = NULL; |
525 | + gtk_image_get_stock(image, &stock_id, NULL); |
526 | + |
527 | + gtk_stock_lookup (stock_id, &stock); |
528 | + |
529 | + if (should_show_image (image)) |
530 | + dbusmenu_menuitem_property_set (menuitem, |
531 | + DBUSMENU_MENUITEM_PROP_ICON_NAME, |
532 | + stock_id); |
533 | + else |
534 | + dbusmenu_menuitem_property_remove (menuitem, |
535 | + DBUSMENU_MENUITEM_PROP_ICON_NAME); |
536 | + |
537 | + const gchar *label = dbusmenu_menuitem_property_get (menuitem, |
538 | + DBUSMENU_MENUITEM_PROP_LABEL); |
539 | + |
540 | + if (stock.label != NULL && label != NULL) |
541 | + { |
542 | + dbusmenu_menuitem_property_set (menuitem, |
543 | + DBUSMENU_MENUITEM_PROP_LABEL, |
544 | + stock.label); |
545 | + |
546 | + return TRUE; |
547 | + } |
548 | + |
549 | + return FALSE; |
550 | +} |
551 | + |
552 | +static void |
553 | +checkbox_toggled (GtkWidget *widget, DbusmenuMenuitem *mi) |
554 | +{ |
555 | + dbusmenu_menuitem_property_set_int (mi, |
556 | + DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, |
557 | + gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); |
558 | +} |
559 | + |
560 | +static void |
561 | +update_icon_name (DbusmenuMenuitem *menuitem, |
562 | + GtkWidget *widget) |
563 | +{ |
564 | + GtkImage *image; |
565 | + |
566 | + g_return_if_fail (GTK_IS_IMAGE (widget)); |
567 | + |
568 | + image = GTK_IMAGE (widget); |
569 | + |
570 | + if (gtk_image_get_storage_type (image) != GTK_IMAGE_ICON_NAME) |
571 | + return; |
572 | + |
573 | + if (should_show_image (image)) { |
574 | + const gchar * icon_name = NULL; |
575 | + gtk_image_get_icon_name(image, &icon_name, NULL); |
576 | + dbusmenu_menuitem_property_set (menuitem, |
577 | + DBUSMENU_MENUITEM_PROP_ICON_NAME, |
578 | + icon_name); |
579 | + } else { |
580 | + dbusmenu_menuitem_property_remove (menuitem, |
581 | + DBUSMENU_MENUITEM_PROP_ICON_NAME); |
582 | + } |
583 | +} |
584 | + |
585 | +static GtkWidget * |
586 | +find_menu_label (GtkWidget *widget) |
587 | +{ |
588 | + GtkWidget *label = NULL; |
589 | + |
590 | + if (GTK_IS_LABEL (widget)) |
591 | + return widget; |
592 | + |
593 | + if (GTK_IS_CONTAINER (widget)) |
594 | + { |
595 | + GList *children; |
596 | + GList *l; |
597 | + |
598 | + children = gtk_container_get_children (GTK_CONTAINER (widget)); |
599 | + |
600 | + for (l = children; l; l = l->next) |
601 | + { |
602 | + label = find_menu_label (l->data); |
603 | + |
604 | + if (label) |
605 | + break; |
606 | + } |
607 | + |
608 | + g_list_free (children); |
609 | + } |
610 | + |
611 | + return label; |
612 | +} |
613 | + |
614 | +static void |
615 | +label_notify_cb (GtkWidget *widget, |
616 | + GParamSpec *pspec, |
617 | + gpointer data) |
618 | +{ |
619 | + DbusmenuMenuitem *child = (DbusmenuMenuitem *)data; |
620 | + |
621 | + if (pspec->name == g_intern_static_string ("label")) |
622 | + { |
623 | + dbusmenu_menuitem_property_set (child, |
624 | + DBUSMENU_MENUITEM_PROP_LABEL, |
625 | + gtk_label_get_text (GTK_LABEL (widget))); |
626 | + } |
627 | +} |
628 | + |
629 | +static void |
630 | +action_notify_cb (GtkAction *action, |
631 | + GParamSpec *pspec, |
632 | + gpointer data) |
633 | +{ |
634 | + DbusmenuMenuitem *mi = (DbusmenuMenuitem *)data; |
635 | + |
636 | + if (pspec->name == g_intern_static_string ("sensitive")) |
637 | + { |
638 | + dbusmenu_menuitem_property_set_bool (mi, |
639 | + DBUSMENU_MENUITEM_PROP_ENABLED, |
640 | + gtk_action_is_sensitive (action)); |
641 | + } |
642 | + else if (pspec->name == g_intern_static_string ("visible")) |
643 | + { |
644 | + dbusmenu_menuitem_property_set_bool (mi, |
645 | + DBUSMENU_MENUITEM_PROP_VISIBLE, |
646 | + gtk_action_is_visible (action)); |
647 | + } |
648 | + else if (pspec->name == g_intern_static_string ("active")) |
649 | + { |
650 | + dbusmenu_menuitem_property_set_bool (mi, |
651 | + DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, |
652 | + gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))); |
653 | + } |
654 | + else if (pspec->name == g_intern_static_string ("label")) |
655 | + { |
656 | + dbusmenu_menuitem_property_set (mi, |
657 | + DBUSMENU_MENUITEM_PROP_LABEL, |
658 | + gtk_action_get_label (action)); |
659 | + } |
660 | +} |
661 | + |
662 | +static void |
663 | +item_activated (DbusmenuMenuitem *item, guint timestamp, gpointer user_data) |
664 | +{ |
665 | + GtkWidget *child; |
666 | + |
667 | + if (user_data != NULL) |
668 | + { |
669 | + child = (GtkWidget *)user_data; |
670 | + |
671 | + if (GTK_IS_MENU_ITEM (child)) |
672 | + { |
673 | + gtk_menu_item_activate (GTK_MENU_ITEM (child)); |
674 | + } |
675 | + } |
676 | +} |
677 | + |
678 | +static gboolean |
679 | +item_about_to_show (DbusmenuMenuitem *item, gpointer user_data) |
680 | +{ |
681 | + GtkWidget *child; |
682 | + |
683 | + if (user_data != NULL) |
684 | + { |
685 | + child = (GtkWidget *)user_data; |
686 | + |
687 | + if (GTK_IS_MENU_ITEM (child)) |
688 | + { |
689 | + // Only called for items with submens. So we activate it here in |
690 | + // case the program dynamically creates menus (like empathy does) |
691 | + gtk_menu_item_activate (GTK_MENU_ITEM (child)); |
692 | + } |
693 | + } |
694 | + |
695 | + return TRUE; |
696 | +} |
697 | + |
698 | +static void |
699 | +widget_notify_cb (GtkWidget *widget, |
700 | + GParamSpec *pspec, |
701 | + gpointer data) |
702 | +{ |
703 | + DbusmenuMenuitem *child = (DbusmenuMenuitem *)data; |
704 | + |
705 | + if (pspec->name == g_intern_static_string ("sensitive")) |
706 | + { |
707 | + dbusmenu_menuitem_property_set_bool (child, |
708 | + DBUSMENU_MENUITEM_PROP_ENABLED, |
709 | + gtk_widget_get_sensitive (widget)); |
710 | + } |
711 | + else if (pspec->name == g_intern_static_string ("label")) |
712 | + { |
713 | + dbusmenu_menuitem_property_set (child, |
714 | + DBUSMENU_MENUITEM_PROP_LABEL, |
715 | + gtk_menu_item_get_label (GTK_MENU_ITEM (widget))); |
716 | + } |
717 | + else if (pspec->name == g_intern_static_string ("visible")) |
718 | + { |
719 | + dbusmenu_menuitem_property_set_bool (child, |
720 | + DBUSMENU_MENUITEM_PROP_VISIBLE, |
721 | + gtk_widget_get_visible (widget)); |
722 | + } |
723 | + else if (pspec->name == g_intern_static_string ("stock")) |
724 | + { |
725 | + update_stock_item (child, widget); |
726 | + } |
727 | + else if (pspec->name == g_intern_static_string ("icon-name")) |
728 | + { |
729 | + update_icon_name (child, widget); |
730 | + } |
731 | + else if (pspec->name == g_intern_static_string ("parent")) |
732 | + { |
733 | + /* |
734 | + * We probably should have added a 'remove' method to the |
735 | + * UbuntuMenuProxy early on, but it's late in the cycle now. |
736 | + */ |
737 | + if (gtk_widget_get_parent (widget) == NULL) |
738 | + { |
739 | + g_signal_handlers_disconnect_by_func (widget, |
740 | + G_CALLBACK (widget_notify_cb), |
741 | + child); |
742 | + |
743 | + DbusmenuMenuitem *parent = g_object_get_data (G_OBJECT (child), "dbusmenu-parent"); |
744 | + |
745 | + if (DBUSMENU_IS_MENUITEM (parent) && DBUSMENU_IS_MENUITEM (child)) |
746 | + { |
747 | + dbusmenu_menuitem_child_delete (parent, child); |
748 | + } |
749 | + } |
750 | + } |
751 | +} |
752 | + |
753 | +static gboolean |
754 | +should_show_image (GtkImage *image) |
755 | +{ |
756 | + GtkWidget *item; |
757 | + |
758 | + item = gtk_widget_get_ancestor (GTK_WIDGET (image), |
759 | + GTK_TYPE_IMAGE_MENU_ITEM); |
760 | + |
761 | + if (item) |
762 | + { |
763 | + GtkSettings *settings; |
764 | + gboolean gtk_menu_images; |
765 | + |
766 | + settings = gtk_widget_get_settings (item); |
767 | + |
768 | + g_object_get (settings, "gtk-menu-images", >k_menu_images, NULL); |
769 | + |
770 | + if (gtk_menu_images) |
771 | + return TRUE; |
772 | + |
773 | + return gtk_image_menu_item_get_always_show_image (GTK_IMAGE_MENU_ITEM (item)); |
774 | + } |
775 | + |
776 | + return FALSE; |
777 | +} |
778 | + |
779 | +>>>>>>> MERGE-SOURCE |
780 | |
781 | === modified file 'libdbusmenu-gtk/serializablemenuitem.c' |
782 | --- libdbusmenu-gtk/serializablemenuitem.c 2011-01-27 19:48:12 +0000 |
783 | +++ libdbusmenu-gtk/serializablemenuitem.c 2011-01-27 19:48:12 +0000 |
784 | @@ -166,7 +166,7 @@ |
785 | } |
786 | |
787 | /** |
788 | - dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem: |
789 | + dbusmenu_gtk_serializable_menu_item_build_menuitem: |
790 | @smi: #DbusmenuGtkSerializableMenuItem to build a #DbusmenuMenuitem mirroring |
791 | |
792 | This function is for menu items that are instanciated from |
793 | @@ -179,7 +179,7 @@ |
794 | set by this object. |
795 | */ |
796 | DbusmenuMenuitem * |
797 | -dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi) |
798 | +dbusmenu_gtk_serializable_menu_item_build_menuitem (DbusmenuGtkSerializableMenuItem * smi) |
799 | { |
800 | g_return_val_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi), NULL); |
801 | |
802 | @@ -207,7 +207,7 @@ |
803 | DbusmenuGtkSerializableMenuItem * smi = DBUSMENU_GTK_SERIALIZABLE_MENU_ITEM(g_object_new(th->type, NULL)); |
804 | g_return_val_if_fail(smi != NULL, FALSE); |
805 | |
806 | - dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem(smi, newitem); |
807 | + dbusmenu_gtk_serializable_menu_item_set_menuitem(smi, newitem); |
808 | dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(smi), parent); |
809 | |
810 | return TRUE; |
811 | @@ -265,7 +265,7 @@ |
812 | } |
813 | |
814 | /** |
815 | - dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem: |
816 | + dbusmenu_gtk_serializable_menu_item_set_menuitem: |
817 | @smi: #DbusmenuGtkSerializableMenuItem to set the @DbusmenuGtkSerializableMenuItem::dbusmenu-menuitem of |
818 | @mi: Menuitem to get the properties from |
819 | |
820 | @@ -276,7 +276,7 @@ |
821 | pick up this property being set. |
822 | */ |
823 | void |
824 | -dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi) |
825 | +dbusmenu_gtk_serializable_menu_item_set_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi) |
826 | { |
827 | g_return_if_fail(DBUSMENU_IS_GTK_SERIALIZABLE_MENU_ITEM(smi)); |
828 | g_return_if_fail(mi != NULL); |
829 | |
830 | === modified file 'libdbusmenu-gtk/serializablemenuitem.h' |
831 | --- libdbusmenu-gtk/serializablemenuitem.h 2011-01-27 19:48:12 +0000 |
832 | +++ libdbusmenu-gtk/serializablemenuitem.h 2011-01-27 19:48:12 +0000 |
833 | @@ -90,6 +90,13 @@ |
834 | DbusmenuGtkSerializableMenuItem: |
835 | @parent: Inherit from GtkMenuItem |
836 | @priv: Blind structure of private variables |
837 | + |
838 | + The Serializable Menuitem provides a way for menu items to be created |
839 | + that can easily be picked up by the Dbusmenu GTK Parser. This way |
840 | + you can create custom items, and transport them across dbusmenu to |
841 | + your menus or the appmenu on the other side of the bus. By providing |
842 | + these function the parser has enough information to both serialize, and |
843 | + deserialize on the other side, the menuitem you've so carefully created. |
844 | */ |
845 | struct _DbusmenuGtkSerializableMenuItem { |
846 | GtkMenuItem parent; |
847 | @@ -99,9 +106,9 @@ |
848 | |
849 | GType dbusmenu_gtk_serializable_menu_item_get_type (void); |
850 | |
851 | -DbusmenuMenuitem * dbusmenu_gtk_serializable_menu_item_build_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi); |
852 | +DbusmenuMenuitem * dbusmenu_gtk_serializable_menu_item_build_menuitem (DbusmenuGtkSerializableMenuItem * smi); |
853 | void dbusmenu_gtk_serializable_menu_item_register_to_client (DbusmenuClient * client, GType item_type); |
854 | -void dbusmenu_gtk_serializable_menu_item_set_dbusmenu_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi); |
855 | +void dbusmenu_gtk_serializable_menu_item_set_menuitem (DbusmenuGtkSerializableMenuItem * smi, DbusmenuMenuitem * mi); |
856 | |
857 | G_END_DECLS |
858 |
How does this branch relate to https:/ /code.launchpad .net/~ted/ dbusmenu/ serializable- menuitem/ +merge/ 47604 ? They look identical?