aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--src/app-menu-item.c207
-rw-r--r--src/app-menu-item.h7
-rw-r--r--src/messages-service.c65
4 files changed, 276 insertions, 5 deletions
diff --git a/configure.ac b/configure.ac
index 9a906ec..0932e1d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,7 +31,7 @@ GIO_UNIX_REQUIRED_VERSION=2.18
PANEL_REQUIRED_VERSION=2.0.0
INDICATE_REQUIRED_VERSION=0.3.0
INDICATOR_REQUIRED_VERSION=0.3.3
-DBUSMENUGTK_REQUIRED_VERSION=0.2.2
+DBUSMENUGTK_REQUIRED_VERSION=0.2.5
PKG_CHECK_MODULES(APPLET, gtk+-2.0 >= $GTK_REQUIRED_VERSION
gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION
diff --git a/src/app-menu-item.c b/src/app-menu-item.c
index 5fc2a9c..2fb24f6 100644
--- a/src/app-menu-item.c
+++ b/src/app-menu-item.c
@@ -26,12 +26,15 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#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 @@ struct _AppMenuItemPrivate
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 app_menu_item_finalize (GObject *object);
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 @@ app_menu_item_class_init (AppMenuItemClass *klass)
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 @@ app_menu_item_init (AppMenuItem *self)
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,28 @@ app_menu_item_dispose (GObject *object)
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);
+ priv->listener = NULL;
+ }
+
+ 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 +215,7 @@ app_menu_item_new (IndicateListener * listener, IndicateListenerServer * server)
/* 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);
@@ -206,6 +254,7 @@ update_label (AppMenuItem * self)
static void
count_changed (IndicateListener * listener, IndicateListenerServer * server, guint count, gpointer data)
{
+ g_return_if_fail(IS_APP_MENU_ITEM(data));
AppMenuItem * self = APP_MENU_ITEM(data);
AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
@@ -234,6 +283,7 @@ count_cb (IndicateListener * listener, IndicateListenerServer * server, guint va
static void
desktop_cb (IndicateListener * listener, IndicateListenerServer * server, gchar * value, gpointer data)
{
+ g_return_if_fail(IS_APP_MENU_ITEM(data));
AppMenuItem * self = APP_MENU_ITEM(data);
AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
@@ -262,6 +312,149 @@ desktop_cb (IndicateListener * listener, IndicateListenerServer * server, gchar
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)
+{
+ g_return_if_fail(IS_APP_MENU_ITEM(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)
+{
+ g_return_if_fail(IS_APP_MENU_ITEM(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)
+{
+ g_return_if_fail(IS_APP_MENU_ITEM(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);
+ g_return_if_fail(IS_APP_MENU_ITEM(data));
+ 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 +502,13 @@ app_menu_item_get_desktop (AppMenuItem * appitem)
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;
+}
diff --git a/src/app-menu-item.h b/src/app-menu-item.h
index 583d50d..48a7cfa 100644
--- a/src/app-menu-item.h
+++ b/src/app-menu-item.h
@@ -37,8 +37,9 @@ G_BEGIN_DECLS
#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 @@ struct _AppMenuItemClass {
void (* count_changed) (guint count);
void (* name_changed) (gchar * name);
+ void (* shortcuts_changed) (void);
};
struct _AppMenuItem {
@@ -60,6 +62,7 @@ guint app_menu_item_get_count (AppMenuItem * appitem);
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
diff --git a/src/messages-service.c b/src/messages-service.c
index cdfdb34..0ebab0b 100644
--- a/src/messages-service.c
+++ b/src/messages-service.c
@@ -31,6 +31,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#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 @@ static MessageServiceDbus * dbus_interface = NULL;
#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);
@@ -577,11 +579,21 @@ server_added (IndicateListener * listener, IndicateListenerServer * server, gcha
/* 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);
@@ -590,6 +602,50 @@ server_added (IndicateListener * listener, IndicateListenerServer * server, gcha
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
@@ -826,6 +882,15 @@ resort_menu (DbusmenuMenuitem * menushell)
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