diff options
Diffstat (limited to 'libdbusmenu-glib')
-rw-r--r-- | libdbusmenu-glib/client.c | 117 | ||||
-rw-r--r-- | libdbusmenu-glib/menuitem.c | 60 | ||||
-rw-r--r-- | libdbusmenu-glib/menuitem.h | 2 | ||||
-rw-r--r-- | libdbusmenu-glib/server.c | 1 |
4 files changed, 177 insertions, 3 deletions
diff --git a/libdbusmenu-glib/client.c b/libdbusmenu-glib/client.c index 6094eca..d5e4334 100644 --- a/libdbusmenu-glib/client.c +++ b/libdbusmenu-glib/client.c @@ -64,6 +64,8 @@ struct _DbusmenuClientPrivate DBusGProxy * menuproxy; DBusGProxy * propproxy; DBusGProxyCall * layoutcall; + + DBusGProxy * dbusproxy; }; #define DBUSMENU_CLIENT_GET_PRIVATE(o) \ @@ -148,6 +150,8 @@ dbusmenu_client_init (DbusmenuClient *self) priv->propproxy = NULL; priv->layoutcall = NULL; + priv->dbusproxy = NULL; + return; } @@ -168,8 +172,17 @@ dbusmenu_client_dispose (GObject *object) g_object_unref(G_OBJECT(priv->propproxy)); priv->propproxy = NULL; } + if (priv->dbusproxy != NULL) { + g_object_unref(G_OBJECT(priv->dbusproxy)); + priv->dbusproxy = NULL; + } priv->session_bus = NULL; + if (priv->root != NULL) { + g_object_unref(G_OBJECT(priv->root)); + priv->root = NULL; + } + G_OBJECT_CLASS (dbusmenu_client_parent_class)->dispose (object); return; } @@ -272,6 +285,84 @@ id_update (DBusGProxy * proxy, guint id, DbusmenuClient * client) return; } +/* Watches to see if our DBus savior comes onto the bus */ +static void +dbus_owner_change (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, DbusmenuClient * client) +{ + DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client); + + if (!(new != NULL && prev == NULL)) { + /* If it's not someone new getting on the bus, sorry we + simply just don't care. It's not that your service isn't + important to someone, just not us. You'll find the right + process someday, there's lots of processes out there. */ + return; + } + + if (g_strcmp0(new, priv->dbus_name)) { + /* Again, someone else's service. */ + return; + } + + /* Woot! A service for us to love and to hold for ever + and ever and ever! */ + return build_proxies(client); +} + +/* This function builds the DBus proxy which will look out for + the service coming up. */ +static void +build_dbus_proxy (DbusmenuClient * client) +{ + DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client); + GError * error = NULL; + + if (priv->dbusproxy != NULL) { + return; + } + + priv->dbusproxy = dbus_g_proxy_new_for_name_owner (priv->session_bus, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + &error); + if (error != NULL) { + g_debug("Oh, that's bad. That's really bad. We can't get a proxy to DBus itself? Seriously? Here's all I know: %s", error->message); + g_error_free(error); + return; + } + + dbus_g_proxy_add_signal(priv->dbusproxy, "NameOwnerChanged", + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal(priv->dbusproxy, "NameOwnerChanged", + G_CALLBACK(dbus_owner_change), client, NULL); + + return; +} + +/* A signal handler that gets called when a proxy is destoryed a + so it needs to clean up a little. Make sure we don't think we + have a layout and setup the dbus watcher. */ +static void +proxy_destroyed (GObject * gobj_proxy, gpointer userdata) +{ + DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(userdata); + + if (priv->root != NULL) { + g_object_unref(G_OBJECT(priv->root)); + priv->root = NULL; + g_signal_emit(G_OBJECT(userdata), signals[LAYOUT_UPDATED], 0, TRUE); + } + + if ((gpointer)priv->menuproxy == (gpointer)gobj_proxy) { + priv->layoutcall = NULL; + } + + build_dbus_proxy(DBUSMENU_CLIENT(userdata)); + return; +} + /* When we have a name and an object, build the two proxies and get the first version of the layout */ static void @@ -287,6 +378,7 @@ build_proxies (DbusmenuClient * client) if (error != NULL) { g_error("Unable to get session bus: %s", error->message); g_error_free(error); + build_dbus_proxy(client); return; } @@ -300,6 +392,8 @@ build_proxies (DbusmenuClient * client) g_error_free(error); return; } + g_object_add_weak_pointer(G_OBJECT(priv->propproxy), (gpointer *)&priv->propproxy); + g_signal_connect(G_OBJECT(priv->propproxy), "destroy", G_CALLBACK(proxy_destroyed), client); priv->menuproxy = dbus_g_proxy_new_for_name_owner(priv->session_bus, priv->dbus_name, @@ -311,6 +405,14 @@ build_proxies (DbusmenuClient * client) g_error_free(error); return; } + g_object_add_weak_pointer(G_OBJECT(priv->menuproxy), (gpointer *)&priv->menuproxy); + g_signal_connect(G_OBJECT(priv->menuproxy), "destroy", G_CALLBACK(proxy_destroyed), client); + + /* If we get here, we don't need the DBus proxy */ + if (priv->dbusproxy != NULL) { + g_object_unref(G_OBJECT(priv->dbusproxy)); + priv->dbusproxy = NULL; + } dbus_g_proxy_add_signal(priv->menuproxy, "LayoutUpdate", G_TYPE_INVALID); dbus_g_proxy_connect_signal(priv->menuproxy, "LayoutUpdate", G_CALLBACK(layout_update), client, NULL); @@ -388,6 +490,7 @@ parse_layout_xml(xmlNodePtr node, DbusmenuMenuitem * item, DbusmenuMenuitem * pa dbusmenu_menuitem_child_delete(parent, item); } g_object_unref(G_OBJECT(item)); + item = NULL; } if (id == 0) { @@ -404,6 +507,7 @@ parse_layout_xml(xmlNodePtr node, DbusmenuMenuitem * item, DbusmenuMenuitem * pa xmlNodePtr children; guint position; GList * oldchildren = dbusmenu_menuitem_take_children(item); + /* g_debug("Starting old children: %d", g_list_length(oldchildren)); */ for (children = node->children, position = 0; children != NULL; children = children->next, position++) { /* g_debug("Looking at child: %d", position); */ @@ -424,9 +528,11 @@ parse_layout_xml(xmlNodePtr node, DbusmenuMenuitem * item, DbusmenuMenuitem * pa dbusmenu_menuitem_child_add_position(item, childmi, position); } + /* g_debug("Stopping old children: %d", g_list_length(oldchildren)); */ GList * oldchildleft = NULL; for (oldchildleft = oldchildren; oldchildleft != NULL; oldchildleft = g_list_next(oldchildleft)) { DbusmenuMenuitem * oldmi = DBUSMENU_MENUITEM(oldchildleft->data); + g_debug("Unref'ing menu item with layout update. ID: %d", dbusmenu_menuitem_get_id(oldmi)); g_object_unref(G_OBJECT(oldmi)); } g_list_free(oldchildren); @@ -491,6 +597,10 @@ update_layout (DbusmenuClient * client) { DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client); + if (priv->propproxy == NULL) { + return; + } + if (priv->layoutcall != NULL) { return; } @@ -546,7 +656,8 @@ dbusmenu_client_new (const gchar * name, const gchar * object) it could block longer. Return value: A #DbusmenuMenuitem representing the root of - menu on the server. + menu on the server. If there is no server or there is + an error receiving its layout it'll return #NULL. */ DbusmenuMenuitem * dbusmenu_client_get_root (DbusmenuClient * client) @@ -555,6 +666,10 @@ dbusmenu_client_get_root (DbusmenuClient * client) DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client); + if (priv->propproxy == NULL) { + return NULL; + } + if (priv->layoutcall != NULL) { /* Will end the current call and block on it's completion */ update_layout_cb(priv->propproxy, priv->layoutcall, client); diff --git a/libdbusmenu-glib/menuitem.c b/libdbusmenu-glib/menuitem.c index 9506cad..95391a4 100644 --- a/libdbusmenu-glib/menuitem.c +++ b/libdbusmenu-glib/menuitem.c @@ -139,7 +139,7 @@ dbusmenu_menuitem_class_init (DbusmenuMenuitemClass *klass) G_STRUCT_OFFSET(DbusmenuMenuitemClass, child_added), NULL, NULL, _dbusmenu_menuitem_marshal_VOID__OBJECT, - G_TYPE_NONE, 2, G_TYPE_OBJECT); + G_TYPE_NONE, 1, G_TYPE_OBJECT); /** DbusmenuMenuitem::child-removed: @arg0: The #DbusmenuMenuitem which was the parent. @@ -156,7 +156,7 @@ dbusmenu_menuitem_class_init (DbusmenuMenuitemClass *klass) G_STRUCT_OFFSET(DbusmenuMenuitemClass, child_removed), NULL, NULL, _dbusmenu_menuitem_marshal_VOID__OBJECT, - G_TYPE_NONE, 2, G_TYPE_OBJECT); + G_TYPE_NONE, 1, G_TYPE_OBJECT); g_object_class_install_property (object_class, PROP_ID, g_param_spec_uint("id", "ID for the menu item", @@ -185,6 +185,14 @@ dbusmenu_menuitem_init (DbusmenuMenuitem *self) static void dbusmenu_menuitem_dispose (GObject *object) { + DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(object); + + GList * child = NULL; + for (child = priv->children; child != NULL; child = g_list_next(child)) { + g_object_unref(G_OBJECT(child->data)); + } + g_list_free(priv->children); + priv->children = NULL; G_OBJECT_CLASS (dbusmenu_menuitem_parent_class)->dispose (object); return; @@ -193,6 +201,7 @@ dbusmenu_menuitem_dispose (GObject *object) static void dbusmenu_menuitem_finalize (GObject *object) { + g_debug("Menuitem dying"); DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(object); if (priv->properties != NULL) { @@ -394,6 +403,28 @@ dbusmenu_menuitem_child_append (DbusmenuMenuitem * mi, DbusmenuMenuitem * child) } /** + dbusmenu_menuitem_child_prepend: + @mi: The #DbusmenuMenuitem which will become a new parent + @child: The #DbusmenMenuitem that will be a child + + This function adds @child to the list of children on @mi at + the beginning of that list. + + Return value: Whether the child has been added successfully. +*/ +gboolean +dbusmenu_menuitem_child_prepend (DbusmenuMenuitem * mi, DbusmenuMenuitem * child) +{ + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), FALSE); + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(child), FALSE); + + DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi); + priv->children = g_list_prepend(priv->children, child); + g_signal_emit(G_OBJECT(mi), signals[CHILD_ADDED], 0, child, TRUE); + return TRUE; +} + +/** dbusmenu_menuitem_child_delete: @mi: The #DbusmenuMenuitem which has @child as a child @child: The child #DbusmenuMenuitem that you want to no longer @@ -441,6 +472,31 @@ dbusmenu_menuitem_child_add_position (DbusmenuMenuitem * mi, DbusmenuMenuitem * } /** + dbusmenu_menuitem_child_reorder: + @base: The #DbusmenuMenuitem that has children needing realignment + @child: The #DbusmenuMenuitem that is a child needing to be moved + @position: The position in the list to place it in + + This function moves a child on the list of children. It is + for a child that is already in the list, but simply needs a + new location. + + Return value: Whether the move was successful. +*/ +gboolean +dbusmenu_menuitem_child_reorder(DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint position) +{ + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(mi), FALSE); + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(child), FALSE); + + DbusmenuMenuitemPrivate * priv = DBUSMENU_MENUITEM_GET_PRIVATE(mi); + priv->children = g_list_remove(priv->children, child); + priv->children = g_list_insert(priv->children, child, position); + + return TRUE; +} + +/** dbusmenu_menuitem_child_find: @mi: The #DbusmenuMenuitem who's children to look on @id: The ID of the child that we're looking for. diff --git a/libdbusmenu-glib/menuitem.h b/libdbusmenu-glib/menuitem.h index 3f3e97c..c4fcf73 100644 --- a/libdbusmenu-glib/menuitem.h +++ b/libdbusmenu-glib/menuitem.h @@ -107,8 +107,10 @@ GList * dbusmenu_menuitem_take_children (DbusmenuMenuitem * mi) G_GNUC_WARN_UNUS guint dbusmenu_menuitem_get_position (DbusmenuMenuitem * mi, DbusmenuMenuitem * parent); gboolean dbusmenu_menuitem_child_append (DbusmenuMenuitem * mi, DbusmenuMenuitem * child); +gboolean dbusmenu_menuitem_child_prepend (DbusmenuMenuitem * mi, DbusmenuMenuitem * child); gboolean dbusmenu_menuitem_child_delete (DbusmenuMenuitem * mi, DbusmenuMenuitem * child); gboolean dbusmenu_menuitem_child_add_position (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint position); +gboolean dbusmenu_menuitem_child_reorder (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint position); DbusmenuMenuitem * dbusmenu_menuitem_child_find (DbusmenuMenuitem * mi, guint id); DbusmenuMenuitem * dbusmenu_menuitem_find_id (DbusmenuMenuitem * mi, guint id); diff --git a/libdbusmenu-glib/server.c b/libdbusmenu-glib/server.c index 562b2d7..cf8ea85 100644 --- a/libdbusmenu-glib/server.c +++ b/libdbusmenu-glib/server.c @@ -490,6 +490,7 @@ dbusmenu_server_set_root (DbusmenuServer * self, DbusmenuMenuitem * root) g_value_init(&rootvalue, G_TYPE_OBJECT); g_value_set_object(&rootvalue, root); g_object_set_property(G_OBJECT(self), DBUSMENU_SERVER_PROP_ROOT_NODE, &rootvalue); + g_object_unref(G_OBJECT(root)); return; } |