aboutsummaryrefslogtreecommitdiff
path: root/libdbusmenu-glib
diff options
context:
space:
mode:
Diffstat (limited to 'libdbusmenu-glib')
-rw-r--r--libdbusmenu-glib/client.c117
-rw-r--r--libdbusmenu-glib/menuitem.c60
-rw-r--r--libdbusmenu-glib/menuitem.h2
-rw-r--r--libdbusmenu-glib/server.c1
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;
}