← Back to team overview

ayatana-commits team mailing list archive

[Merge] lp:~ted/indicator-messages/dynamic-commands into lp:indicator-messages

 

Ted Gould has proposed merging lp:~ted/indicator-messages/dynamic-commands into lp:indicator-messages with lp:~ted/indicator-messages/static-commands as a prerequisite.

    Requested reviews:
    Indicator Applet Developers (indicator-applet-developers)


Adds dynamic menu items from the applications.
-- 
https://code.launchpad.net/~ted/indicator-messages/dynamic-commands/+merge/19570
Your team ayatana-commits is subscribed to branch lp:indicator-messages.
=== modified file 'src/app-menu-item.c'
--- src/app-menu-item.c	2010-02-09 19:32:28 +0000
+++ src/app-menu-item.c	2010-02-18 03:05:20 +0000
@@ -26,12 +26,15 @@
 
 #include <glib/gi18n.h>
 #include <gio/gdesktopappinfo.h>
+#include <libdbusmenu-glib/client.h>
+#include <libdbusmenu-glib/menuitem-proxy.h>
 #include "app-menu-item.h"
 #include "dbus-data.h"
 
 enum {
 	COUNT_CHANGED,
 	NAME_CHANGED,
+	SHORTCUTS_CHANGED,
 	LAST_SIGNAL
 };
 
@@ -48,6 +51,10 @@
 	GAppInfo * appinfo;
 	gchar * desktop;
 	guint unreadcount;
+
+	DbusmenuClient * client;
+	DbusmenuMenuitem * root;
+	GList * shortcuts;
 };
 
 #define APP_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_MENU_ITEM_TYPE, AppMenuItemPrivate))
@@ -60,6 +67,7 @@
 static void activate_cb (AppMenuItem * self, guint timestamp, gpointer data);
 static void count_changed (IndicateListener * listener, IndicateListenerServer * server, guint count, gpointer data);
 static void count_cb (IndicateListener * listener, IndicateListenerServer * server, guint value, gpointer data);
+static void menu_cb (IndicateListener * listener, IndicateListenerServer * server, gchar * menupath, gpointer data);
 static void desktop_cb (IndicateListener * listener, IndicateListenerServer * server, gchar * value, gpointer data);
 static void update_label (AppMenuItem * self);
 
@@ -90,6 +98,13 @@
 	                                      NULL, NULL,
 	                                      g_cclosure_marshal_VOID__STRING,
 	                                      G_TYPE_NONE, 1, G_TYPE_STRING);
+	signals[SHORTCUTS_CHANGED] =  g_signal_new(APP_MENU_ITEM_SIGNAL_SHORTCUTS_CHANGED,
+	                                      G_TYPE_FROM_CLASS(klass),
+	                                      G_SIGNAL_RUN_LAST,
+	                                      G_STRUCT_OFFSET (AppMenuItemClass, shortcuts_changed),
+	                                      NULL, NULL,
+	                                      g_cclosure_marshal_VOID__VOID,
+	                                      G_TYPE_NONE, 0, G_TYPE_NONE);
 
 	return;
 }
@@ -107,6 +122,18 @@
 	priv->desktop = NULL;
 	priv->unreadcount = 0;
 
+	priv->client = NULL;
+	priv->root = NULL;
+	priv->shortcuts = NULL;
+
+	return;
+}
+
+/* A wrapper to make the prototypes work for GFunc */
+static void
+func_unref (gpointer data, gpointer user_data)
+{
+	g_object_unref(G_OBJECT(data));
 	return;
 }
 
@@ -117,8 +144,27 @@
 	AppMenuItem * self = APP_MENU_ITEM(object);
 	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
 
-	g_signal_handlers_disconnect_by_func(G_OBJECT(priv->listener), count_changed, self);
-	g_object_unref(priv->listener);
+	if (priv->listener != NULL) {
+		g_signal_handlers_disconnect_by_func(G_OBJECT(priv->listener), count_changed, self);
+		g_object_unref(priv->listener);
+	}
+
+	if (priv->shortcuts != NULL) {
+		g_list_foreach(priv->shortcuts, func_unref, NULL);
+		g_list_free(priv->shortcuts);
+		priv->shortcuts = NULL;
+		g_signal_emit(object, signals[SHORTCUTS_CHANGED], 0, TRUE);
+	}
+
+	if (priv->root != NULL) {
+		g_object_unref(priv->root);
+		priv->root = NULL;
+	}
+
+	if (priv->client != NULL) {
+		g_object_unref(priv->client);
+		priv->client = NULL;
+	}
 
 	G_OBJECT_CLASS (app_menu_item_parent_class)->dispose (object);
 }
@@ -168,6 +214,7 @@
 	/* Get the values we care about from the server */
 	indicate_listener_server_get_desktop(listener, server, desktop_cb, self);
 	indicate_listener_server_get_count(listener, server, count_cb, self);
+	indicate_listener_server_get_menu(listener, server, menu_cb, self);
 
 	g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL);
 
@@ -262,6 +309,145 @@
 	return;
 }
 
+/* Relay this signal into causing a rebuild of the shortcuts
+   from those above us. */
+static void
+child_added_cb (DbusmenuMenuitem * root, DbusmenuMenuitem * child, guint position, gpointer data)
+{
+	AppMenuItem * self = APP_MENU_ITEM(data);
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
+	DbusmenuMenuitemProxy * mip = dbusmenu_menuitem_proxy_new(child);
+
+	priv->shortcuts = g_list_insert(priv->shortcuts, mip, position);
+
+	g_signal_emit(G_OBJECT(data), signals[SHORTCUTS_CHANGED], 0, TRUE);
+	return;
+}
+
+/* Relay this signal into causing a rebuild of the shortcuts
+   from those above us. */
+static void
+child_removed_cb (DbusmenuMenuitem * root, DbusmenuMenuitem * child, gpointer data)
+{
+	AppMenuItem * self = APP_MENU_ITEM(data);
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
+
+	GList * pitems = priv->shortcuts;
+	while (pitems != NULL) {
+		DbusmenuMenuitemProxy * mip = DBUSMENU_MENUITEM_PROXY(pitems->data);
+
+		if (dbusmenu_menuitem_proxy_get_wrapped(mip) == child) {
+			break;
+		}
+
+		pitems = g_list_next(pitems);
+	}
+
+	if (pitems != NULL) {
+		DbusmenuMenuitemProxy * mip = DBUSMENU_MENUITEM_PROXY(pitems->data);
+		g_object_unref(mip);
+		priv->shortcuts = g_list_remove(priv->shortcuts, mip);
+
+		g_signal_emit(G_OBJECT(data), signals[SHORTCUTS_CHANGED], 0, TRUE);
+	}
+
+	return;
+}
+
+/* Relay this signal into causing a rebuild of the shortcuts
+   from those above us. */
+static void 
+child_moved_cb (DbusmenuMenuitem * root, DbusmenuMenuitem * child, guint newpos, guint oldpos, gpointer data)
+{
+	AppMenuItem * self = APP_MENU_ITEM(data);
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
+
+	DbusmenuMenuitemProxy * mip = DBUSMENU_MENUITEM_PROXY(g_list_nth_data(priv->shortcuts, oldpos));
+
+	if (mip != NULL) {
+		if (dbusmenu_menuitem_proxy_get_wrapped(mip) != child) {
+			mip = NULL;
+		}
+	}
+
+	if (mip != NULL) {
+		priv->shortcuts = g_list_remove(priv->shortcuts, mip);
+		priv->shortcuts = g_list_insert(priv->shortcuts, mip, newpos);
+		g_signal_emit(G_OBJECT(data), signals[SHORTCUTS_CHANGED], 0, TRUE);
+	}
+
+	return;
+}
+
+/* We've got a new root.  We need to proxy it and handle it's children
+   if that's a relevant thing to do. */
+static void
+root_changed (DbusmenuClient * client, DbusmenuMenuitem * newroot, gpointer data)
+{
+	g_debug("Root Changed");
+	AppMenuItem * self = APP_MENU_ITEM(data);
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
+	gboolean change_time = FALSE;
+
+	if (priv->root != NULL) {
+		if (dbusmenu_menuitem_get_children(DBUSMENU_MENUITEM(priv->root)) != NULL) {
+			change_time = TRUE;
+			g_list_foreach(priv->shortcuts, func_unref, NULL);
+			g_list_free(priv->shortcuts);
+			priv->shortcuts = NULL;
+		}
+		g_object_unref(priv->root);
+		priv->root = NULL;
+	}
+
+	/* We need to proxy the new root across to the old
+	   world of indicator land. */
+	priv->root = newroot;
+	g_object_ref(priv->root);
+	g_signal_connect(G_OBJECT(priv->root), DBUSMENU_MENUITEM_SIGNAL_CHILD_ADDED,   G_CALLBACK(child_added_cb),   self);
+	g_signal_connect(G_OBJECT(priv->root), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(child_removed_cb), self);
+	g_signal_connect(G_OBJECT(priv->root), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED,   G_CALLBACK(child_moved_cb),   self);
+
+	/* See if we have any menuitems to worry about,
+	   otherwise we'll just move along. */
+	GList * children = dbusmenu_menuitem_get_children(DBUSMENU_MENUITEM(priv->root));
+	if (children != NULL) {
+		change_time = TRUE;
+		g_debug("\tProcessing %d children", g_list_length(children));
+		while (children != NULL) {
+			DbusmenuMenuitemProxy * mip = dbusmenu_menuitem_proxy_new(DBUSMENU_MENUITEM(children->data));
+			priv->shortcuts = g_list_append(priv->shortcuts, mip);
+			children = g_list_next(children);
+		}
+	}
+
+	if (change_time) {
+		g_signal_emit(G_OBJECT(self), signals[SHORTCUTS_CHANGED], 0, TRUE);
+	}
+
+	return;
+}
+
+/* Gets the path to menuitems if there are some.  Now we need to
+   make them special. */
+static void
+menu_cb (IndicateListener * listener, IndicateListenerServer * server, gchar * menupath, gpointer data)
+{
+	g_debug("Got Menu: %s", menupath);
+	AppMenuItem * self = APP_MENU_ITEM(data);
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
+
+	priv->client = dbusmenu_client_new(indicate_listener_server_get_dbusname(server), menupath);
+	g_signal_connect(G_OBJECT(priv->client), DBUSMENU_CLIENT_SIGNAL_ROOT_CHANGED, G_CALLBACK(root_changed), self);
+
+	DbusmenuMenuitem * root = dbusmenu_client_get_root(priv->client);
+	if (root != NULL) {
+		root_changed(priv->client, root, self);
+	}
+
+	return;
+}
+
 static void
 activate_cb (AppMenuItem * self, guint timestamp, gpointer data)
 {
@@ -309,3 +495,13 @@
 	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
 	return priv->desktop;
 }
+
+/* Get the dynamic items added onto the end of
+   and app entry. */
+GList *
+app_menu_item_get_items (AppMenuItem * appitem)
+{
+	g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL);
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
+	return priv->shortcuts;
+}

=== modified file 'src/app-menu-item.h'
--- src/app-menu-item.h	2009-08-20 03:29:40 +0000
+++ src/app-menu-item.h	2010-02-18 03:05:20 +0000
@@ -37,8 +37,9 @@
 #define IS_APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_MENU_ITEM_TYPE))
 #define APP_MENU_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), APP_MENU_ITEM_TYPE, AppMenuItemClass))
 
-#define APP_MENU_ITEM_SIGNAL_COUNT_CHANGED  "count-changed"
-#define APP_MENU_ITEM_SIGNAL_NAME_CHANGED   "name-changed"
+#define APP_MENU_ITEM_SIGNAL_COUNT_CHANGED     "count-changed"
+#define APP_MENU_ITEM_SIGNAL_NAME_CHANGED      "name-changed"
+#define APP_MENU_ITEM_SIGNAL_SHORTCUTS_CHANGED "shortcuts-changed"
 
 typedef struct _AppMenuItem      AppMenuItem;
 typedef struct _AppMenuItemClass AppMenuItemClass;
@@ -48,6 +49,7 @@
 
 	void (* count_changed) (guint count);
 	void (* name_changed) (gchar * name);
+	void (* shortcuts_changed) (void);
 };
 
 struct _AppMenuItem {
@@ -60,6 +62,7 @@
 IndicateListenerServer * app_menu_item_get_server (AppMenuItem * appitem);
 const gchar * app_menu_item_get_name (AppMenuItem * appitem);
 const gchar * app_menu_item_get_desktop (AppMenuItem * appitem);
+GList * app_menu_item_get_items (AppMenuItem * appitem);
 
 G_END_DECLS
 

=== modified file 'src/messages-service.c'
--- src/messages-service.c	2010-02-18 03:05:20 +0000
+++ src/messages-service.c	2010-02-18 03:05:20 +0000
@@ -31,6 +31,7 @@
 
 #include <libdbusmenu-glib/client.h>
 #include <libdbusmenu-glib/server.h>
+#include <libdbusmenu-glib/menuitem-proxy.h>
 
 #include "im-menu-item.h"
 #include "app-menu-item.h"
@@ -51,6 +52,7 @@
 #define DESKTOP_FILE_GROUP        "Messaging Menu"
 #define DESKTOP_FILE_KEY_DESKTOP  "DesktopFile"
 
+static void server_shortcuts_changed (AppMenuItem * appitem, gpointer data);
 static void server_count_changed (AppMenuItem * appitem, guint count, gpointer data);
 static void server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data);
 static void im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data);
@@ -582,11 +584,21 @@
 	/* Connect the signals up to the menu item */
 	g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_COUNT_CHANGED, G_CALLBACK(server_count_changed), sl_item);
 	g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_NAME_CHANGED,  G_CALLBACK(server_name_changed),  menushell);
+	g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_SHORTCUTS_CHANGED,  G_CALLBACK(server_shortcuts_changed),  menushell);
 
 	/* Put our new menu item in, with the separator behind it.
 	   resort_menu will take care of whether it should be hidden
 	   or not. */
 	dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem));
+
+	GList * shortcuts = app_menu_item_get_items(sl_item->menuitem);
+	while (shortcuts != NULL) {
+		DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(shortcuts->data);
+		g_debug("\tAdding shortcut: %s", dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL));
+		dbusmenu_menuitem_child_append(menushell, mi);
+		shortcuts = g_list_next(shortcuts);
+	}
+
 	dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(sl_item->separator));
 
 	resort_menu(menushell);
@@ -595,6 +607,50 @@
 	return;
 }
 
+/* The shortcuts have changed, let's just remove them and put
+   the back. */
+static void
+server_shortcuts_changed (AppMenuItem * appitem, gpointer data)
+{
+	g_debug("Application Shortcuts changed");
+	DbusmenuMenuitem * shell = DBUSMENU_MENUITEM(data);
+	gboolean appitemfound = FALSE;
+	GList * children = dbusmenu_menuitem_get_children(shell);
+	GList * removelist = NULL;
+
+	while (children != NULL) {
+		if (!appitemfound && children->data != appitem) {
+			children = g_list_next(children);
+			continue;
+		}
+		appitemfound = TRUE;
+
+		if (!DBUSMENU_IS_MENUITEM_PROXY(children->data)) {
+			break;
+		}
+
+		removelist = g_list_prepend(removelist, children->data);
+	}
+
+	GList * removeitem;
+	for (removeitem = removelist; removeitem != NULL; removeitem = g_list_next(removeitem)) {
+		dbusmenu_menuitem_child_delete(shell, DBUSMENU_MENUITEM(removeitem->data));
+	}
+	g_list_free(removeitem);
+
+	GList * shortcuts = app_menu_item_get_items(appitem);
+	while (shortcuts != NULL) {
+		DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(shortcuts->data);
+		g_debug("\tAdding shortcut: %s", dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL));
+		dbusmenu_menuitem_child_append(shell, mi);
+		shortcuts = g_list_next(shortcuts);
+	}
+
+	resort_menu(shell);
+
+	return;
+}
+
 /* The name of a server has changed, we probably
    need to reorder the menu to keep it in alphabetical
    order.  This happens often after we read the destkop
@@ -831,6 +887,15 @@
 			g_debug("\tMoving app %s to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position);
 			dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(si->menuitem), position);
 			position++;
+
+			/* Inserting the shortcuts from the launcher */
+			GList * shortcuts = app_menu_item_get_items(si->menuitem);
+			while (shortcuts != NULL) {
+				g_debug("\t\tMoving shortcut to position %d", position);
+				dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcuts->data), position);
+				position++;
+				shortcuts = g_list_next(shortcuts);
+			}
 		}
 
 		/* Putting all the indicators that are related to this application


Follow ups