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