Merge lp:~ted/libdbusmenu/group-prop-change-signals into lp:libdbusmenu/0.5
- group-prop-change-signals
- Merge into trunk
Proposed by
Ted Gould
Status: | Merged |
---|---|
Merged at revision: | 212 |
Proposed branch: | lp:~ted/libdbusmenu/group-prop-change-signals |
Merge into: | lp:libdbusmenu/0.5 |
Diff against target: |
1207 lines (+539/-231) 9 files modified
configure.ac (+3/-7) libdbusmenu-glib/client.c (+108/-80) libdbusmenu-glib/dbus-menu.xml (+46/-63) libdbusmenu-glib/menuitem-private.h (+3/-2) libdbusmenu-glib/menuitem.c (+49/-15) libdbusmenu-glib/menuitem.h (+6/-5) libdbusmenu-glib/server.c (+319/-58) tests/json-loader.c (+0/-1) tests/test-glib-layout-client.c (+5/-0) |
To merge this branch: | bzr merge lp:~ted/libdbusmenu/group-prop-change-signals |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
DBus Menu Team | Pending | ||
Review via email: mp+49849@code.launchpad.net |
This proposal supersedes a proposal from 2011-02-15.
Commit message
Description of the change
Makes it so that the property update signals are all aggregated into a single larger message so that we don't send as much dbus traffic.
This also includes the no-xml. They got merged together and I don't know how to get LP to take them back appart. Here's the message from that one:
Removes the XML from the GetLayout function and instead replaces it with a recursive DBus data type. Can get large.
Some notes:
* This is the basic feature, things like the properties aren't currently used
* There is no default handling so there is only a stub there for now, that's a future branch
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'configure.ac' |
2 | --- configure.ac 2011-02-10 20:15:31 +0000 |
3 | +++ configure.ac 2011-02-15 18:02:06 +0000 |
4 | @@ -42,11 +42,9 @@ |
5 | ########################### |
6 | |
7 | GLIB_REQUIRED_VERSION=2.26 |
8 | -XML_REQUIRED_VERSION=2.6 |
9 | |
10 | PKG_CHECK_MODULES(DBUSMENUGLIB, glib-2.0 >= $GLIB_REQUIRED_VERSION |
11 | - gio-2.0 >= $GLIB_REQUIRED_VERSION |
12 | - libxml-2.0 >= $XML_REQUIRED_VERSION) |
13 | + gio-2.0 >= $GLIB_REQUIRED_VERSION) |
14 | |
15 | AC_SUBST(DBUSMENUGLIB_CFLAGS) |
16 | AC_SUBST(DBUSMENUGLIB_LIBS) |
17 | @@ -65,16 +63,14 @@ |
18 | [with_gtk=2]) |
19 | AS_IF([test "x$with_gtk" = x3], |
20 | [PKG_CHECK_MODULES(DBUSMENUGTK, gtk+-3.0 >= $GTK3_REQUIRED_VERSION |
21 | - glib-2.0 >= $GLIB_REQUIRED_VERSION |
22 | - libxml-2.0 >= $XML_REQUIRED_VERSION) |
23 | + glib-2.0 >= $GLIB_REQUIRED_VERSION) |
24 | AC_SUBST(DBUSMENUGTK_CFLAGS) |
25 | AC_SUBST(DBUSMENUGTK_LIBS) |
26 | AC_DEFINE(HAVE_GTK3, 1, [whether gtk3 is available]) |
27 | ], |
28 | [test "x$with_gtk" = x2], |
29 | [PKG_CHECK_MODULES(DBUSMENUGTK, gtk+-2.0 >= $GTK_REQUIRED_VERSION |
30 | - glib-2.0 >= $GLIB_REQUIRED_VERSION |
31 | - libxml-2.0 >= $XML_REQUIRED_VERSION) |
32 | + glib-2.0 >= $GLIB_REQUIRED_VERSION) |
33 | AC_SUBST(DBUSMENUGTK_CFLAGS) |
34 | AC_SUBST(DBUSMENUGTK_LIBS) |
35 | ], |
36 | |
37 | === modified file 'libdbusmenu-glib/client.c' |
38 | --- libdbusmenu-glib/client.c 2011-01-31 16:48:21 +0000 |
39 | +++ libdbusmenu-glib/client.c 2011-02-15 18:02:06 +0000 |
40 | @@ -32,9 +32,6 @@ |
41 | |
42 | #include <gio/gio.h> |
43 | |
44 | -#include <libxml/parser.h> |
45 | -#include <libxml/tree.h> |
46 | - |
47 | #include "client.h" |
48 | #include "menuitem.h" |
49 | #include "menuitem-private.h" |
50 | @@ -151,9 +148,8 @@ |
51 | static void id_prop_update (GDBusProxy * proxy, gint id, gchar * property, GVariant * value, DbusmenuClient * client); |
52 | static void id_update (GDBusProxy * proxy, gint id, DbusmenuClient * client); |
53 | static void build_proxies (DbusmenuClient * client); |
54 | -static gint parse_node_get_id (xmlNodePtr node); |
55 | -static DbusmenuMenuitem * parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * item, DbusmenuMenuitem * parent, GDBusProxy * proxy); |
56 | -static gint parse_layout (DbusmenuClient * client, const gchar * layout); |
57 | +static DbusmenuMenuitem * parse_layout_xml(DbusmenuClient * client, GVariant * layout, DbusmenuMenuitem * item, DbusmenuMenuitem * parent, GDBusProxy * proxy); |
58 | +static gint parse_layout (DbusmenuClient * client, GVariant * layout); |
59 | static void update_layout_cb (GObject * proxy, GAsyncResult * res, gpointer data); |
60 | static void update_layout (DbusmenuClient * client); |
61 | static void menuitem_get_properties_cb (GVariant * properties, GError * error, gpointer data); |
62 | @@ -1030,11 +1026,60 @@ |
63 | { |
64 | g_return_if_fail(DBUSMENU_IS_CLIENT(user_data)); |
65 | DbusmenuClient * client = DBUSMENU_CLIENT(user_data); |
66 | + DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client); |
67 | |
68 | if (g_strcmp0(signal, "LayoutUpdated") == 0) { |
69 | guint revision; gint parent; |
70 | g_variant_get(params, "(ui)", &revision, &parent); |
71 | layout_update(proxy, revision, parent, client); |
72 | + } else if (priv->root == NULL) { |
73 | + /* Drop out here, all the rest of these really need to have a root |
74 | + node so we can just ignore them if there isn't one. */ |
75 | + } else if (g_strcmp0(signal, "ItemPropertiesUpdated") == 0) { |
76 | + /* Remove before adding just incase there is a duplicate, against the |
77 | + rules, but we can handle it so let's do it. */ |
78 | + GVariantIter ritems; |
79 | + g_variant_iter_init(&ritems, g_variant_get_child_value(params, 1)); |
80 | + |
81 | + GVariant * ritem; |
82 | + while ((ritem = g_variant_iter_next_value(&ritems)) != NULL) { |
83 | + gint id = g_variant_get_int32(g_variant_get_child_value(ritem, 0)); |
84 | + DbusmenuMenuitem * menuitem = dbusmenu_menuitem_find_id(priv->root, id); |
85 | + |
86 | + if (menuitem == NULL) { |
87 | + continue; |
88 | + } |
89 | + |
90 | + GVariantIter properties; |
91 | + g_variant_iter_init(&properties, g_variant_get_child_value(ritem, 1)); |
92 | + gchar * property; |
93 | + |
94 | + while (g_variant_iter_next(&properties, "s", &property)) { |
95 | + g_debug("Removing property '%s' on %d", property, id); |
96 | + dbusmenu_menuitem_property_remove(menuitem, property); |
97 | + } |
98 | + } |
99 | + |
100 | + GVariantIter items; |
101 | + g_variant_iter_init(&items, g_variant_get_child_value(params, 0)); |
102 | + |
103 | + GVariant * item; |
104 | + while ((item = g_variant_iter_next_value(&items)) != NULL) { |
105 | + gint id = g_variant_get_int32(g_variant_get_child_value(item, 0)); |
106 | + GVariantIter properties; |
107 | + g_variant_iter_init(&properties, g_variant_get_child_value(item, 1)); |
108 | + gchar * property; |
109 | + GVariant * value; |
110 | + |
111 | + while (g_variant_iter_next(&properties, "{sv}", &property, &value)) { |
112 | + GVariant * internalvalue = value; |
113 | + if (G_LIKELY(g_variant_is_of_type(value, G_VARIANT_TYPE_VARIANT))) { |
114 | + /* Unboxing if needed */ |
115 | + internalvalue = g_variant_get_variant(value); |
116 | + } |
117 | + id_prop_update(proxy, id, property, internalvalue, client); |
118 | + } |
119 | + } |
120 | } else if (g_strcmp0(signal, "ItemPropertyUpdated") == 0) { |
121 | gint id; gchar * property; GVariant * value; |
122 | g_variant_get(params, "(isv)", &id, &property, &value); |
123 | @@ -1054,40 +1099,6 @@ |
124 | return; |
125 | } |
126 | |
127 | -/* Get the ID attribute of the node, parse it and |
128 | - return it. Also we're checking to ensure the node |
129 | - is a 'menu' here. */ |
130 | -static gint |
131 | -parse_node_get_id (xmlNodePtr node) |
132 | -{ |
133 | - if (node == NULL) { |
134 | - return -1; |
135 | - } |
136 | - if (node->type != XML_ELEMENT_NODE) { |
137 | - return -1; |
138 | - } |
139 | - if (g_strcmp0((gchar *)node->name, "menu") != 0) { |
140 | - /* This kills some nodes early */ |
141 | - g_warning("XML Node is not 'menu' it is '%s'", node->name); |
142 | - return -1; |
143 | - } |
144 | - |
145 | - xmlAttrPtr attrib; |
146 | - for (attrib = node->properties; attrib != NULL; attrib = attrib->next) { |
147 | - if (g_strcmp0((gchar *)attrib->name, "id") == 0) { |
148 | - if (attrib->children != NULL) { |
149 | - gint id = (guint)g_ascii_strtoll((gchar *)attrib->children->content, NULL, 10); |
150 | - /* g_debug ("Found ID: %d", id); */ |
151 | - return id; |
152 | - } |
153 | - break; |
154 | - } |
155 | - } |
156 | - |
157 | - g_warning("Unable to find an ID on the node"); |
158 | - return -1; |
159 | -} |
160 | - |
161 | /* This is the callback for the properties on a menu item. There |
162 | should be all of them in the Hash, and they we use foreach to |
163 | copy them into the menuitem. |
164 | @@ -1265,7 +1276,7 @@ |
165 | edata->event = g_strdup(name); |
166 | edata->timestamp = timestamp; |
167 | edata->variant = variant; |
168 | - g_variant_ref(variant); |
169 | + g_variant_ref_sink(variant); |
170 | |
171 | g_dbus_proxy_call(priv->menuproxy, |
172 | "Event", |
173 | @@ -1390,10 +1401,14 @@ |
174 | /* Parse recursively through the XML and make it into |
175 | objects as need be */ |
176 | static DbusmenuMenuitem * |
177 | -parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * item, DbusmenuMenuitem * parent, GDBusProxy * proxy) |
178 | +parse_layout_xml(DbusmenuClient * client, GVariant * layout, DbusmenuMenuitem * item, DbusmenuMenuitem * parent, GDBusProxy * proxy) |
179 | { |
180 | + if (layout == NULL) { |
181 | + return NULL; |
182 | + } |
183 | + |
184 | /* First verify and figure out what we've got */ |
185 | - gint id = parse_node_get_id(node); |
186 | + gint id = g_variant_get_int32(g_variant_get_child_value(layout, 0)); |
187 | if (id < 0) { |
188 | return NULL; |
189 | } |
190 | @@ -1405,20 +1420,26 @@ |
191 | g_return_val_if_fail(id == dbusmenu_menuitem_get_id(item), NULL); |
192 | |
193 | /* Some variables */ |
194 | - xmlNodePtr children; |
195 | - guint position; |
196 | + GVariantIter children; |
197 | + g_variant_iter_init(&children, g_variant_get_child_value(layout, 2)); |
198 | + GVariant * child; |
199 | + |
200 | + guint position = 0; |
201 | GList * oldchildren = g_list_copy(dbusmenu_menuitem_get_children(item)); |
202 | /* g_debug("Starting old children: %d", g_list_length(oldchildren)); */ |
203 | |
204 | /* Go through all the XML Nodes and make sure that we have menuitems |
205 | to cover those XML nodes. */ |
206 | - for (children = node->children, position = 0; children != NULL; children = children->next, position++) { |
207 | + while ((child = g_variant_iter_next_value(&children)) != NULL) { |
208 | /* g_debug("Looking at child: %d", position); */ |
209 | - gint childid = parse_node_get_id(children); |
210 | + if (g_variant_is_of_type(child, G_VARIANT_TYPE_VARIANT)) { |
211 | + child = g_variant_get_variant(child); |
212 | + } |
213 | + |
214 | + gint childid = g_variant_get_int32(g_variant_get_child_value(child, 0)); |
215 | if (childid < 0) { |
216 | /* Don't increment the position when there isn't a valid |
217 | node in the XML tree. It's probably a comment. */ |
218 | - position--; |
219 | continue; |
220 | } |
221 | DbusmenuMenuitem * childmi = NULL; |
222 | @@ -1451,6 +1472,8 @@ |
223 | dbusmenu_menuitem_child_reorder(item, childmi, position); |
224 | parse_layout_update(childmi, client); |
225 | } |
226 | + |
227 | + position++; |
228 | } |
229 | |
230 | /* Remove any children that are no longer used by this version of |
231 | @@ -1473,14 +1496,20 @@ |
232 | } |
233 | |
234 | /* now it's time to recurse down the tree. */ |
235 | - children = node->children; |
236 | + g_variant_iter_init(&children, g_variant_get_child_value(layout, 2)); |
237 | + |
238 | + child = g_variant_iter_next_value(&children); |
239 | GList * childmis = dbusmenu_menuitem_get_children(item); |
240 | - while (children != NULL && childmis != NULL) { |
241 | - gint xmlid = parse_node_get_id(children); |
242 | + while (child != NULL && childmis != NULL) { |
243 | + if (g_variant_is_of_type(child, G_VARIANT_TYPE_VARIANT)) { |
244 | + child = g_variant_get_variant(child); |
245 | + } |
246 | + |
247 | + gint xmlid = g_variant_get_int32(g_variant_get_child_value(child, 0)); |
248 | /* If this isn't a valid menu item we need to move on |
249 | until we have one. This avoids things like comments. */ |
250 | if (xmlid < 0) { |
251 | - children = children->next; |
252 | + child = g_variant_iter_next_value(&children); |
253 | continue; |
254 | } |
255 | |
256 | @@ -1489,13 +1518,14 @@ |
257 | g_debug("Recursing parse_layout_xml. XML ID: %d MI ID: %d", xmlid, miid); |
258 | #endif |
259 | |
260 | - parse_layout_xml(client, children, DBUSMENU_MENUITEM(childmis->data), item, proxy); |
261 | + parse_layout_xml(client, child, DBUSMENU_MENUITEM(childmis->data), item, proxy); |
262 | |
263 | - children = children->next; |
264 | + child = g_variant_iter_next_value(&children); |
265 | childmis = g_list_next(childmis); |
266 | } |
267 | - if (children != NULL) { |
268 | - g_warning("Sync failed, now we've got extra XML nodes."); |
269 | + |
270 | + if (child != NULL) { |
271 | + g_warning("Sync failed, now we've got extra layout nodes."); |
272 | } |
273 | if (childmis != NULL) { |
274 | g_warning("Sync failed, now we've got extra menu items."); |
275 | @@ -1507,7 +1537,7 @@ |
276 | /* Take the layout passed to us over DBus and turn it into |
277 | a set of beautiful objects */ |
278 | static gint |
279 | -parse_layout (DbusmenuClient * client, const gchar * layout) |
280 | +parse_layout (DbusmenuClient * client, GVariant * layout) |
281 | { |
282 | #ifdef MASSIVEDEBUGGING |
283 | g_debug("Client Parsing a new layout"); |
284 | @@ -1515,17 +1545,6 @@ |
285 | |
286 | DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client); |
287 | |
288 | - xmlDocPtr xmldoc; |
289 | - |
290 | - /* No one should need more characters than this! */ |
291 | - xmldoc = xmlReadMemory(layout, g_utf8_strlen(layout, 1024*1024), "dbusmenu.xml", NULL, 0); |
292 | - |
293 | - xmlNodePtr root = xmlDocGetRootElement(xmldoc); |
294 | - |
295 | - if (root == NULL) { |
296 | - g_warning("Unable to get root node of menu XML"); |
297 | - } |
298 | - |
299 | DbusmenuMenuitem * oldroot = priv->root; |
300 | |
301 | if (priv->root == NULL) { |
302 | @@ -1534,11 +1553,10 @@ |
303 | parse_layout_update(priv->root, client); |
304 | } |
305 | |
306 | - priv->root = parse_layout_xml(client, root, priv->root, NULL, priv->menuproxy); |
307 | - xmlFreeDoc(xmldoc); |
308 | + priv->root = parse_layout_xml(client, layout, priv->root, NULL, priv->menuproxy); |
309 | |
310 | if (priv->root == NULL) { |
311 | - g_warning("Unable to parse layout on client %s object %s: %s", priv->dbus_name, priv->dbus_object, layout); |
312 | + g_warning("Unable to parse layout on client %s object %s: %s", priv->dbus_name, priv->dbus_object, g_variant_print(layout, TRUE)); |
313 | } |
314 | |
315 | if (priv->root != oldroot) { |
316 | @@ -1579,14 +1597,10 @@ |
317 | goto out; |
318 | } |
319 | |
320 | - guint rev; |
321 | - gchar * xml; |
322 | - |
323 | - g_variant_get(params, "(us)", &rev, &xml); |
324 | - g_variant_unref(params); |
325 | - |
326 | - guint parseable = parse_layout(client, xml); |
327 | - g_free(xml); |
328 | + guint rev = g_variant_get_uint32(g_variant_get_child_value(params, 0)); |
329 | + GVariant * layout = g_variant_get_child_value(params, 1); |
330 | + |
331 | + guint parseable = parse_layout(client, layout); |
332 | |
333 | if (parseable == 0) { |
334 | g_warning("Unable to parse layout!"); |
335 | @@ -1612,6 +1626,10 @@ |
336 | priv->layoutcall = NULL; |
337 | } |
338 | |
339 | + if (params != NULL) { |
340 | + g_variant_unref(params); |
341 | + } |
342 | + |
343 | g_object_unref(G_OBJECT(client)); |
344 | return; |
345 | } |
346 | @@ -1639,10 +1657,20 @@ |
347 | |
348 | priv->layoutcall = g_cancellable_new(); |
349 | |
350 | + GVariantBuilder tupleb; |
351 | + g_variant_builder_init(&tupleb, G_VARIANT_TYPE_TUPLE); |
352 | + |
353 | + g_variant_builder_add_value(&tupleb, g_variant_new_int32(0)); // root |
354 | + g_variant_builder_add_value(&tupleb, g_variant_new_int32(-1)); // recurse |
355 | + g_variant_builder_add_value(&tupleb, g_variant_new_array(G_VARIANT_TYPE_STRING, NULL, 0)); // props |
356 | + |
357 | + GVariant * args = g_variant_builder_end(&tupleb); |
358 | + // g_debug("Args (type: %s): %s", g_variant_get_type_string(args), g_variant_print(args, TRUE)); |
359 | + |
360 | g_object_ref(G_OBJECT(client)); |
361 | g_dbus_proxy_call(priv->menuproxy, |
362 | "GetLayout", |
363 | - g_variant_new("(i)", 0), /* root */ |
364 | + args, |
365 | G_DBUS_CALL_FLAGS_NONE, |
366 | -1, /* timeout */ |
367 | priv->layoutcall, /* cancellable */ |
368 | |
369 | === modified file 'libdbusmenu-glib/dbus-menu.xml' |
370 | --- libdbusmenu-glib/dbus-menu.xml 2011-01-13 15:53:15 +0000 |
371 | +++ libdbusmenu-glib/dbus-menu.xml 2011-02-15 18:02:06 +0000 |
372 | @@ -174,34 +174,38 @@ |
373 | <!-- Functions --> |
374 | |
375 | <method name="GetLayout"> |
376 | - <dox:d><![CDATA[ |
377 | - Provides an XML representation of the menu hierarchy |
378 | - |
379 | - XML syntax: |
380 | - |
381 | - @verbatim |
382 | -<menu id="0"> # Root container |
383 | - <menu id="1"> # First level menu, for example "File" |
384 | - <menu id="2"/> ~ Second level menu, for example "Open" |
385 | - <menu id="3"/> |
386 | - ... |
387 | - </menu> |
388 | - <menu id="4"> # Another first level menu, say "Edit" |
389 | - ... |
390 | - </menu> |
391 | - ... |
392 | -</menu> |
393 | - @endverbatim |
394 | - ]]></dox:d> |
395 | + <dox:d> |
396 | + Provides the layout and propertiers that are attached to the entries |
397 | + that are in the layout. It only gives the items that are children |
398 | + of the item that is specified in @parentId. It will return all of the |
399 | + properties or specific ones depending of the value in @propertyNames. |
400 | + |
401 | + The format is recursive, where the second 'v' is in the same format |
402 | + as the original 'a(ia(sv)a(v))'. If the @recursive flag is set to |
403 | + less than one then the second array will have zero entries. |
404 | + </dox:d> |
405 | <arg type="i" name="parentId" direction="in"> |
406 | <dox:d>The ID of the parent node for the layout. For |
407 | grabbing the layout from the root node use zero.</dox:d> |
408 | </arg> |
409 | + <arg type="i" name="recurse" direction="in"> |
410 | + <dox:d> |
411 | + The amount of levels of recursion to use. -1, as value would |
412 | + deliver all the items under the @parentId. |
413 | + </dox:d> |
414 | + </arg> |
415 | + <arg type="as" name="propertyNames" direction="in" > |
416 | + <dox:d> |
417 | + The list of item properties we are |
418 | + interested in. If there are no entries in the list all of |
419 | + the properties will be sent. |
420 | + </dox:d> |
421 | + </arg> |
422 | <arg type="u" name="revision" direction="out"> |
423 | <dox:d>The revision number of the layout. For matching |
424 | with layoutUpdated signals.</dox:d> |
425 | </arg> |
426 | - <arg type="s" name="layout" direction="out"> |
427 | + <arg type="(ia{sv}av)" name="layout" direction="out"> |
428 | <dox:d>The layout as an XML string of IDs.</dox:d> |
429 | </arg> |
430 | </method> |
431 | @@ -236,33 +240,21 @@ |
432 | </arg> |
433 | </method> |
434 | |
435 | - <method name="GetChildren"> |
436 | - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="DBusMenuItemList"/> |
437 | - <arg type="i" name="id" direction="in" /> |
438 | - <arg type="as" name="propertyNames" direction="in" /> |
439 | - <arg type="a(ia{sv})" name="properties" direction="out" /> |
440 | - </method> |
441 | - |
442 | <method name="GetProperty"> |
443 | - <arg type="i" name="id" direction="in" /> |
444 | - <arg type="s" name="name" direction="in" /> |
445 | - <arg type="v" name="value" direction="out" /> |
446 | - </method> |
447 | - |
448 | - <method name="GetProperties"> |
449 | <dox:d> |
450 | - Returns multiple properties in one call. This is more efficient than |
451 | - GetProperty. |
452 | - |
453 | + Get a signal property on a single item. This is not useful if you're |
454 | + going to implement this interface, it should only be used if you're |
455 | + debugging via a commandline tool. |
456 | </dox:d> |
457 | - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/> |
458 | - <arg type="i" name="id" direction="in" > |
459 | - <dox:d>The item whose properties we want to retrieve.</dox:d> |
460 | - </arg> |
461 | - <arg type="as" name="propertyNames" direction="in" > |
462 | - <dox:d>List of string name of the properties we want. If the list contains no entries, all properties are sent.</dox:d> |
463 | - </arg> |
464 | - <arg type="a{sv}" name="properties" direction="out" /> |
465 | + <arg type="i" name="id" direction="in"> |
466 | + <dox:d>the id of the item which received the event</dox:d> |
467 | + </arg> |
468 | + <arg type="s" name="name" direction="in"> |
469 | + <dox:d>the name of the property to get</dox:d> |
470 | + </arg> |
471 | + <arg type="v" name="value" direction="out"> |
472 | + <dox:d>the value of the property</dox:d> |
473 | + </arg> |
474 | </method> |
475 | |
476 | <method name="Event"> |
477 | @@ -309,25 +301,16 @@ |
478 | </method> |
479 | |
480 | <!-- Signals --> |
481 | - <signal name="ItemPropertyUpdated"> |
482 | - <dox:d> |
483 | - Triggered by the application to notify the applet that the property @a property |
484 | - from item @a id has changed to @a value. |
485 | - </dox:d> |
486 | - <arg type="i" name="id" direction="out" /> |
487 | - <arg type="s" name="prop" direction="out" /> |
488 | - <arg type="v" name="value" direction="out" /> |
489 | - </signal> |
490 | - |
491 | - <signal name="ItemUpdated"> |
492 | - <dox:d> |
493 | - Triggered by the application to notify the applet that all properties of item |
494 | - </dox:d> |
495 | - <arg type="i" name="id" direction="out" > |
496 | - <dox:d>id which should be considered outdated</dox:d> |
497 | - </arg> |
498 | - </signal> |
499 | - |
500 | + <signal name="ItemsPropertiesUpdated"> |
501 | + <dox:d> |
502 | + Triggered when there are lots of property updates across many items |
503 | + so they all get grouped into a single dbus message. The format is |
504 | + the ID of the item with a hashtable of names and values for those |
505 | + properties. |
506 | + </dox:d> |
507 | + <arg type="a(ia(sv))" name="props" direction="out" /> |
508 | + <arg type="a(ia(s))" name="props_removed" direction="out" /> |
509 | + </signal> |
510 | <signal name="LayoutUpdated"> |
511 | <dox:d> |
512 | Triggered by the application to notify display of a layout update, up to |
513 | |
514 | === modified file 'libdbusmenu-glib/menuitem-private.h' |
515 | --- libdbusmenu-glib/menuitem-private.h 2010-10-14 21:00:38 +0000 |
516 | +++ libdbusmenu-glib/menuitem-private.h 2011-02-15 18:02:06 +0000 |
517 | @@ -33,10 +33,11 @@ |
518 | |
519 | G_BEGIN_DECLS |
520 | |
521 | -void dbusmenu_menuitem_buildxml (DbusmenuMenuitem * mi, GPtrArray * array); |
522 | +GVariant * dbusmenu_menuitem_build_variant (DbusmenuMenuitem * mi, const gchar ** properties, gint recurse); |
523 | gboolean dbusmenu_menuitem_realized (DbusmenuMenuitem * mi); |
524 | void dbusmenu_menuitem_set_realized (DbusmenuMenuitem * mi); |
525 | -GVariant * dbusmenu_menuitem_properties_variant (DbusmenuMenuitem * mi); |
526 | +GVariant * dbusmenu_menuitem_properties_variant (DbusmenuMenuitem * mi, const gchar ** properties); |
527 | +gboolean dbusmenu_menuitem_property_is_default (DbusmenuMenuitem * mi, const gchar * property); |
528 | |
529 | G_END_DECLS |
530 | |
531 | |
532 | === modified file 'libdbusmenu-glib/menuitem.c' |
533 | --- libdbusmenu-glib/menuitem.c 2011-02-04 17:00:07 +0000 |
534 | +++ libdbusmenu-glib/menuitem.c 2011-02-15 18:02:06 +0000 |
535 | @@ -1009,7 +1009,7 @@ |
536 | |
537 | if (value != NULL) { |
538 | gchar * lprop = g_strdup(property); |
539 | - g_variant_ref(value); |
540 | + g_variant_ref_sink(value); |
541 | |
542 | if (currentval == NULL || !g_variant_equal((GVariant*)currentval, value)) { |
543 | g_hash_table_replace(priv->properties, lprop, value); |
544 | @@ -1213,7 +1213,7 @@ |
545 | GHashTable * table = (GHashTable *)in_data; |
546 | gchar * key = (gchar *)in_key; |
547 | GVariant * value = (GVariant *)in_value; |
548 | - g_variant_ref(value); |
549 | + g_variant_ref_sink(value); |
550 | g_hash_table_insert(table, g_strdup(key), value); |
551 | return; |
552 | } |
553 | @@ -1250,7 +1250,9 @@ |
554 | static void |
555 | variant_helper (gpointer in_key, gpointer in_value, gpointer user_data) |
556 | { |
557 | - g_variant_builder_add((GVariantBuilder *)user_data, "{sv}", in_key, in_value); |
558 | + GVariant * value = g_variant_new_dict_entry(g_variant_new_string((gchar *)in_key), |
559 | + g_variant_new_variant((GVariant *)in_value)); |
560 | + g_variant_builder_add_value((GVariantBuilder *)user_data, value); |
561 | return; |
562 | } |
563 | |
564 | @@ -1264,7 +1266,7 @@ |
565 | Return Value: A GVariant of type "a{sv}" or NULL on error. |
566 | */ |
567 | GVariant * |
568 | -dbusmenu_menuitem_properties_variant (DbusmenuMenuitem * mi) |
569 | +dbusmenu_menuitem_properties_variant (DbusmenuMenuitem * mi, const gchar ** properties) |
570 | { |
571 | g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), NULL); |
572 | |
573 | @@ -1274,7 +1276,7 @@ |
574 | |
575 | if (g_hash_table_size(priv->properties) > 0) { |
576 | GVariantBuilder builder; |
577 | - g_variant_builder_init(&builder, g_variant_type_new("a{sv}")); |
578 | + g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); |
579 | |
580 | g_hash_table_foreach(priv->properties, variant_helper, &builder); |
581 | |
582 | @@ -1322,7 +1324,7 @@ |
583 | |
584 | |
585 | /** |
586 | - dbusmenu_menuitem_buildxml: |
587 | + dbusmenu_menuitem_buildvariant: |
588 | @mi: #DbusmenuMenuitem to represent in XML |
589 | @array: (element-type utf8): A list of string that will be turned into an XML file |
590 | |
591 | @@ -1332,28 +1334,50 @@ |
592 | start tag and one that is a closing tag. It will allow it's |
593 | children to place their own tags in the array in between those two. |
594 | */ |
595 | -void |
596 | -dbusmenu_menuitem_buildxml (DbusmenuMenuitem * mi, GPtrArray * array) |
597 | +GVariant * |
598 | +dbusmenu_menuitem_build_variant (DbusmenuMenuitem * mi, const gchar ** properties, gint recurse) |
599 | { |
600 | - g_return_if_fail(DBUSMENU_IS_MENUITEM(mi)); |
601 | + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), NULL); |
602 | |
603 | gint id = 0; |
604 | if (!dbusmenu_menuitem_get_root(mi)) { |
605 | id = dbusmenu_menuitem_get_id(mi); |
606 | } |
607 | |
608 | + /* This is the tuple that'll build up being a representation of |
609 | + this entry */ |
610 | + GVariantBuilder tupleb; |
611 | + g_variant_builder_init(&tupleb, G_VARIANT_TYPE_TUPLE); |
612 | + |
613 | + /* Add our ID */ |
614 | + g_variant_builder_add_value(&tupleb, g_variant_new_int32(id)); |
615 | + |
616 | + /* Figure out the properties */ |
617 | + GVariant * props = dbusmenu_menuitem_properties_variant(mi, properties); |
618 | + if (props != NULL) { |
619 | + g_variant_builder_add_value(&tupleb, props); |
620 | + } else { |
621 | + g_variant_builder_add_value(&tupleb, g_variant_parse(G_VARIANT_TYPE("a{sv}"), "[ ]", NULL, NULL, NULL)); |
622 | + } |
623 | + |
624 | + /* Pillage the children */ |
625 | GList * children = dbusmenu_menuitem_get_children(mi); |
626 | - if (children == NULL) { |
627 | - g_ptr_array_add(array, g_strdup_printf("<menu id=\"%d\"/>", id)); |
628 | + if (children == NULL && recurse != 0) { |
629 | + g_variant_builder_add_value(&tupleb, g_variant_new_array(G_VARIANT_TYPE_VARIANT, NULL, 0)); |
630 | } else { |
631 | - g_ptr_array_add(array, g_strdup_printf("<menu id=\"%d\">", id)); |
632 | + GVariantBuilder childrenbuilder; |
633 | + g_variant_builder_init(&childrenbuilder, G_VARIANT_TYPE_ARRAY); |
634 | + |
635 | for ( ; children != NULL; children = children->next) { |
636 | - dbusmenu_menuitem_buildxml(DBUSMENU_MENUITEM(children->data), array); |
637 | + GVariant * child = dbusmenu_menuitem_build_variant(DBUSMENU_MENUITEM(children->data), properties, recurse - 1); |
638 | + |
639 | + g_variant_builder_add_value(&childrenbuilder, g_variant_new_variant(child)); |
640 | } |
641 | - g_ptr_array_add(array, g_strdup("</menu>")); |
642 | + |
643 | + g_variant_builder_add_value(&tupleb, g_variant_builder_end(&childrenbuilder)); |
644 | } |
645 | |
646 | - return; |
647 | + return g_variant_builder_end(&tupleb); |
648 | } |
649 | |
650 | typedef struct { |
651 | @@ -1473,3 +1497,13 @@ |
652 | |
653 | return; |
654 | } |
655 | + |
656 | +/* Checks to see if the value of this property is unique or just the |
657 | + default value. */ |
658 | +/* TODO: Implement this */ |
659 | +gboolean |
660 | +dbusmenu_menuitem_property_is_default (DbusmenuMenuitem * mi, const gchar * property) |
661 | +{ |
662 | + /* No defaults system yet */ |
663 | + return FALSE; |
664 | +} |
665 | |
666 | === modified file 'libdbusmenu-glib/menuitem.h' |
667 | --- libdbusmenu-glib/menuitem.h 2011-01-07 05:25:02 +0000 |
668 | +++ libdbusmenu-glib/menuitem.h 2011-02-15 18:02:06 +0000 |
669 | @@ -111,14 +111,15 @@ |
670 | typedef void (*dbusmenu_menuitem_about_to_show_cb) (DbusmenuMenuitem * mi, gpointer user_data); |
671 | |
672 | /** |
673 | - * dbusmenu_menuitem_buildxml_slot_t: |
674 | + * dbusmenu_menuitem_buildvariant_slot_t: |
675 | * @mi: (in): Menu item that should be built from |
676 | - * @stringarray: (inout) (transfer none) (array) (element-type utf8): An array of strings that can be combined into an XML file. |
677 | * |
678 | * This is the function that is called to represent this menu item |
679 | - * as an XML fragment. Should call it's own children. |
680 | + * as a variant. Should call it's own children. |
681 | + * |
682 | + * Return value: (transfer full) A variant representing this item and it's children |
683 | */ |
684 | -typedef void (*dbusmenu_menuitem_buildxml_slot_t) (DbusmenuMenuitem * mi, GPtrArray* stringarray); |
685 | +typedef GVariant * (*dbusmenu_menuitem_buildvariant_slot_t) (DbusmenuMenuitem * mi, gchar ** properties); |
686 | |
687 | /** |
688 | * DbusmenuMenuitemClass: |
689 | @@ -155,7 +156,7 @@ |
690 | void (*realized) (void); |
691 | |
692 | /* Virtual functions */ |
693 | - dbusmenu_menuitem_buildxml_slot_t buildxml; |
694 | + dbusmenu_menuitem_buildvariant_slot_t buildvariant; |
695 | void (*handle_event) (DbusmenuMenuitem * mi, const gchar * name, GVariant * value, guint timestamp); |
696 | void (*send_about_to_show) (DbusmenuMenuitem * mi, void (*cb) (DbusmenuMenuitem * mi, gpointer user_data), gpointer cb_data); |
697 | |
698 | |
699 | === modified file 'libdbusmenu-glib/server.c' |
700 | --- libdbusmenu-glib/server.c 2011-01-31 14:10:49 +0000 |
701 | +++ libdbusmenu-glib/server.c 2011-02-15 18:02:06 +0000 |
702 | @@ -54,6 +54,9 @@ |
703 | GDBusConnection * bus; |
704 | GCancellable * bus_lookup; |
705 | guint dbus_registration; |
706 | + |
707 | + GArray * prop_array; |
708 | + guint property_idle; |
709 | }; |
710 | |
711 | #define DBUSMENU_SERVER_GET_PRIVATE(o) (DBUSMENU_SERVER(o)->priv) |
712 | @@ -156,6 +159,7 @@ |
713 | static void menuitem_signals_remove (DbusmenuMenuitem * mi, |
714 | gpointer data); |
715 | static GQuark error_quark (void); |
716 | +static void prop_array_teardown (GArray * prop_array); |
717 | static void bus_get_layout (DbusmenuServer * server, |
718 | GVariant * params, |
719 | GDBusMethodInvocation * invocation); |
720 | @@ -354,6 +358,17 @@ |
721 | |
722 | if (priv->layout_idle != 0) { |
723 | g_source_remove(priv->layout_idle); |
724 | + priv->layout_idle = 0; |
725 | + } |
726 | + |
727 | + if (priv->property_idle != 0) { |
728 | + g_source_remove(priv->property_idle); |
729 | + priv->property_idle = 0; |
730 | + } |
731 | + |
732 | + if (priv->prop_array != NULL) { |
733 | + prop_array_teardown(priv->prop_array); |
734 | + priv->prop_array = NULL; |
735 | } |
736 | |
737 | if (priv->root != NULL) { |
738 | @@ -418,6 +433,15 @@ |
739 | if (priv->root != NULL) { |
740 | dbusmenu_menuitem_foreach(priv->root, menuitem_signals_remove, obj); |
741 | dbusmenu_menuitem_set_root(priv->root, FALSE); |
742 | + |
743 | + GList * properties = dbusmenu_menuitem_properties_list(priv->root); |
744 | + GList * iter; |
745 | + for (iter = properties; iter != NULL; iter = g_list_next(iter)) { |
746 | + gchar * property = (gchar *)iter->data; |
747 | + menuitem_property_changed(priv->root, property, NULL, DBUSMENU_SERVER(obj)); |
748 | + } |
749 | + g_list_free(properties); |
750 | + |
751 | g_object_unref(G_OBJECT(priv->root)); |
752 | priv->root = NULL; |
753 | } |
754 | @@ -426,6 +450,14 @@ |
755 | g_object_ref(G_OBJECT(priv->root)); |
756 | dbusmenu_menuitem_set_root(priv->root, TRUE); |
757 | dbusmenu_menuitem_foreach(priv->root, menuitem_signals_create, obj); |
758 | + |
759 | + GList * properties = dbusmenu_menuitem_properties_list(priv->root); |
760 | + GList * iter; |
761 | + for (iter = properties; iter != NULL; iter = g_list_next(iter)) { |
762 | + gchar * property = (gchar *)iter->data; |
763 | + menuitem_property_changed(priv->root, property, dbusmenu_menuitem_property_get_variant(priv->root, property), DBUSMENU_SERVER(obj)); |
764 | + } |
765 | + g_list_free(properties); |
766 | } else { |
767 | g_debug("Setting root node to NULL"); |
768 | } |
769 | @@ -440,17 +472,6 @@ |
770 | } |
771 | |
772 | static void |
773 | -xmlarray_foreach_free (gpointer arrayentry, gpointer userdata) |
774 | -{ |
775 | - if (arrayentry != NULL) { |
776 | - /* g_debug("Freeing pointer: %s", (gchar *)arrayentry); */ |
777 | - g_free(arrayentry); |
778 | - } |
779 | - |
780 | - return; |
781 | -} |
782 | - |
783 | -static void |
784 | get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec) |
785 | { |
786 | DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(obj); |
787 | @@ -633,22 +654,264 @@ |
788 | return; |
789 | } |
790 | |
791 | +typedef struct _prop_idle_item_t prop_idle_item_t; |
792 | +struct _prop_idle_item_t { |
793 | + gint id; |
794 | + GArray * array; |
795 | +}; |
796 | + |
797 | +typedef struct _prop_idle_prop_t prop_idle_prop_t; |
798 | +struct _prop_idle_prop_t { |
799 | + gchar * property; |
800 | + GVariant * variant; |
801 | +}; |
802 | + |
803 | +/* Takes appart our data structure so we don't leak any |
804 | + memory or references. */ |
805 | +static void |
806 | +prop_array_teardown (GArray * prop_array) |
807 | +{ |
808 | + int i, j; |
809 | + |
810 | + for (i = 0; i < prop_array->len; i++) { |
811 | + prop_idle_item_t * iitem = &g_array_index(prop_array, prop_idle_item_t, i); |
812 | + |
813 | + for (j = 0; j < iitem->array->len; j++) { |
814 | + prop_idle_prop_t * iprop = &g_array_index(iitem->array, prop_idle_prop_t, j); |
815 | + |
816 | + g_free(iprop->property); |
817 | + |
818 | + if (iprop->variant != NULL) { |
819 | + g_variant_unref(iprop->variant); |
820 | + } |
821 | + } |
822 | + |
823 | + g_array_free(iitem->array, TRUE); |
824 | + } |
825 | + |
826 | + g_array_free(prop_array, TRUE); |
827 | + |
828 | + return; |
829 | +} |
830 | + |
831 | +/* Works in the idle to send a set of property updates so that they'll |
832 | + all update in a single dbus message. */ |
833 | +static gboolean |
834 | +menuitem_property_idle (gpointer user_data) |
835 | +{ |
836 | + DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(user_data); |
837 | + |
838 | + /* Source will get removed as we return */ |
839 | + priv->property_idle = 0; |
840 | + |
841 | + /* If there are no items, let's just not signal */ |
842 | + if (priv->prop_array == NULL) { |
843 | + return FALSE; |
844 | + } |
845 | + |
846 | + int i, j; |
847 | + GVariantBuilder itembuilder; |
848 | + gboolean item_init = FALSE; |
849 | + |
850 | + GVariantBuilder removeitembuilder; |
851 | + gboolean removeitem_init = FALSE; |
852 | + |
853 | + for (i = 0; i < priv->prop_array->len; i++) { |
854 | + prop_idle_item_t * iitem = &g_array_index(priv->prop_array, prop_idle_item_t, i); |
855 | + |
856 | + GVariantBuilder dictbuilder; |
857 | + gboolean dictinit = FALSE; |
858 | + |
859 | + GVariantBuilder removedictbuilder; |
860 | + gboolean removedictinit = FALSE; |
861 | + |
862 | + /* Go throught each item and see if it should go in the removal list |
863 | + or the additive list. */ |
864 | + for (j = 0; j < iitem->array->len; j++) { |
865 | + prop_idle_prop_t * iprop = &g_array_index(iitem->array, prop_idle_prop_t, j); |
866 | + |
867 | + if (iprop->variant != NULL) { |
868 | + if (!dictinit) { |
869 | + g_variant_builder_init(&dictbuilder, G_VARIANT_TYPE_DICTIONARY); |
870 | + dictinit = TRUE; |
871 | + } |
872 | + |
873 | + GVariant * entry = g_variant_new_dict_entry(g_variant_new_string(iprop->property), |
874 | + g_variant_new_variant(iprop->variant)); |
875 | + |
876 | + g_variant_builder_add_value(&dictbuilder, entry); |
877 | + } else { |
878 | + if (!removedictinit) { |
879 | + g_variant_builder_init(&removedictbuilder, G_VARIANT_TYPE_ARRAY); |
880 | + removedictinit = TRUE; |
881 | + } |
882 | + |
883 | + g_variant_builder_add_value(&removedictbuilder, g_variant_new_string(iprop->property)); |
884 | + } |
885 | + } |
886 | + |
887 | + /* If we've got new values that are real values we need to add that |
888 | + to the list of items to send the value of */ |
889 | + if (dictinit) { |
890 | + GVariantBuilder tuplebuilder; |
891 | + g_variant_builder_init(&tuplebuilder, G_VARIANT_TYPE_TUPLE); |
892 | + |
893 | + g_variant_builder_add_value(&tuplebuilder, g_variant_new_int32(iitem->id)); |
894 | + g_variant_builder_add_value(&tuplebuilder, g_variant_builder_end(&dictbuilder)); |
895 | + |
896 | + if (!item_init) { |
897 | + g_variant_builder_init(&itembuilder, G_VARIANT_TYPE_ARRAY); |
898 | + item_init = TRUE; |
899 | + } |
900 | + |
901 | + g_variant_builder_add_value(&itembuilder, g_variant_builder_end(&tuplebuilder)); |
902 | + } |
903 | + |
904 | + /* If we've got properties that have been removed then we need to add |
905 | + them to the list of removed items */ |
906 | + if (removedictinit) { |
907 | + GVariantBuilder tuplebuilder; |
908 | + g_variant_builder_init(&tuplebuilder, G_VARIANT_TYPE_TUPLE); |
909 | + |
910 | + g_variant_builder_add_value(&tuplebuilder, g_variant_new_int32(iitem->id)); |
911 | + g_variant_builder_add_value(&tuplebuilder, g_variant_builder_end(&removedictbuilder)); |
912 | + |
913 | + if (!removeitem_init) { |
914 | + g_variant_builder_init(&removeitembuilder, G_VARIANT_TYPE_ARRAY); |
915 | + removeitem_init = TRUE; |
916 | + } |
917 | + |
918 | + g_variant_builder_add_value(&removeitembuilder, g_variant_builder_end(&tuplebuilder)); |
919 | + } |
920 | + } |
921 | + |
922 | + GVariant * megadata[2]; |
923 | + |
924 | + if (item_init) { |
925 | + megadata[0] = g_variant_builder_end(&itembuilder); |
926 | + } else { |
927 | + GError * error = NULL; |
928 | + megadata[0] = g_variant_parse(G_VARIANT_TYPE("a(ia{sv})"), "[ ]", NULL, NULL, &error); |
929 | + |
930 | + if (error != NULL) { |
931 | + g_warning("Unable to parse '[ ]' as a 'a(ia{sv})': %s", error->message); |
932 | + g_error_free(error); |
933 | + } |
934 | + } |
935 | + |
936 | + if (removeitem_init) { |
937 | + megadata[1] = g_variant_builder_end(&removeitembuilder); |
938 | + } else { |
939 | + GError * error = NULL; |
940 | + megadata[1] = g_variant_parse(G_VARIANT_TYPE("a(ia(s))"), "[ ]", NULL, NULL, &error); |
941 | + |
942 | + if (error != NULL) { |
943 | + g_warning("Unable to parse '[ ]' as a 'a(ia(s))': %s", error->message); |
944 | + g_error_free(error); |
945 | + } |
946 | + } |
947 | + |
948 | + if (priv->dbusobject != NULL && priv->bus != NULL) { |
949 | + g_dbus_connection_emit_signal(priv->bus, |
950 | + NULL, |
951 | + priv->dbusobject, |
952 | + DBUSMENU_INTERFACE, |
953 | + "ItemPropertiesUpdated", |
954 | + g_variant_new_tuple(megadata, 2), |
955 | + NULL); |
956 | + } else { |
957 | + g_variant_unref(megadata[0]); |
958 | + g_variant_unref(megadata[1]); |
959 | + } |
960 | + |
961 | + /* Clean everything up */ |
962 | + prop_array_teardown(priv->prop_array); |
963 | + priv->prop_array = NULL; |
964 | + |
965 | + return FALSE; |
966 | +} |
967 | + |
968 | static void |
969 | menuitem_property_changed (DbusmenuMenuitem * mi, gchar * property, GVariant * variant, DbusmenuServer * server) |
970 | { |
971 | + int i; |
972 | + gint item_id; |
973 | + |
974 | DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server); |
975 | |
976 | - g_signal_emit(G_OBJECT(server), signals[ID_PROP_UPDATE], 0, dbusmenu_menuitem_get_id(mi), property, variant, TRUE); |
977 | - |
978 | - if (priv->dbusobject != NULL && priv->bus != NULL) { |
979 | - g_dbus_connection_emit_signal(priv->bus, |
980 | - NULL, |
981 | - priv->dbusobject, |
982 | - DBUSMENU_INTERFACE, |
983 | - "ItemPropertyUpdated", |
984 | - g_variant_new("(isv)", dbusmenu_menuitem_get_id(mi), property, variant), |
985 | - NULL); |
986 | - } |
987 | + item_id = dbusmenu_menuitem_get_id(mi); |
988 | + |
989 | + g_signal_emit(G_OBJECT(server), signals[ID_PROP_UPDATE], 0, item_id, property, variant, TRUE); |
990 | + |
991 | + /* See if we have a property array, if not, we need to |
992 | + build one of these suckers */ |
993 | + if (priv->prop_array == NULL) { |
994 | + priv->prop_array = g_array_new(FALSE, FALSE, sizeof(prop_idle_item_t)); |
995 | + } |
996 | + |
997 | + /* Look to see if we already have this item in the list |
998 | + and use it if so */ |
999 | + prop_idle_item_t * item = NULL; |
1000 | + for (i = 0; i < priv->prop_array->len; i++) { |
1001 | + prop_idle_item_t * iitem = &g_array_index(priv->prop_array, prop_idle_item_t, i); |
1002 | + if (iitem->id == item_id) { |
1003 | + item = iitem; |
1004 | + break; |
1005 | + } |
1006 | + } |
1007 | + |
1008 | + GArray * properties = NULL; |
1009 | + /* If not, we'll need to build ourselves one */ |
1010 | + if (item == NULL) { |
1011 | + prop_idle_item_t myitem; |
1012 | + myitem.id = item_id; |
1013 | + myitem.array = g_array_new(FALSE, FALSE, sizeof(prop_idle_prop_t)); |
1014 | + |
1015 | + g_array_append_val(priv->prop_array, myitem); |
1016 | + properties = myitem.array; |
1017 | + } else { |
1018 | + properties = item->array; |
1019 | + } |
1020 | + |
1021 | + /* Check to see if this property is in the list */ |
1022 | + prop_idle_prop_t * prop = NULL; |
1023 | + for (i = 0; i < properties->len; i++) { |
1024 | + prop_idle_prop_t * iprop = &g_array_index(properties, prop_idle_prop_t, i); |
1025 | + if (g_strcmp0(iprop->property, property) == 0) { |
1026 | + prop = iprop; |
1027 | + break; |
1028 | + } |
1029 | + } |
1030 | + |
1031 | + /* If it's the default value we want to treat it like a clearing |
1032 | + of the value so that it doesn't get sent over dbus and waste |
1033 | + bandwidth */ |
1034 | + if (dbusmenu_menuitem_property_is_default(mi, property)) { |
1035 | + variant = NULL; |
1036 | + } |
1037 | + |
1038 | + /* If so, we need to swap the value */ |
1039 | + if (prop != NULL) { |
1040 | + g_variant_unref(prop->variant); |
1041 | + prop->variant = variant; |
1042 | + } else { |
1043 | + /* else we need to add it */ |
1044 | + prop_idle_prop_t myprop; |
1045 | + myprop.property = g_strdup(property); |
1046 | + myprop.variant = variant; |
1047 | + |
1048 | + g_array_append_val(properties, myprop); |
1049 | + } |
1050 | + if (variant != NULL) { |
1051 | + g_variant_ref_sink(variant); |
1052 | + } |
1053 | + |
1054 | + /* Check to see if the idle is already queued, and queue it |
1055 | + if not. */ |
1056 | + if (priv->property_idle == 0) { |
1057 | + priv->property_idle = g_idle_add(menuitem_property_idle, server); |
1058 | + } |
1059 | + |
1060 | return; |
1061 | } |
1062 | |
1063 | @@ -757,26 +1020,28 @@ |
1064 | { |
1065 | DbusmenuServerPrivate * priv = DBUSMENU_SERVER_GET_PRIVATE(server); |
1066 | |
1067 | - gint parent = 0; |
1068 | - g_variant_get(params, "(i)", &parent); |
1069 | + /* Input */ |
1070 | + gint parent = g_variant_get_int32(g_variant_get_child_value(params, 0)); |
1071 | + gint recurse = g_variant_get_int32(g_variant_get_child_value(params, 1)); |
1072 | + const gchar ** props = g_variant_get_strv(g_variant_get_child_value(params, 2), NULL); |
1073 | |
1074 | + /* Output */ |
1075 | guint revision = priv->layout_revision; |
1076 | - GPtrArray * xmlarray = g_ptr_array_new(); |
1077 | - |
1078 | - if (parent == 0) { |
1079 | - if (priv->root == NULL) { |
1080 | - /* g_debug("Getting layout without root node!"); */ |
1081 | - g_ptr_array_add(xmlarray, g_strdup("<menu id=\"0\"/>")); |
1082 | + GVariant * items = NULL; |
1083 | + |
1084 | + if (priv->root != NULL) { |
1085 | + items = dbusmenu_menuitem_build_variant(priv->root, props, recurse); |
1086 | + } |
1087 | + |
1088 | + /* What happens if we don't have anything? */ |
1089 | + if (items == NULL) { |
1090 | + if (parent == 0) { |
1091 | + /* We should always have a root, so we'll make up one for |
1092 | + right now. */ |
1093 | + items = g_variant_parse(G_VARIANT_TYPE("(ia{sv}av)"), "(0, [], [])", NULL, NULL, NULL); |
1094 | } else { |
1095 | - dbusmenu_menuitem_buildxml(priv->root, xmlarray); |
1096 | - } |
1097 | - } else { |
1098 | - DbusmenuMenuitem * item = NULL; |
1099 | - if (priv->root != NULL) { |
1100 | - item = dbusmenu_menuitem_find_id(priv->root, parent); |
1101 | - } |
1102 | - |
1103 | - if (item == NULL) { |
1104 | + /* If we were looking for a specific ID that's an error that |
1105 | + we should send back, so let's do that. */ |
1106 | g_dbus_method_invocation_return_error(invocation, |
1107 | error_quark(), |
1108 | INVALID_MENUITEM_ID, |
1109 | @@ -784,23 +1049,19 @@ |
1110 | parent); |
1111 | return; |
1112 | } |
1113 | - dbusmenu_menuitem_buildxml(item, xmlarray); |
1114 | } |
1115 | - g_ptr_array_add(xmlarray, NULL); |
1116 | - |
1117 | - /* build string */ |
1118 | - gchar * layout = g_strjoinv("", (gchar **)xmlarray->pdata); |
1119 | - |
1120 | - g_ptr_array_foreach(xmlarray, xmlarray_foreach_free, NULL); |
1121 | - g_ptr_array_free(xmlarray, TRUE); |
1122 | - |
1123 | + |
1124 | + /* Build the final variant tuple */ |
1125 | + GVariantBuilder tuplebuilder; |
1126 | + g_variant_builder_init(&tuplebuilder, G_VARIANT_TYPE_TUPLE); |
1127 | + |
1128 | + g_variant_builder_add_value(&tuplebuilder, g_variant_new_uint32(revision)); |
1129 | + g_variant_builder_add_value(&tuplebuilder, items); |
1130 | + |
1131 | + GVariant * retval = g_variant_builder_end(&tuplebuilder); |
1132 | + // g_debug("Sending layout type: %s", g_variant_get_type_string(retval)); |
1133 | g_dbus_method_invocation_return_value(invocation, |
1134 | - g_variant_new("(us)", |
1135 | - revision, |
1136 | - layout)); |
1137 | - |
1138 | - g_free(layout); |
1139 | - |
1140 | + retval); |
1141 | return; |
1142 | } |
1143 | |
1144 | @@ -874,7 +1135,7 @@ |
1145 | return; |
1146 | } |
1147 | |
1148 | - GVariant * dict = dbusmenu_menuitem_properties_variant(mi); |
1149 | + GVariant * dict = dbusmenu_menuitem_properties_variant(mi, NULL); |
1150 | |
1151 | g_dbus_method_invocation_return_value(invocation, g_variant_new("(a{sv})", dict)); |
1152 | |
1153 | @@ -922,7 +1183,7 @@ |
1154 | GVariantBuilder wbuilder; |
1155 | g_variant_builder_init(&wbuilder, G_VARIANT_TYPE_TUPLE); |
1156 | g_variant_builder_add(&wbuilder, "i", id); |
1157 | - GVariant * props = dbusmenu_menuitem_properties_variant(mi); |
1158 | + GVariant * props = dbusmenu_menuitem_properties_variant(mi, NULL); |
1159 | |
1160 | if (props == NULL) { |
1161 | GError * error = NULL; |
1162 | @@ -982,7 +1243,7 @@ |
1163 | gint id = dbusmenu_menuitem_get_id(mi); |
1164 | g_variant_builder_add_value(&tuple, g_variant_new_int32(id)); |
1165 | |
1166 | - GVariant * props = dbusmenu_menuitem_properties_variant(mi); |
1167 | + GVariant * props = dbusmenu_menuitem_properties_variant(mi, NULL); |
1168 | g_variant_builder_add_value(&tuple, props); |
1169 | |
1170 | g_variant_builder_add_value(builder, g_variant_builder_end(&tuple)); |
1171 | @@ -1105,7 +1366,7 @@ |
1172 | event_data->variant = g_variant_get_variant(event_data->variant); |
1173 | } |
1174 | |
1175 | - g_variant_ref(event_data->variant); |
1176 | + g_variant_ref_sink(event_data->variant); |
1177 | |
1178 | g_timeout_add(0, event_local_handler, event_data); |
1179 | |
1180 | |
1181 | === modified file 'tests/json-loader.c' |
1182 | --- tests/json-loader.c 2010-12-02 03:35:46 +0000 |
1183 | +++ tests/json-loader.c 2011-02-15 18:02:06 +0000 |
1184 | @@ -109,7 +109,6 @@ |
1185 | |
1186 | if (variant != NULL) { |
1187 | dbusmenu_menuitem_property_set_variant(mi, member, variant); |
1188 | - g_variant_unref(variant); |
1189 | } |
1190 | } |
1191 | |
1192 | |
1193 | === modified file 'tests/test-glib-layout-client.c' |
1194 | --- tests/test-glib-layout-client.c 2010-02-05 17:54:42 +0000 |
1195 | +++ tests/test-glib-layout-client.c 2011-02-15 18:02:06 +0000 |
1196 | @@ -81,6 +81,11 @@ |
1197 | g_debug("Layout Updated"); |
1198 | |
1199 | DbusmenuMenuitem * menuroot = dbusmenu_client_get_root(client); |
1200 | + if (menuroot == NULL) { |
1201 | + g_debug("Root NULL, waiting"); |
1202 | + return; |
1203 | + } |
1204 | + |
1205 | layout_t * layout = &layouts[layouton]; |
1206 | |
1207 | if (!verify_root_to_layout(menuroot, layout)) { |