220
238
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(object);
240
if (priv->delayed_idle != 0) {
241
g_source_remove(priv->delayed_idle);
242
priv->delayed_idle = 0;
245
/* Only used for queueing up a new command, so we can
246
just drop this array. */
247
if (priv->delayed_property_list == NULL) {
248
gchar ** dataregion = (gchar **)g_array_free(priv->delayed_property_list, FALSE);
249
if (dataregion != NULL) {
250
g_strfreev(dataregion);
252
priv->delayed_property_list = NULL;
255
if (priv->delayed_property_listeners == NULL) {
257
GError * localerror = NULL;
259
/* Making sure all the callbacks get called so that if they had
260
memory in their user_data that needs to be free'd that happens. */
261
for (i = 0; i < priv->delayed_property_listeners->len; i++) {
262
properties_listener_t * listener = &g_array_index(priv->delayed_property_listeners, properties_listener_t, i);
263
if (!listener->replied) {
264
if (localerror == NULL) {
265
g_set_error_literal(&localerror, error_domain(), 0, "DbusmenuClient Shutdown");
267
listener->callback(priv->menuproxy, NULL, localerror, listener->user_data);
270
if (localerror != NULL) {
271
g_error_free(localerror);
274
g_array_free(priv->delayed_property_listeners, TRUE);
275
priv->delayed_property_listeners = NULL;
222
278
if (priv->layoutcall != NULL) {
223
279
dbus_g_proxy_cancel_call(priv->menuproxy, priv->layoutcall);
224
280
priv->layoutcall = NULL;
311
367
/* Internal funcs */
372
static GQuark error = 0;
374
error = g_quark_from_static_string(G_LOG_DOMAIN "-CLIENT");
379
/* Quick little function to search through the listeners and find
380
one that matches an ID */
381
static properties_listener_t *
382
find_listener (GArray * listeners, guint index, gint id)
384
if (index >= listeners->len) {
388
properties_listener_t * retval = &g_array_index(listeners, properties_listener_t, index);
389
if (retval->id == id) {
393
return find_listener(listeners, index + 1, id);
396
/* Call back from getting the group properties, now we need
397
to unwind and call the various functions. */
399
get_properties_callback (DBusGProxy *proxy, GPtrArray *OUT_properties, GError *error, gpointer userdata)
401
GArray * listeners = (GArray *)userdata;
404
#ifdef MASSIVEDEBUGGING
405
g_debug("Get properties callback: %d", OUT_properties->len);
409
/* If we get an error, all our callbacks need to hear about it. */
410
g_warning("Group Properties error: %s", error->message);
411
for (i = 0; i < listeners->len; i++) {
412
properties_listener_t * listener = &g_array_index(listeners, properties_listener_t, i);
413
listener->callback(proxy, NULL, error, listener->user_data);
415
g_array_free(listeners, TRUE);
419
/* Callback all the folks we can find */
420
for (i = 0; i < OUT_properties->len; i++) {
421
GValueArray * varray = (GValueArray *)g_ptr_array_index(OUT_properties, i);
423
if (varray->n_values != 2) {
424
g_warning("Value Array is %d entries long but we expected 2.", varray->n_values);
428
GValue * vid = g_value_array_get_nth(varray, 0);
429
GValue * vproperties = g_value_array_get_nth(varray, 1);
431
if (G_VALUE_TYPE(vid) != G_TYPE_INT) {
432
g_warning("ID Entry not holding an int: %s", G_VALUE_TYPE_NAME(vid));
434
if (G_VALUE_TYPE(vproperties) != dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) {
435
g_warning("Properties Entry not holding an a{sv}: %s", G_VALUE_TYPE_NAME(vproperties));
438
gint id = g_value_get_int(vid);
439
GHashTable * properties = g_value_get_boxed(vproperties);
441
properties_listener_t * listener = find_listener(listeners, 0, id);
442
if (listener == NULL) {
443
g_warning("Unable to find listener for ID %d", id);
447
if (!listener->replied) {
448
listener->callback(proxy, properties, NULL, listener->user_data);
449
listener->replied = TRUE;
451
g_warning("Odd, we've already replied to the listener on ID %d", id);
455
/* Provide errors for those who we can't */
456
GError * localerror = NULL;
457
for (i = 0; i < listeners->len; i++) {
458
properties_listener_t * listener = &g_array_index(listeners, properties_listener_t, i);
459
if (!listener->replied) {
460
if (localerror == NULL) {
461
g_set_error_literal(&localerror, error_domain(), 0, "Error getting properties for ID");
463
listener->callback(proxy, NULL, localerror, listener->user_data);
466
if (localerror != NULL) {
467
g_error_free(localerror);
471
g_array_free(listeners, TRUE);
476
/* Idle handler to send out all of our property requests as one big
477
lovely property request. */
479
get_properties_idle (gpointer user_data)
481
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(user_data);
482
//org_ayatana_dbusmenu_get_properties_async(priv->menuproxy, id, properties, callback, user_data);
484
if (priv->delayed_property_listeners->len == 0) {
485
g_warning("Odd, idle func got no listeners.");
489
/* Build up an ID list to pass */
490
GArray * idlist = g_array_new(FALSE, FALSE, sizeof(gint));
492
for (i = 0; i < priv->delayed_property_listeners->len; i++) {
493
g_array_append_val(idlist, g_array_index(priv->delayed_property_listeners, properties_listener_t, i).id);
496
org_ayatana_dbusmenu_get_group_properties_async(priv->menuproxy, idlist, (const gchar **)priv->delayed_property_list->data, get_properties_callback, priv->delayed_property_listeners);
499
g_array_free(idlist, TRUE);
501
/* Free properties */
502
gchar ** dataregion = (gchar **)g_array_free(priv->delayed_property_list, FALSE);
503
if (dataregion != NULL) {
504
g_strfreev(dataregion);
506
priv->delayed_property_list = g_array_new(TRUE, FALSE, sizeof(gchar *));
508
/* Rebuild the listeners */
509
priv->delayed_property_listeners = g_array_new(FALSE, FALSE, sizeof(properties_listener_t));
511
/* Make sure we set for a new idle */
512
priv->delayed_idle = 0;
517
/* Forces a call out to start getting properties with the menu items
518
that we have queued up already. */
520
get_properties_flush (DbusmenuClient * client)
522
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
524
if (priv->delayed_idle == 0) {
528
g_source_remove(priv->delayed_idle);
529
priv->delayed_idle = 0;
531
get_properties_idle(client);
533
dbus_g_connection_flush(priv->session_bus);
538
/* A function to group all the get_properties commands to make them
539
more efficient over dbus. */
541
get_properties_globber (DbusmenuClient * client, gint id, const gchar ** properties, org_ayatana_dbusmenu_get_properties_reply callback, gpointer user_data)
543
DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
544
if (find_listener(priv->delayed_property_listeners, 0, id) != NULL) {
545
g_warning("Asking for properties from same ID twice: %d", id);
546
GError * localerror = NULL;
547
g_set_error_literal(&localerror, error_domain(), 0, "ID already queued");
548
callback(priv->menuproxy, NULL, localerror, user_data);
549
g_error_free(localerror);
553
if (properties == NULL || properties[0] == NULL) {
555
if (priv->delayed_property_list->len != 0) {
556
/* If there are entries in the list, then we'll need to
557
remove them all, and start over */
558
gchar ** dataregion = (gchar **)g_array_free(priv->delayed_property_list, FALSE);
559
if (dataregion != NULL) {
560
g_strfreev(dataregion);
562
priv->delayed_property_list = g_array_new(TRUE, FALSE, sizeof(gchar *));
565
/* there could be a list we care about */
566
/* TODO: No one uses this today */
567
/* TODO: Copy them into the list */
570
properties_listener_t listener = {0};
572
listener.callback = callback;
573
listener.user_data = user_data;
574
listener.replied = FALSE;
576
g_array_append_val(priv->delayed_property_listeners, listener);
578
if (priv->delayed_idle == 0) {
579
priv->delayed_idle = g_idle_add(get_properties_idle, client);
313
585
/* Annoying little wrapper to make the right function update */
315
587
layout_update (DBusGProxy * proxy, guint revision, gint parent, DbusmenuClient * client)
1061
/* Builds a new child with property requests and everything
1062
else to clean up the code a bit */
1063
static DbusmenuMenuitem *
1064
parse_layout_new_child (gint id, DbusmenuClient * client, DbusmenuMenuitem * parent)
1066
DbusmenuMenuitem * item = NULL;
1068
/* Build a new item */
1069
item = DBUSMENU_MENUITEM(dbusmenu_client_menuitem_new(id, client));
1070
if (parent == NULL) {
1071
dbusmenu_menuitem_set_root(item, TRUE);
1074
/* Get the properties queued up for this item */
1075
/* Not happy allocating about this, but I need these :( */
1076
newItemPropData * propdata = g_new0(newItemPropData, 1);
1077
if (propdata != NULL) {
1078
propdata->client = client;
1079
propdata->item = item;
1080
propdata->parent = parent;
1083
get_properties_globber(client, id, NULL, menuitem_get_properties_new_cb, propdata);
1085
g_warning("Unable to allocate memory to get properties for menuitem. This menuitem will never be realized.");
1091
/* Refresh the properties on this item */
1093
parse_layout_update (DbusmenuMenuitem * item, DbusmenuClient * client)
1096
get_properties_globber(client, dbusmenu_menuitem_get_id(item), NULL, menuitem_get_properties_replace_cb, item);
787
1100
/* Parse recursively through the XML and make it into
788
1101
objects as need be */
789
1102
static DbusmenuMenuitem *
790
1103
parse_layout_xml(DbusmenuClient * client, xmlNodePtr node, DbusmenuMenuitem * item, DbusmenuMenuitem * parent, DBusGProxy * proxy)
1105
/* First verify and figure out what we've got */
792
1106
gint id = parse_node_get_id(node);
796
1110
#ifdef MASSIVEDEBUGGING
797
1111
g_debug("Client looking at node with id: %d", id);
799
/* If we don't have any item, or the IDs don't match */
800
if (item == NULL || dbusmenu_menuitem_get_id(item) != id) {
802
if (parent != NULL) {
803
dbusmenu_menuitem_child_delete(parent, item);
808
/* Build a new item */
809
item = DBUSMENU_MENUITEM(dbusmenu_client_menuitem_new(id, client));
810
if (parent == NULL) {
811
dbusmenu_menuitem_set_root(item, TRUE);
814
/* Get the properties queued up for this item */
815
/* Not happy about this, but I need these :( */
816
newItemPropData * propdata = g_new0(newItemPropData, 1);
817
if (propdata != NULL) {
818
propdata->client = client;
819
propdata->item = item;
820
propdata->parent = parent;
822
gchar * properties[1] = {NULL}; /* This gets them all */
824
org_ayatana_dbusmenu_get_properties_async(proxy, id, (const gchar **)properties, menuitem_get_properties_new_cb, propdata);
826
g_warning("Unable to allocate memory to get properties for menuitem. This menuitem will never be realized.");
829
/* Refresh the properties */
830
/* XXX: We shouldn't need to get the properties everytime we reuse an entry */
831
gchar * properties[1] = {NULL}; /* This gets them all */
833
org_ayatana_dbusmenu_get_properties_async(proxy, id, (const gchar **)properties, menuitem_get_properties_replace_cb, item);
1114
g_return_val_if_fail(item != NULL, NULL);
1115
g_return_val_if_fail(id == dbusmenu_menuitem_get_id(item), NULL);
1117
/* Some variables */
836
1118
xmlNodePtr children;
838
1120
GList * oldchildren = g_list_copy(dbusmenu_menuitem_get_children(item));
839
1121
/* g_debug("Starting old children: %d", g_list_length(oldchildren)); */
1123
/* Go through all the XML Nodes and make sure that we have menuitems
1124
to cover those XML nodes. */
841
1125
for (children = node->children, position = 0; children != NULL; children = children->next, position++) {
842
1126
/* g_debug("Looking at child: %d", position); */
843
1127
gint childid = parse_node_get_id(children);