diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/app-menu-item.c | 474 | ||||
-rw-r--r-- | src/app-menu-item.h | 17 | ||||
-rw-r--r-- | src/dbus-data.h | 4 | ||||
-rw-r--r-- | src/im-menu-item.c | 586 | ||||
-rw-r--r-- | src/im-menu-item.h | 67 | ||||
-rw-r--r-- | src/messages-service.c | 807 | ||||
-rw-r--r-- | src/status-items.c | 89 | ||||
-rw-r--r-- | src/status-items.h | 4 |
9 files changed, 175 insertions, 1875 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 4fdc8a9..2527878 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,8 +42,6 @@ indicator_messages_service_SOURCES = \ messages-service-dbus.h \ gen-messages-service.xml.h \ gen-messages-service.xml.c \ - im-menu-item.c \ - im-menu-item.h \ app-menu-item.c \ app-menu-item.h \ dbus-data.h \ diff --git a/src/app-menu-item.c b/src/app-menu-item.c index 48aef3e..b5d4994 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -26,17 +26,13 @@ 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 <gio/gio.h> #include <libindicator/indicator-desktop-shortcuts.h> #include "app-menu-item.h" #include "dbus-data.h" enum { - COUNT_CHANGED, NAME_CHANGED, - SHORTCUT_ADDED, - SHORTCUT_REMOVED, LAST_SIGNAL }; @@ -46,18 +42,13 @@ typedef struct _AppMenuItemPrivate AppMenuItemPrivate; struct _AppMenuItemPrivate { - IndicateListener * listener; - IndicateListenerServer * server; - - gchar * type; GDesktopAppInfo * appinfo; guint unreadcount; - DbusmenuClient * client; - DbusmenuMenuitem * root; - GList * shortcuts; - GList * static_shortcuts; IndicatorDesktopShortcuts * ids; + + GMenu *menu; + GSimpleActionGroup *static_shortcuts; }; #define APP_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_MENU_ITEM_TYPE, AppMenuItemPrivate)) @@ -66,16 +57,12 @@ struct _AppMenuItemPrivate static void app_menu_item_class_init (AppMenuItemClass *klass); static void app_menu_item_init (AppMenuItem *self); static void app_menu_item_dispose (GObject *object); -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, const gchar * menupath, gpointer data); -static void desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const gchar * value, gpointer data); -static void update_label (AppMenuItem * self); +static void activate_cb (GSimpleAction *action, + GVariant *param, + gpointer userdata); /* GObject Boilerplate */ -G_DEFINE_TYPE (AppMenuItem, app_menu_item, DBUSMENU_TYPE_MENUITEM); +G_DEFINE_TYPE (AppMenuItem, app_menu_item, G_TYPE_OBJECT); static void app_menu_item_class_init (AppMenuItemClass *klass) @@ -85,15 +72,7 @@ app_menu_item_class_init (AppMenuItemClass *klass) g_type_class_add_private (klass, sizeof (AppMenuItemPrivate)); object_class->dispose = app_menu_item_dispose; - object_class->finalize = app_menu_item_finalize; - signals[COUNT_CHANGED] = g_signal_new(APP_MENU_ITEM_SIGNAL_COUNT_CHANGED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (AppMenuItemClass, count_changed), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); signals[NAME_CHANGED] = g_signal_new(APP_MENU_ITEM_SIGNAL_NAME_CHANGED, G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, @@ -101,22 +80,6 @@ app_menu_item_class_init (AppMenuItemClass *klass) NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); - signals[SHORTCUT_ADDED] = g_signal_new(APP_MENU_ITEM_SIGNAL_SHORTCUT_ADDED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (AppMenuItemClass, shortcut_added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - signals[SHORTCUT_REMOVED] = g_signal_new(APP_MENU_ITEM_SIGNAL_SHORTCUT_REMOVED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (AppMenuItemClass, shortcut_removed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - return; } static void @@ -125,71 +88,29 @@ app_menu_item_init (AppMenuItem *self) g_debug("Building new App Menu Item"); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - priv->listener = NULL; - priv->server = NULL; - priv->type = NULL; priv->appinfo = NULL; priv->unreadcount = 0; - priv->client = NULL; - priv->root = NULL; - priv->shortcuts = NULL; - priv->static_shortcuts = NULL; - - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); + priv->menu = g_menu_new (); + priv->static_shortcuts = g_simple_action_group_new (); return; } -/* A wrapper to make the prototypes work for GFunc */ -static void -func_unref (gpointer data, gpointer user_data) -{ - g_signal_emit(user_data, signals[SHORTCUT_REMOVED], 0, data, TRUE); - g_object_unref(G_OBJECT(data)); - return; -} - -/* Disconnect the count_changed signal and unref the listener */ static void app_menu_item_dispose (GObject *object) { AppMenuItem * self = APP_MENU_ITEM(object); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - 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, object); - g_list_free(priv->shortcuts); - priv->shortcuts = NULL; - } - - if (priv->static_shortcuts != NULL) { - g_list_foreach(priv->static_shortcuts, func_unref, object); - g_list_free(priv->static_shortcuts); - priv->static_shortcuts = NULL; - } + g_clear_object (&priv->menu); + g_clear_object (&priv->static_shortcuts); if (priv->ids != NULL) { g_object_unref(priv->ids); priv->ids = NULL; } - if (priv->root != NULL) { - g_object_unref(priv->root); - priv->root = NULL; - } - - if (priv->client != NULL) { - g_object_unref(priv->client); - priv->client = NULL; - } - if (priv->appinfo != NULL) { g_object_unref(priv->appinfo); priv->appinfo = NULL; @@ -198,34 +119,14 @@ app_menu_item_dispose (GObject *object) G_OBJECT_CLASS (app_menu_item_parent_class)->dispose (object); } -/* Free the memory used by our type, desktop file and application - info structures. */ -static void -app_menu_item_finalize (GObject *object) -{ - AppMenuItem * self = APP_MENU_ITEM(object); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - if (priv->type != NULL) { - g_free(priv->type); - priv->type = NULL; - } - - G_OBJECT_CLASS (app_menu_item_parent_class)->finalize (object); - - return; -} - /* Respond to one of the shortcuts getting clicked on. */ static void -nick_activate_cb (DbusmenuMenuitem * self, guint timestamp, gpointer data) +nick_activate_cb (GSimpleAction *action, + GVariant *param, + gpointer userdata) { - gchar * nick = g_object_get_data(G_OBJECT(self), "ids-nick-data"); - AppMenuItem * mi = APP_MENU_ITEM(data); - - g_return_if_fail(nick != NULL); - g_return_if_fail(mi != NULL); - + const gchar * nick = g_action_get_name (G_ACTION (action)); + AppMenuItem * mi = APP_MENU_ITEM (userdata); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(mi); g_return_if_fail(priv->ids != NULL); @@ -234,29 +135,24 @@ nick_activate_cb (DbusmenuMenuitem * self, guint timestamp, gpointer data) g_warning("Unable to execute nick '%s' for desktop file '%s'", nick, g_desktop_app_info_get_filename (priv->appinfo)); } - - return; } - static void app_menu_item_set_appinfo (AppMenuItem *self, GDesktopAppInfo *appinfo) { AppMenuItemPrivate *priv = APP_MENU_ITEM_GET_PRIVATE (self); + GSimpleAction *launch; + GMenuItem *menuitem; GKeyFile *keyfile; gchar *iconstr = NULL; + gchar *label; g_return_if_fail (appinfo != NULL); g_clear_object (&priv->appinfo); priv->appinfo = g_object_ref (appinfo); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_RUNNING, TRUE); - - update_label(self); - keyfile = g_key_file_new(); g_key_file_load_from_file(keyfile, g_desktop_app_info_get_filename (appinfo), G_KEY_FILE_NONE, NULL); @@ -280,29 +176,47 @@ app_menu_item_set_appinfo (AppMenuItem *self, iconstr = g_icon_to_string(icon); } - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_ICON, iconstr); - g_free(iconstr); + launch = g_simple_action_new ("launch", NULL); + g_signal_connect (launch, "activate", G_CALLBACK (activate_cb), self); + g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (launch)); - g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE); + if (priv->unreadcount > 0) + label = g_strdup_printf("%s (%d)", app_menu_item_get_name (self), priv->unreadcount); + else + label = g_strdup(app_menu_item_get_name (self)); + + menuitem = g_menu_item_new (label, "launch"); + g_menu_item_set_attribute (menuitem, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", iconstr); + g_menu_append_item (priv->menu, menuitem); /* Start to build static shortcuts */ priv->ids = indicator_desktop_shortcuts_new(g_desktop_app_info_get_filename (priv->appinfo), "Messaging Menu"); const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids); gint i; for (i = 0; nicks[i] != NULL; i++) { - DbusmenuMenuitem * mi = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); - g_object_set_data(G_OBJECT(mi), "ids-nick-data", (gpointer)nicks[i]); + gchar *name; + GSimpleAction *action; + GMenuItem *item; - gchar *name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); - dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, name); - g_free(name); + name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); + + action = g_simple_action_new (name, NULL); + g_signal_connect(action, "activate", G_CALLBACK (nick_activate_cb), self); + g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (action)); - g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(nick_activate_cb), self); + item = g_menu_item_new (name, name); + g_menu_append_item (priv->menu, item); - priv->static_shortcuts = g_list_append(priv->static_shortcuts, mi); + g_object_unref (item); + g_free(name); } + g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE); + + g_free(label); + g_free(iconstr); + g_object_unref (launch); + g_object_unref (menuitem); g_key_file_unref(keyfile); } @@ -315,269 +229,19 @@ app_menu_item_new (GDesktopAppInfo *appinfo) return self; } -AppMenuItem * -app_menu_item_new_with_server (IndicateListener * listener, IndicateListenerServer * server) -{ - AppMenuItem * self = g_object_new(APP_MENU_ITEM_TYPE, NULL); - app_menu_item_set_server (self, listener, server); - return self; -} - -void -app_menu_item_set_server (AppMenuItem *self, - IndicateListener *listener, - IndicateListenerServer *server) -{ - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - /* only allow setting this once */ - g_return_if_fail (priv->listener == NULL && priv->server == NULL); - - /* Copy the listener so we can use it later */ - priv->listener = listener; - g_object_ref(G_OBJECT(listener)); - - /* Can not ref as not real GObject */ - priv->server = server; - - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); - - /* Set up listener signals */ - g_signal_connect(G_OBJECT(listener), INDICATE_LISTENER_SIGNAL_SERVER_COUNT_CHANGED, G_CALLBACK(count_changed), self); - - /* 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); - - indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_SERVER_DISPLAY); - indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_SERVER_SIGNAL); - indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_COUNT); - indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_DISPLAY); - indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_SIGNAL); - indicate_listener_set_server_max_indicators(listener, server, MAX_NUMBER_OF_INDICATORS); -} - static void -update_label (AppMenuItem * self) +activate_cb (GSimpleAction *action, + GVariant *param, + gpointer userdata) { - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - const gchar * name = app_menu_item_get_name(self); - - if (priv->unreadcount > 0) { - /* TRANSLATORS: This is the name of the program and the number of indicators. So it - would read something like "Mail Client (5)" */ - gchar * label = g_strdup_printf(_("%s (%d)"), _(name), priv->unreadcount); - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_NAME, label); - g_free(label); - } else { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_NAME, _(name)); - } - - return; -} - -/* Callback to the signal that the server count - has changed to a new value. This checks to see if - it's actually changed and if so signals everyone and - updates the label. */ -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); - - if (priv->unreadcount != count) { - priv->unreadcount = count; - update_label(self); - g_signal_emit(G_OBJECT(self), signals[COUNT_CHANGED], 0, priv->unreadcount, TRUE); - } - - return; -} - -/* Callback for getting the count property off - of the server. */ -static void -count_cb (IndicateListener * listener, IndicateListenerServer * server, guint value, gpointer data) -{ - count_changed(listener, server, value, data); - return; -} - -/* Callback for when we ask the server for the path - to it's desktop file. We then turn it into an - app structure and start sucking data out of it. - Mostly the name. And the icon. */ -static void -desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const gchar * value, gpointer data) -{ - g_return_if_fail(IS_APP_MENU_ITEM(data)); - AppMenuItem * self = APP_MENU_ITEM(data); - GDesktopAppInfo *appinfo; - - if (value == NULL || value[0] == '\0') { - return; - } - - appinfo = g_desktop_app_info_new_from_filename(value); - app_menu_item_set_appinfo (self, appinfo); - g_object_unref (appinfo); -} - -/* 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[SHORTCUT_ADDED], 0, mip, 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); - priv->shortcuts = g_list_remove(priv->shortcuts, mip); - - g_signal_emit(G_OBJECT(data), signals[SHORTCUT_REMOVED], 0, mip, TRUE); - g_object_unref(mip); - } - - 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[SHORTCUT_ADDED], 0, NULL, 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); - - if (priv->root != NULL) { - if (dbusmenu_menuitem_get_children(DBUSMENU_MENUITEM(priv->root)) != NULL) { - g_list_foreach(priv->shortcuts, func_unref, data); - 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; - - if (priv->root != NULL) { - 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) { - 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); - g_signal_emit(G_OBJECT(self), signals[SHORTCUT_ADDED], 0, mip, TRUE); - children = g_list_next(children); - } - } - } - - 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, const 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); + AppMenuItem * mi = APP_MENU_ITEM (userdata); + AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(mi); + GError *error = NULL; - DbusmenuMenuitem * root = dbusmenu_client_get_root(priv->client); - if (root != NULL) { - root_changed(priv->client, root, self); + if (!g_app_info_launch (G_APP_INFO (priv->appinfo), NULL, NULL, &error)) { + g_warning("Unable to execute application for desktop file '%s'", + g_desktop_app_info_get_filename (priv->appinfo)); } - - return; -} - -static void -activate_cb (AppMenuItem * self, guint timestamp, gpointer data) -{ - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - g_return_if_fail (priv->listener != NULL && priv->server != NULL); - - indicate_listener_display(priv->listener, priv->server, NULL, timestamp); - - return; } guint @@ -589,14 +253,6 @@ app_menu_item_get_count (AppMenuItem * appitem) return priv->unreadcount; } -IndicateListenerServer * -app_menu_item_get_server (AppMenuItem * appitem) { - g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - - return priv->server; -} - const gchar * app_menu_item_get_name (AppMenuItem * appitem) { @@ -606,9 +262,6 @@ app_menu_item_get_name (AppMenuItem * appitem) if (priv->appinfo) { return g_app_info_get_name(G_APP_INFO(priv->appinfo)); } - else if (priv->server) { - return INDICATE_LISTENER_SERVER_DBUS_NAME(priv->server); - } return NULL; } @@ -623,13 +276,10 @@ app_menu_item_get_desktop (AppMenuItem * appitem) return NULL; } -/* Get the dynamic items added onto the end of - and app entry. */ -GList * -app_menu_item_get_items (AppMenuItem * appitem) +GMenuModel * +app_menu_item_get_menu (AppMenuItem *appitem) { - g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - return g_list_concat (g_list_copy (priv->shortcuts), - g_list_copy (priv->static_shortcuts)); + return G_MENU_MODEL (priv->menu); } + diff --git a/src/app-menu-item.h b/src/app-menu-item.h index 74efb6a..785a997 100644 --- a/src/app-menu-item.h +++ b/src/app-menu-item.h @@ -22,11 +22,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #ifndef __APP_MENU_ITEM_H__ #define __APP_MENU_ITEM_H__ -#include <glib.h> -#include <glib-object.h> - -#include <libdbusmenu-glib/menuitem.h> -#include <libindicate/listener.h> +#include <gio/gio.h> G_BEGIN_DECLS @@ -46,27 +42,22 @@ typedef struct _AppMenuItem AppMenuItem; typedef struct _AppMenuItemClass AppMenuItemClass; struct _AppMenuItemClass { - DbusmenuMenuitemClass parent_class; + GObjectClass parent_class; void (* count_changed) (guint count); void (* name_changed) (gchar * name); - void (* shortcut_added) (DbusmenuMenuitem * mi); - void (* shortcut_removed) (DbusmenuMenuitem * mi); }; struct _AppMenuItem { - DbusmenuMenuitem parent; + GObject parent; }; GType app_menu_item_get_type (void); AppMenuItem * app_menu_item_new (GDesktopAppInfo *appinfo); -AppMenuItem * app_menu_item_new_with_server (IndicateListener * listener, IndicateListenerServer * server); -void app_menu_item_set_server (AppMenuItem *self, IndicateListener *listener, IndicateListenerServer *server); 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); +GMenuModel * app_menu_item_get_menu (AppMenuItem *appitem); G_END_DECLS diff --git a/src/dbus-data.h b/src/dbus-data.h index 1e82ded..d7efd86 100644 --- a/src/dbus-data.h +++ b/src/dbus-data.h @@ -25,4 +25,8 @@ have a better place to put it. */ #define ICON_KEY "X-Ayatana-Messaging-Menu-Icon" +#define INDICATOR_MENU_ATTRIBUTE_VISIBLE "indicator-visible" +#define INDICATOR_MENU_ATTRIBUTE_ENABLED "indicator-enabled" +#define INDICATOR_MENU_ATTRIBUTE_ICON_NAME "indicator-icon-name" + #endif /* __DBUS_DATA_H__ */ diff --git a/src/im-menu-item.c b/src/im-menu-item.c deleted file mode 100644 index 7466d3e..0000000 --- a/src/im-menu-item.c +++ /dev/null @@ -1,586 +0,0 @@ -/* -An indicator to show information that is in messaging applications -that the user is using. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould <ted@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <glib/gi18n.h> -#include <libdbusmenu-glib/client.h> -#include <libindicate/indicator.h> -#include <libindicate/indicator-messages.h> -#include <libindicate/listener.h> -#include "im-menu-item.h" -#include "dbus-data.h" - -enum { - TIME_CHANGED, - ATTENTION_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -typedef struct _ImMenuItemPrivate ImMenuItemPrivate; - -struct _ImMenuItemPrivate -{ - IndicateListener * listener; - IndicateListenerServer * server; - IndicateListenerIndicator * indicator; - - glong creation_seconds; - glong seconds; - gchar * count; - gulong indicator_changed; - gboolean attention; - gboolean show; - - guint time_update_min; -}; - -#define IM_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IM_MENU_ITEM_TYPE, ImMenuItemPrivate)) - -/* Prototypes */ -static void im_menu_item_class_init (ImMenuItemClass *klass); -static void im_menu_item_init (ImMenuItem *self); -static void im_menu_item_dispose (GObject *object); -static void im_menu_item_finalize (GObject *object); -static void sender_cb (IndicateListener * listener, - IndicateListenerServer * server, - IndicateListenerIndicator * indicator, - gchar * property, - const gchar * propertydata, - gpointer data); -static void time_cb (IndicateListener * listener, - IndicateListenerServer * server, - IndicateListenerIndicator * indicator, - gchar * property, - const GTimeVal * propertydata, - gpointer data); -static void icon_cb (IndicateListener * listener, - IndicateListenerServer * server, - IndicateListenerIndicator * indicator, - gchar * property, - const gchar * propertydata, - gpointer data); -static void activate_cb (ImMenuItem * self, - guint timestamp, - gpointer data); -static void indicator_modified_cb (IndicateListener * listener, - IndicateListenerServer * server, - IndicateListenerIndicator * indicator, - gchar * property, - ImMenuItem * self); - -G_DEFINE_TYPE (ImMenuItem, im_menu_item, DBUSMENU_TYPE_MENUITEM); - -static void -im_menu_item_class_init (ImMenuItemClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (ImMenuItemPrivate)); - - object_class->dispose = im_menu_item_dispose; - object_class->finalize = im_menu_item_finalize; - - signals[TIME_CHANGED] = g_signal_new(IM_MENU_ITEM_SIGNAL_TIME_CHANGED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ImMenuItemClass, time_changed), - NULL, NULL, - g_cclosure_marshal_VOID__LONG, - G_TYPE_NONE, 1, G_TYPE_LONG); - signals[ATTENTION_CHANGED] = g_signal_new(IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ImMenuItemClass, attention_changed), - NULL, NULL, - g_cclosure_marshal_VOID__BOOLEAN, - G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - - return; -} - -static void -im_menu_item_init (ImMenuItem *self) -{ - g_debug("Building new IM Menu Item"); - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - /* Set the variables to NULL, but they should be - configured further down the line. */ - priv->listener = NULL; - priv->server = NULL; - priv->indicator = NULL; - - /* A sane default, but look below */ - priv->creation_seconds = 0; - priv->seconds = 0; - - /* Set the seconds to be the time when the item was - created incase we're not given a better time. */ - GTimeVal current_time; - g_get_current_time(¤t_time); - priv->creation_seconds = current_time.tv_sec; - - return; -} - -static void -im_menu_item_dispose (GObject *object) -{ - G_OBJECT_CLASS (im_menu_item_parent_class)->dispose (object); - - ImMenuItem * self = IM_MENU_ITEM(object); - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - if (priv->time_update_min != 0) { - g_source_remove(priv->time_update_min); - } - - g_signal_handler_disconnect(priv->listener, priv->indicator_changed); - priv->indicator_changed = 0; - - return; -} - -static void -im_menu_item_finalize (GObject *object) -{ - G_OBJECT_CLASS (im_menu_item_parent_class)->finalize (object); -} - -/* Call back for getting icon data. It just passes it along - to the indicator so that it can visualize it. Not our problem. */ -static void -icon_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const gchar * propertydata, gpointer data) -{ - gsize len; - guchar *icon; - icon = g_base64_decode (propertydata, &len); - dbusmenu_menuitem_property_set_byte_array(DBUSMENU_MENUITEM(data), INDICATOR_MENUITEM_PROP_ICON, icon, len); - g_free (icon); - return; -} - -/* This function takes the time and turns it into the appropriate - string to put on the right side of the menu item. Of course it - doesn't do that if there is a count set. If there's a count then - it gets that space. */ -static void -update_time (ImMenuItem * self) -{ - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - /* Count has been set, so it takes priority. */ - if (priv->count != NULL) { - return; - } - - /* Seconds hasn't been set, so we just want to keep the time - area blank. */ - if (priv->seconds == 0) { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_RIGHT, ""); - return; - } - - gchar * timestring = NULL; - - GTimeVal current_time; - g_get_current_time(¤t_time); - - guint elapsed_seconds = current_time.tv_sec - priv->seconds; - guint elapsed_minutes = elapsed_seconds / 60; - - if (elapsed_seconds % 60 > 55) { - /* We're using fuzzy timers, so we need fuzzy comparisons */ - elapsed_minutes += 1; - } - - if (elapsed_minutes < 60) { - /* TRANSLATORS: This string is used to represent the number of minutes - since an IM has occured. It is in the right column - of a menu so being brief is desirable, but one character - is not a requirement. */ - timestring = g_strdup_printf(ngettext("%d m", "%d m", elapsed_minutes), elapsed_minutes); - } else { - guint elapsed_hours = elapsed_minutes / 60; - - if (elapsed_minutes % 60 > 55) { - /* We're using fuzzy timers, so we need fuzzy comparisons */ - elapsed_hours += 1; - } - - /* TRANSLATORS: This string is used to represent the number of hours - since an IM has occured. It is in the right column - of a menu so being brief is desirable, but one character - is not a requirement. */ - timestring = g_strdup_printf(ngettext("%d h", "%d h", elapsed_hours), elapsed_hours); - } - - if (timestring != NULL) { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_RIGHT, timestring); - g_free(timestring); - } - - return; -} - -/* This is a wrapper around update_time that matches the prototype - needed to make this a timer callback. Silly. */ -static gboolean -time_update_cb (gpointer data) -{ - ImMenuItem * self = IM_MENU_ITEM(data); - - update_time(self); - - return TRUE; -} - -/* Yet another time function. This one takes the time as formated as - we get it from libindicate and turns it into the seconds that we're - looking for. It should only be called once at the init with a new - indicator and again when the value changes. */ -static void -time_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const GTimeVal * propertydata, gpointer data) -{ - g_debug("Got Time info"); - ImMenuItem * self = IM_MENU_ITEM(data); - if (self == NULL) { - g_error("Menu Item callback called without a menu item"); - return; - } - - if (property == NULL || g_strcmp0(property, "time")) { - g_warning("Time callback called without being sent the time."); - return; - } - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - priv->seconds = propertydata->tv_sec; - - update_time(self); - - if (priv->time_update_min == 0) { - priv->time_update_min = g_timeout_add_seconds(60, time_update_cb, self); - } - - g_signal_emit(G_OBJECT(self), signals[TIME_CHANGED], 0, priv->seconds, TRUE); - - return; -} - -/* Returns a newly allocated string which is 'str' with all occurences of - * consecutive whitespace collapsed into single space character. */ -static gchar * -collapse_whitespace (const gchar *str) -{ - GString *result; - gboolean in_space = FALSE; - - if (!str) - return NULL; - - result = g_string_sized_new (strlen (str)); - - while (*str) { - gunichar c = g_utf8_get_char_validated (str, -1); - - if (c < 0) - break; - - if (!g_unichar_isspace (c)) { - g_string_append_unichar (result, c); - in_space = FALSE; - } - else if (!in_space) { - g_string_append_c (result, ' '); - in_space = TRUE; - } - - str = g_utf8_next_char (str); - } - - return g_string_free (result, FALSE); -} - -/* Callback from libindicate that is for getting the sender information - on a particular indicator. */ -static void -sender_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const gchar * propertydata, gpointer data) -{ - gchar *label; - - g_debug("Got Sender Information: %s", propertydata); - ImMenuItem * self = IM_MENU_ITEM(data); - - /* Our data should be right */ - g_return_if_fail(self != NULL); - /* We should have a property name */ - g_return_if_fail(property != NULL); - /* The Property should be sender or name */ - g_return_if_fail(!g_strcmp0(property, "sender") || !g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_NAME)); - - /* We might get the sender variable returning a - null string as it doesn't exist on newer clients - but we don't want to listen to that. */ - if (!g_strcmp0(property, "sender") && propertydata[0] == '\0') { - return; - } - - label = collapse_whitespace (propertydata); - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_LABEL, label); - g_free (label); - - return; -} - -/* Callback saying that the count is updated, we need to either put - that on the menu item or just remove it if the count is gone. If - that's the case we can update time. */ -static void -count_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const gchar * propertydata, gpointer data) -{ - g_debug("Got Count Information"); - ImMenuItem * self = IM_MENU_ITEM(data); - - /* Our data should be right */ - g_return_if_fail(self != NULL); - /* We should have a property name */ - g_return_if_fail(property != NULL); - /* The Property should be count */ - g_return_if_fail(!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_COUNT)); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - if (propertydata == NULL || propertydata[0] == '\0') { - /* The count is either being unset or it was never - set in the first place. */ - if (priv->count != NULL) { - g_free(priv->count); - priv->count = NULL; - update_time(self); - dbusmenu_menuitem_property_set_bool (DBUSMENU_MENUITEM (self), - INDICATOR_MENUITEM_PROP_RIGHT_IS_LOZENGE, - FALSE); - } - return; - } - - if (priv->count != NULL) { - g_free(priv->count); - } - - priv->count = g_strdup_printf("%s", propertydata); - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_RIGHT, priv->count); - dbusmenu_menuitem_property_set_bool (DBUSMENU_MENUITEM (self), - INDICATOR_MENUITEM_PROP_RIGHT_IS_LOZENGE, - TRUE); - - return; -} - -/* This is getting the attention variable that's looking at whether - this indicator should be calling for attention or not. If we are, - we need to signal that. */ -static void -attention_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, GVariant * propertydata, gpointer data) -{ - g_debug("Got Attention Information"); - ImMenuItem * self = IM_MENU_ITEM(data); - - /* Our data should be right */ - g_return_if_fail(self != NULL); - /* We should have a property name */ - g_return_if_fail(property != NULL); - /* The Property should be count */ - g_return_if_fail(!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION)); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - gboolean wantit; - if (g_variant_is_of_type(propertydata, G_VARIANT_TYPE_BOOLEAN)) { - wantit = g_variant_get_boolean(propertydata); - } else if (g_variant_is_of_type(propertydata, G_VARIANT_TYPE_STRING)) { - const gchar * propstring = g_variant_get_string(propertydata, NULL); - - if (propstring == NULL || propstring[0] == '\0' || !g_strcmp0(propstring, "false")) { - wantit = FALSE; - } else { - wantit = TRUE; - } - } else { - g_warning("Got property '%s' of an unknown type.", property); - return; - } - - if (priv->attention != wantit) { - priv->attention = wantit; - g_signal_emit(G_OBJECT(self), signals[ATTENTION_CHANGED], 0, wantit, TRUE); - } - - return; -} - -/* Callback when the item gets clicked on from the Messaging Menu */ -static void -activate_cb (ImMenuItem * self, guint timestamp, gpointer data) -{ - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - indicate_listener_display(priv->listener, priv->server, priv->indicator, timestamp); -} - -/* Callback when a property gets modified. It figures out which one - got modified and notifies the appropriate person. */ -void -indicator_modified_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, ImMenuItem * self) -{ - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - /* Not meant for us */ - if (INDICATE_LISTENER_INDICATOR_ID(indicator) != INDICATE_LISTENER_INDICATOR_ID(priv->indicator)) return; - if (server != priv->server) return; - - /* Determine which property has been changed and request the - value go to the appropriate callback. */ - if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_NAME)) { - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_NAME, sender_cb, self); - } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_TIME)) { - indicate_listener_get_property_time(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_TIME, time_cb, self); - } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ICON)) { - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ICON, icon_cb, self); - } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_COUNT)) { - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_COUNT, count_cb, self); - } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION)) { - indicate_listener_get_property_variant(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION, attention_cb, self); - } else if (!g_strcmp0(property, "sender")) { - /* This is a compatibility string with v1 and should be removed */ - g_debug("Indicator is using 'sender' property which is a v1 string."); - indicate_listener_get_property(listener, server, indicator, "sender", sender_cb, self); - } - - return; -} - -ImMenuItem * -im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator) -{ - ImMenuItem * self = g_object_new(IM_MENU_ITEM_TYPE, NULL); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - priv->listener = listener; - priv->server = server; - priv->indicator = indicator; - priv->count = NULL; - priv->time_update_min = 0; - priv->attention = FALSE; - priv->show = TRUE; - - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, INDICATOR_MENUITEM_TYPE); - - indicate_listener_displayed(listener, server, indicator, TRUE); - - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_NAME, sender_cb, self); - indicate_listener_get_property_time(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_TIME, time_cb, self); - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ICON, icon_cb, self); - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_COUNT, count_cb, self); - indicate_listener_get_property_variant(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION, attention_cb, self); - indicate_listener_get_property(listener, server, indicator, "sender", sender_cb, self); - - g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL); - priv->indicator_changed = g_signal_connect(G_OBJECT(listener), INDICATE_LISTENER_SIGNAL_INDICATOR_MODIFIED, G_CALLBACK(indicator_modified_cb), self); - - return self; -} - -/* Gets the number of seconds for the creator - of this item. */ -glong -im_menu_item_get_seconds (ImMenuItem * menuitem) -{ - g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), 0); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem); - - if (priv->seconds == 0) { - return priv->creation_seconds; - } else { - return priv->seconds; - } -} - -/* Gets whether or not this indicator item is - asking for attention or not. */ -gboolean -im_menu_item_get_attention (ImMenuItem * menuitem) -{ - g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), FALSE); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem); - return priv->attention; -} - -/* This takes care of items that need to be hidden, this is - usually because they go over the count of allowed indicators. - Which is more than a little bit silly. We shouldn't do that. - But we need to enforce it to save users against bad apps. */ -void -im_menu_item_show (ImMenuItem * menuitem, gboolean show) -{ - g_return_if_fail(IS_IM_MENU_ITEM(menuitem)); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem); - - if (priv->show == show) { - return; - } - - priv->show = show; - /* Tell the app what we're doing to it. If it's being - punished it needs to know about it. */ - indicate_listener_displayed(priv->listener, priv->server, priv->indicator, priv->show); - if (priv->attention) { - /* If we were asking for attention we can ask for it - again if we're being shown, otherwise no. */ - g_signal_emit(G_OBJECT(menuitem), signals[ATTENTION_CHANGED], 0, priv->show, TRUE); - } - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, priv->show ? "true" : "false"); - - return; -} - -/* Check to see if this item is shown. Accessor for the - internal variable. */ -gboolean -im_menu_item_shown (ImMenuItem * menuitem) -{ - g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), FALSE); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem); - - return priv->show; -} diff --git a/src/im-menu-item.h b/src/im-menu-item.h deleted file mode 100644 index 4279c2e..0000000 --- a/src/im-menu-item.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -An indicator to show information that is in messaging applications -that the user is using. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould <ted@canonical.com> - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see <http://www.gnu.org/licenses/>. -*/ -#ifndef __IM_MENU_ITEM_H__ -#define __IM_MENU_ITEM_H__ - -#include <glib.h> -#include <glib-object.h> - -#include <libdbusmenu-glib/menuitem.h> -#include <libindicate/listener.h> - -G_BEGIN_DECLS - -#define IM_MENU_ITEM_TYPE (im_menu_item_get_type ()) -#define IM_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_MENU_ITEM_TYPE, ImMenuItem)) -#define IM_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_MENU_ITEM_TYPE, ImMenuItemClass)) -#define IS_IM_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_MENU_ITEM_TYPE)) -#define IS_IM_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_MENU_ITEM_TYPE)) -#define IM_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_MENU_ITEM_TYPE, ImMenuItemClass)) - -#define IM_MENU_ITEM_SIGNAL_TIME_CHANGED "time-changed" -#define IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED "attention-changed" - -typedef struct _ImMenuItem ImMenuItem; -typedef struct _ImMenuItemClass ImMenuItemClass; - -struct _ImMenuItemClass { - DbusmenuMenuitemClass parent_class; - - void (*time_changed) (glong seconds); - void (*attention_changed) (gboolean requestit); -}; - -struct _ImMenuItem { - DbusmenuMenuitem parent; -}; - -GType im_menu_item_get_type (void); -ImMenuItem * im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator); -glong im_menu_item_get_seconds (ImMenuItem * menuitem); -gboolean im_menu_item_get_attention (ImMenuItem * menuitem); -void im_menu_item_show (ImMenuItem * menuitem, gboolean show); -gboolean im_menu_item_shown (ImMenuItem * menuitem); - -G_END_DECLS - -#endif - diff --git a/src/messages-service.c b/src/messages-service.c index 0934b9c..432846e 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -25,46 +25,27 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <libintl.h> #include <config.h> #include <pango/pango-utils.h> -#include <libindicate/listener.h> #include <libindicator/indicator-service.h> #include <gio/gio.h> #include <gio/gdesktopappinfo.h> #include <glib/gi18n.h> -#include <libdbusmenu-glib/client.h> -#include <libdbusmenu-glib/server.h> - -#include "im-menu-item.h" #include "app-menu-item.h" #include "dbus-data.h" #include "messages-service-dbus.h" #include "status-items.h" static IndicatorService * service = NULL; -static IndicateListener * listener = NULL; static GList * serverList = NULL; -static DbusmenuMenuitem * root_menuitem = NULL; -static DbusmenuMenuitem * status_separator = NULL; -static DbusmenuMenuitem * clear_attention = NULL; +static GDBusConnection *bus; +static GSimpleActionGroup *actions; +static GMenu *menu; static GSettings *settings; static GMainLoop * mainloop = NULL; static MessageServiceDbus * dbus_interface = NULL; -#define DESKTOP_FILE_GROUP "Messaging Menu" -#define DESKTOP_FILE_KEY_DESKTOP "DesktopFile" - -static void server_shortcut_added (AppMenuItem * appitem, DbusmenuMenuitem * mi, gpointer data); -static void server_shortcut_removed (AppMenuItem * appitem, DbusmenuMenuitem * mi, 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); -static void resort_menu (DbusmenuMenuitem * menushell); -static void indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data); -static gboolean build_launcher (gpointer data); -static gboolean build_launchers (gpointer data); - /* * Server List @@ -72,34 +53,13 @@ static gboolean build_launchers (gpointer data); typedef struct _serverList_t serverList_t; struct _serverList_t { - IndicateListenerServer * server; AppMenuItem * menuitem; - DbusmenuMenuitem * separator; gboolean attention; guint count; GList * imList; }; static gint -serverList_equal (gconstpointer a, gconstpointer b) -{ - serverList_t * pa, * pb; - - pa = (serverList_t *)a; - pb = (serverList_t *)b; - - const gchar * pan = INDICATE_LISTENER_SERVER_DBUS_NAME(pa->server); - const gchar * pbn = INDICATE_LISTENER_SERVER_DBUS_NAME(pb->server); - const gchar * pap = indicate_listener_server_get_dbuspath(pa->server); - const gchar * pbp = indicate_listener_server_get_dbuspath(pb->server); - - if (g_strcmp0(pan, pbn) == 0) - return g_strcmp0(pap, pbp); - else - return 1; -} - -static gint serverList_sort (gconstpointer a, gconstpointer b) { serverList_t * pa, * pb; @@ -113,648 +73,7 @@ serverList_sort (gconstpointer a, gconstpointer b) return g_strcmp0(pan, pbn); } -/* - * Item List - */ - -typedef struct _imList_t imList_t; -struct _imList_t { - IndicateListenerServer * server; - IndicateListenerIndicator * indicator; - DbusmenuMenuitem * menuitem; - gulong timechange_cb; - gulong attentionchange_cb; -}; - -static gboolean -imList_equal (gconstpointer a, gconstpointer b) -{ - imList_t * pa, * pb; - - pa = (imList_t *)a; - pb = (imList_t *)b; - - const gchar * pas = INDICATE_LISTENER_SERVER_DBUS_NAME(pa->server); - const gchar * pbs = INDICATE_LISTENER_SERVER_DBUS_NAME(pb->server); - - guint pai = INDICATE_LISTENER_INDICATOR_ID(pa->indicator); - guint pbi = INDICATE_LISTENER_INDICATOR_ID(pb->indicator); - - g_debug("\tComparing (%s %d) to (%s %d)", pas, pai, pbs, pbi); - - return !((!g_strcmp0(pas, pbs)) && (pai == pbi)); -} - -static gint -imList_sort (gconstpointer a, gconstpointer b) -{ - imList_t * pa, * pb; - - pa = (imList_t *)a; - pb = (imList_t *)b; - - return (gint)(im_menu_item_get_seconds(IM_MENU_ITEM(pb->menuitem)) - im_menu_item_get_seconds(IM_MENU_ITEM(pa->menuitem))); -} - - -/* Goes through all the servers and sees if any of them - want attention. If they do, then well we'll give it - to them. If they don't, let's not bother the user - any, shall we? */ -static void -check_attention (void) -{ - GList * pointer; - for (pointer = serverList; pointer != NULL; pointer = g_list_next(pointer)) { - serverList_t * slt = (serverList_t *)pointer->data; - if (slt->attention) { - message_service_dbus_set_attention(dbus_interface, TRUE); - return; - } - } - message_service_dbus_set_attention(dbus_interface, FALSE); - return; -} - -/* This checks a server listing to see if it should - have attention. It can get attention through it's - count or by having an indicator that is requestion - attention. */ -static void -server_attention (serverList_t * slt) -{ - /* Count, easy yes and out. */ - if (slt->count > 0) { - slt->attention = TRUE; - return; - } - - /* Check to see if any of the indicators want attention */ - GList * pointer; - for (pointer = slt->imList; pointer != NULL; pointer = g_list_next(pointer)) { - imList_t * ilt = (imList_t *)pointer->data; - if (im_menu_item_get_attention(IM_MENU_ITEM(ilt->menuitem))) { - slt->attention = TRUE; - return; - } - } - - /* Nope, no one */ - slt->attention = FALSE; - return; -} - -static void -desktop_cb (IndicateListener *listener, - IndicateListenerServer *server, - const gchar *value, - gpointer data) -{ - DbusmenuMenuitem * menushell = DBUSMENU_MENUITEM(data); - GList *listitem; - serverList_t * sl_item = NULL; - - /* Check to see if we already have a launcher for this app */ - for (listitem = serverList; listitem != NULL; listitem = listitem->next) { - serverList_t * slt = listitem->data; - if (!g_strcmp0(app_menu_item_get_desktop(slt->menuitem), value)) { - sl_item = slt; - break; - } - } - - if (!sl_item) { - /* Build the Menu item */ - AppMenuItem * menuitem = app_menu_item_new_with_server (listener, server); - - /* Build a possible server structure */ - sl_item = g_new0(serverList_t, 1); - sl_item->server = server; - sl_item->menuitem = menuitem; - sl_item->imList = NULL; - sl_item->attention = FALSE; - sl_item->count = 0; - - /* Build a separator */ - sl_item->separator = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(sl_item->separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - - /* 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_SHORTCUT_ADDED, G_CALLBACK(server_shortcut_added), menushell); - g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_SHORTCUT_REMOVED, G_CALLBACK(server_shortcut_removed), 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)); - - /* Incase we got an indicator first */ - GList * alreadythere = g_list_find_custom(serverList, sl_item, serverList_equal); - if (alreadythere != NULL) { - /* Use the one we already had */ - g_free(sl_item); - sl_item = (serverList_t *)alreadythere->data; - sl_item->menuitem = menuitem; - serverList = g_list_sort(serverList, serverList_sort); - } else { - /* Insert the new one in the list */ - serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort); - } - - dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(sl_item->separator)); - } - else { - app_menu_item_set_server (sl_item->menuitem, listener, server); - } - - GList * shortcuts = app_menu_item_get_items(sl_item->menuitem); - GList * shortcut = shortcuts; - while (shortcut != NULL) { - DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(shortcut->data); - g_debug("\tAdding shortcut: %s", dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL)); - dbusmenu_menuitem_child_append(menushell, mi); - shortcut = g_list_next(shortcut); - } - g_list_free (shortcuts); - - resort_menu(menushell); -} - -/* A new server has been created on the indicate bus. - We need to check to see if we like it. And build - structures for it if so. */ -static void -server_added (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data) -{ - g_debug("Server Added '%s' of type '%s'.", INDICATE_LISTENER_SERVER_DBUS_NAME(server), type); - if (type == NULL) { - return; - } - - if (type[0] == '\0') { - return; - } - - if (strncmp(type, "message", strlen("message"))) { - g_debug("\tServer type '%s' is not a message based type.", type); - return; - } - - /* fetch the desktop file before creating the menu item, in case we - * already have a launcher for it */ - indicate_listener_server_get_desktop(listener, server, desktop_cb, data); -} - -/* Server shortcut has been added */ -static void -server_shortcut_added (AppMenuItem * appitem, DbusmenuMenuitem * mi, gpointer data) -{ - g_debug("Application Shortcut added: %s", mi != NULL ? dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL) : "none"); - DbusmenuMenuitem * shell = DBUSMENU_MENUITEM(data); - if (mi != NULL) { - dbusmenu_menuitem_property_set (mi, DBUSMENU_MENUITEM_PROP_ICON_NAME, DBUSMENU_MENUITEM_ICON_NAME_BLANK); - dbusmenu_menuitem_child_append(shell, mi); - } - resort_menu(shell); - return; -} - -/* Server shortcut has been removed */ -static void -server_shortcut_removed (AppMenuItem * appitem, DbusmenuMenuitem * mi, gpointer data) -{ - g_debug("Application Shortcut removed: %s", mi != NULL ? dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL) : "none"); - DbusmenuMenuitem * shell = DBUSMENU_MENUITEM(data); - dbusmenu_menuitem_child_delete(shell, mi); - 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 - file from disk. */ -static void -server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data) -{ - serverList = g_list_sort(serverList, serverList_sort); - resort_menu(DBUSMENU_MENUITEM(data)); - return; -} - -/* If the count on the server changes, we need to know - whether that should be grabbing attention or not. If - it is, we need to reevaluate whether the whole thing - should be grabbing attention or not. */ -static void -server_count_changed (AppMenuItem * appitem, guint count, gpointer data) -{ - serverList_t * slt = (serverList_t *)data; - slt->count = count; - - if (count == 0 && slt->attention) { - /* Regen based on indicators if the count isn't going to cause it. */ - server_attention(slt); - /* If we're dropping let's see if we're the last. */ - if (!slt->attention) { - check_attention(); - } - } - - if (count != 0 && !slt->attention) { - slt->attention = TRUE; - /* Let's tell everyone about us! */ - message_service_dbus_set_attention(dbus_interface, TRUE); - } - - return; -} - -/* Respond to the IM entrie's time changing - which results in it needing to resort the list - and rebuild the menu to match. */ -static void -im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data) -{ - serverList_t * sl = (serverList_t *)data; - sl->imList = g_list_sort(sl->imList, imList_sort); - resort_menu(root_menuitem); - return; -} - -/* The IM entrie's request for attention has changed - so we need to pass that up the stack. */ -static void -im_attention_changed (ImMenuItem * imitem, gboolean requestit, gpointer data) -{ - serverList_t * sl = (serverList_t *)data; - - if (requestit) { - sl->attention = TRUE; - message_service_dbus_set_attention(dbus_interface, TRUE); - } else { - server_attention(sl); - if (!sl->attention) { - check_attention(); - } - } - - return; -} - -/* Run when a server is removed from the indicator bus. It figures - out if we have it somewhere, and if so then we dump it out and - clean up all of it's entries. */ -static void -server_removed (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data) -{ - /* Look for the server */ - g_debug("Removing server: %s", INDICATE_LISTENER_SERVER_DBUS_NAME(server)); - serverList_t slt = {0}; - slt.server = server; - GList * lookup = g_list_find_custom(serverList, &slt, serverList_equal); - - /* If we don't have it, exit */ - if (lookup == NULL) { - g_debug("\tUnable to find server: %s", INDICATE_LISTENER_SERVER_DBUS_NAME(server)); - return; - } - - serverList_t * sltp = (serverList_t *)lookup->data; - - /* Removing indicators from this server */ - while (sltp->imList) { - imList_t * imitem = (imList_t *)sltp->imList->data; - indicator_removed(listener, server, imitem->indicator, data); - } - - /* Remove from the server list */ - serverList = g_list_remove(serverList, sltp); - - /* If there is a menu item, let's get rid of it. */ - if (sltp->menuitem != NULL) { - /* If there are shortcuts remove them */ - GList * shortcuts = app_menu_item_get_items(sltp->menuitem); - GList * shortcut = shortcuts; - while (shortcut != NULL) { - g_debug("\tRemoving shortcut: %s", dbusmenu_menuitem_property_get(DBUSMENU_MENUITEM(shortcut->data), DBUSMENU_MENUITEM_PROP_LABEL)); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(shortcut->data), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(shortcut->data)); - shortcut = g_list_next(shortcut); - } - g_list_free (shortcuts); - - g_debug("\tRemoving item"); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(sltp->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->menuitem)); - g_object_unref(G_OBJECT(sltp->menuitem)); - } else { - g_debug("\tNo menuitem"); - } - - /* If there is a separator, let's get rid of it. */ - if (sltp->separator != NULL) { - g_debug("\tRemoving separator"); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(sltp->separator), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->separator)); - g_object_unref(G_OBJECT(sltp->separator)); - } else { - g_debug("\tNo separator"); - } - - if (sltp->attention) { - /* Check to see if this was the server causing the menu item to - be lit up. */ - check_attention(); - } - - g_free(sltp); - - return; -} - -typedef struct _menushell_location menushell_location_t; -struct _menushell_location { - const IndicateListenerServer * server; - gint position; - gboolean found; -}; - -static void -menushell_foreach_cb (DbusmenuMenuitem * data_mi, gpointer data_ms) { - menushell_location_t * msl = (menushell_location_t *)data_ms; - - if (msl->found) return; - - if (!IS_APP_MENU_ITEM(data_mi)) { - msl->position++; - return; - } - - AppMenuItem * appmenu = APP_MENU_ITEM(data_mi); - if (!g_strcmp0(INDICATE_LISTENER_SERVER_DBUS_NAME((IndicateListenerServer*)msl->server), INDICATE_LISTENER_SERVER_DBUS_NAME(app_menu_item_get_server(appmenu)))) { - GList *shortcuts = app_menu_item_get_items(appmenu); - msl->found = TRUE; - /* Return a position at the end of our shortcuts */ - msl->position += g_list_length(shortcuts); - g_list_free (shortcuts); - - } else { - msl->position++; - } - - return; -} - -/* This function takes care of putting the menu in the right order. - It basically it rebuilds the order by looking through all the - applications and launchers and puts them in the right place. The - menu functions will handle the cases where they don't move so this - is a good way to ensure everything is right. */ -static void -resort_menu (DbusmenuMenuitem * menushell) -{ - guint position = 0; - GList * serverentry; - - g_debug("Reordering Menu:"); - - if (DBUSMENU_IS_MENUITEM(status_separator)) { - position = dbusmenu_menuitem_get_position(status_separator, root_menuitem) + 1; - g_debug("\tPriming with location of status separator: %d", position); - } - - for (serverentry = serverList; serverentry != NULL; serverentry = serverentry->next) { - serverList_t * si = (serverList_t *)serverentry->data; - - /* Putting the app menu item in */ - if (si->menuitem != NULL) { - 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); - GList * shortcut = shortcuts; - while (shortcut != NULL) { - g_debug("\t\tMoving shortcut to position %d", position); - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcut->data), position); - position++; - shortcut = g_list_next(shortcut); - } - g_list_free (shortcuts); - } - - /* Putting all the indicators that are related to this application - after it. */ - GList * imentry; - for (imentry = si->imList; imentry != NULL; imentry = imentry->next) { - imList_t * imi = (imList_t *)imentry->data; - - if (imi->menuitem != NULL) { - g_debug("\tMoving indicator on %s id %d to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(imi->server), INDICATE_LISTENER_INDICATOR_ID(imi->indicator), position); - - if (si->menuitem == NULL || !dbusmenu_menuitem_property_get_bool(DBUSMENU_MENUITEM(si->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE)) { - dbusmenu_menuitem_property_set_bool(imi->menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - } else { - dbusmenu_menuitem_property_set_bool(imi->menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - } - - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(imi->menuitem), position); - position++; - } - } - - /* Lastly putting the separator in */ - if (si->separator != NULL) { - g_debug("\tMoving app %s separator to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position); - - if (si->menuitem == NULL || !dbusmenu_menuitem_property_get_bool(DBUSMENU_MENUITEM(si->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE)) { - dbusmenu_menuitem_property_set_bool(si->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - /* Note, this isn't the last if we can't see it */ - } else { - dbusmenu_menuitem_property_set_bool(si->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - } - - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(si->separator), position); - position++; - } - } - - if (clear_attention != NULL) { - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), clear_attention, position); - position++; /* Not needed, but reduce bugs on code tacked on here, compiler will remove */ - } - - return; -} - -/* Responding to a new indicator showing up on the bus. We - need to create a menuitem for it and start populating the - internal structures to track it. */ -static void -indicator_added (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data) -{ - DbusmenuMenuitem * menushell = DBUSMENU_MENUITEM(data); - if (menushell == NULL) { - g_error("Data in callback is not a menushell"); - return; - } - - imList_t * listItem = g_new0(imList_t, 1); - listItem->server = server; - listItem->indicator = indicator; - - /* Building the IM Menu Item which is a subclass - of DBus Menuitem */ - ImMenuItem * menuitem = im_menu_item_new(listener, server, indicator); - listItem->menuitem = DBUSMENU_MENUITEM(menuitem); - - /* Looking for a server entry to attach this indicator - to. If we can't find one then we have to build one - and attach the indicator to it. */ - serverList_t sl_item_local = {0}; - serverList_t * sl_item = NULL; - sl_item_local.server = server; - GList * serverentry = g_list_find_custom(serverList, &sl_item_local, serverList_equal); - - if (serverentry == NULL) { - /* This sucks, we got an indicator before the server. I guess - that's the joy of being asynchronous */ - sl_item = g_new0(serverList_t, 1); - sl_item->server = server; - sl_item->menuitem = NULL; - sl_item->imList = NULL; - sl_item->attention = FALSE; - sl_item->count = 0; - sl_item->separator = NULL; - - serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort); - } else { - sl_item = (serverList_t *)serverentry->data; - } - - /* Added a this entry into the IM list */ - sl_item->imList = g_list_insert_sorted(sl_item->imList, listItem, imList_sort); - listItem->timechange_cb = g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_TIME_CHANGED, G_CALLBACK(im_time_changed), sl_item); - listItem->attentionchange_cb = g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED, G_CALLBACK(im_attention_changed), sl_item); - - /* Check the length of the list. If we've got more inidactors - than we allow. Well. Someone's gotta pay. Sorry. I didn't - want to do this, but you did it to yourself. */ - if (g_list_length(sl_item->imList) > MAX_NUMBER_OF_INDICATORS) { - GList * indicatoritem; - gint count; - for (indicatoritem = sl_item->imList, count = 0; indicatoritem != NULL; indicatoritem = g_list_next(indicatoritem), count++) { - imList_t * im = (imList_t *)indicatoritem->data; - im_menu_item_show(IM_MENU_ITEM(im->menuitem), count < MAX_NUMBER_OF_INDICATORS); - } - } - - /* Placing the item into the shell. Look to see if - we can find our server and slip in there. Otherwise - we'll just append. */ - menushell_location_t msl; - msl.found = FALSE; - msl.position = 0; - msl.server = server; - - dbusmenu_menuitem_foreach(DBUSMENU_MENUITEM(menushell), menushell_foreach_cb, &msl); - if (msl.found) { - dbusmenu_menuitem_child_add_position(menushell, DBUSMENU_MENUITEM(menuitem), msl.position); - } else { - g_warning("Unable to find server menu item"); - dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem)); - resort_menu (root_menuitem); - } - - return; -} - -/* Process and indicator getting removed from the system. We - first need to ensure that it's one of ours and figure out - where we put it. When we find all that out we can go through - the process of removing the effect it had on the system. */ -static void -indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data) -{ - g_debug("Removing %s %d", INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_INDICATOR_ID(indicator)); - - gboolean removed = FALSE; - - /* Find the server that was related to this item */ - serverList_t sl_item_local = {0}; - serverList_t * sl_item = NULL; - sl_item_local.server = server; - GList * serverentry = g_list_find_custom(serverList, &sl_item_local, serverList_equal); - if (serverentry == NULL) { - /* We didn't care about that server */ - return; - } - sl_item = (serverList_t *)serverentry->data; - - /* Look in the IM Hash Table */ - imList_t listData = {0}; - listData.server = server; - listData.indicator = indicator; - - GList * listItem = g_list_find_custom(sl_item->imList, &listData, imList_equal); - DbusmenuMenuitem * menuitem = NULL; - imList_t * ilt = NULL; - if (listItem != NULL) { - ilt = (imList_t *)listItem->data; - menuitem = ilt->menuitem; - } - - /* If we found a menu item and an imList_t item then - we can go ahead and remove it. Otherwise we can - skip this and exit. */ - if (!removed && menuitem != NULL) { - sl_item->imList = g_list_remove(sl_item->imList, ilt); - g_signal_handler_disconnect(menuitem, ilt->timechange_cb); - g_signal_handler_disconnect(menuitem, ilt->attentionchange_cb); - g_free(ilt); - - if (im_menu_item_get_attention(IM_MENU_ITEM(menuitem)) && im_menu_item_shown(IM_MENU_ITEM(menuitem))) { - /* If the removed indicator menu item was asking for - attention we need to see if this server should still - be asking for attention. */ - server_attention(sl_item); - /* If the server is no longer asking for attention then - we need to check if the whole system should be. */ - if (!sl_item->attention) { - check_attention(); - } - } - - if (im_menu_item_shown(IM_MENU_ITEM(menuitem)) && g_list_length(sl_item->imList) >= MAX_NUMBER_OF_INDICATORS) { - /* In this case we need to show a different indicator - becasue a shown one has left. But we're going to be - easy and set all the values. */ - GList * indicatoritem; - gint count; - for (indicatoritem = sl_item->imList, count = 0; indicatoritem != NULL; indicatoritem = g_list_next(indicatoritem), count++) { - imList_t * im = (imList_t *)indicatoritem->data; - im_menu_item_show(IM_MENU_ITEM(im->menuitem), count < MAX_NUMBER_OF_INDICATORS); - } - } - - /* Hide the item immediately, and then remove it - which might take a little longer. */ - dbusmenu_menuitem_property_set_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), menuitem); - removed = TRUE; - } - - if (!removed) { - g_warning("We were asked to remove %s %d but we didn't.", INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_INDICATOR_ID(indicator)); - } - - return; -} - -/* This function turns a specific file into a menu +/* This function turns a specific desktop id into a menu item and registers it appropriately with everyone */ static gboolean build_launcher (gpointer data) @@ -780,26 +99,12 @@ build_launcher (gpointer data) serverList_t * sl_item = g_new0(serverList_t, 1); sl_item->menuitem = app_menu_item_new(appinfo); - /* Build a separator */ - sl_item->separator = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(sl_item->separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - - /* Add it to the list */ serverList = g_list_insert_sorted (serverList, sl_item, serverList_sort); - /* Add it to the menu */ - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(sl_item->menuitem), DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); - dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(sl_item->menuitem)); - GList * shortcuts = app_menu_item_get_items(sl_item->menuitem); - GList * shortcut = shortcuts; - while (shortcut != NULL) { - dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(shortcut->data)); - shortcut = g_list_next(shortcut); - } - g_list_free (shortcuts); - dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(sl_item->separator)); - - resort_menu(root_menuitem); + /* TODO insert it at the right position (alphabetically by application name) */ + g_menu_insert_section (menu, 2, + app_menu_item_get_name (sl_item->menuitem), + app_menu_item_get_menu (sl_item->menuitem)); } g_object_unref (appinfo); @@ -838,36 +143,34 @@ service_shutdown (IndicatorService * service, gpointer user_data) return; } -/* Respond to changing status by updating the icon that - is on the panel */ static void -status_update_callback (void) +clear_action_activate (GSimpleAction *simple, + GVariant *param, + gpointer user_data) { - return; + MessageServiceDbus *msg_service = user_data; + message_service_dbus_set_attention(msg_service, FALSE); } -/* The clear attention item has been clicked on, what to do? */ static void -clear_attention_activate (DbusmenuMenuitem * mi, guint timestamp, MessageServiceDbus * dbus) +clear_action_handler (MessageServiceDbus *msd, + gboolean attention, + gpointer user_data) { - message_service_dbus_set_attention(dbus, FALSE); - return; + GSimpleAction *action = user_data; + g_simple_action_set_enabled (action, attention); } -/* Handle an update of the active state to ensure that we're - only enabled when we could do something. */ -static void -clear_attention_handler (MessageServiceDbus * msd, gboolean attention, DbusmenuMenuitem * clearitem) -{ - dbusmenu_menuitem_property_set_bool(clearitem, DBUSMENU_MENUITEM_PROP_ENABLED, attention); - return; -} - -/* Oh, if you don't know what main() is for - we really shouldn't be talking. */ int main (int argc, char ** argv) { + GError *error = NULL; + GActionEntry entries[] = { + { "status", NULL, "s", "'offline'", NULL }, + { "clear", clear_action_activate } + }; + GMenuModel *status_items; + /* Glib init */ g_type_init(); @@ -884,36 +187,40 @@ main (int argc, char ** argv) /* Bring up the service DBus interface */ dbus_interface = message_service_dbus_new(); - /* Build the base menu */ - root_menuitem = dbusmenu_menuitem_new(); - DbusmenuServer * server = dbusmenu_server_new(INDICATOR_MESSAGES_DBUS_OBJECT); - dbusmenu_server_set_root(server, root_menuitem); + bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (!bus) { + g_warning ("unable to connect to the session bus: %s", error->message); + g_error_free (error); + return 1; + } + + actions = g_simple_action_group_new (); + g_simple_action_group_add_entries (actions, entries, G_N_ELEMENTS (entries), NULL); + g_dbus_connection_export_action_group (bus, INDICATOR_MESSAGES_DBUS_OBJECT, + G_ACTION_GROUP (actions), &error); + if (error) { + g_warning ("unable to export action group on dbus: %s", error->message); + g_error_free (error); + return 1; + } + + g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED, + G_CALLBACK(clear_action_handler), + g_action_map_lookup_action (G_ACTION_MAP (actions), "clear")); + + status_items = status_items_build (g_action_map_lookup_action (G_ACTION_MAP (actions), "status")); + + menu = g_menu_new (); + g_menu_append_section (menu, _("Status"), status_items); + g_menu_append (menu, _("Clear"), "clear"); - /* Add status items */ - GList * statusitems = status_items_build(&status_update_callback); - while (statusitems != NULL) { - dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(statusitems->data)); - statusitems = g_list_next(statusitems); + g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT, + G_MENU_MODEL (menu), &error); + if (error) { + g_warning ("unable to export menu on dbus: %s", error->message); + g_error_free (error); + return 1; } - status_separator = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(status_separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - dbusmenu_menuitem_child_append(root_menuitem, status_separator); - - /* Add in the clear attention item */ - clear_attention = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(clear_attention, DBUSMENU_MENUITEM_PROP_LABEL, _("Clear")); - dbusmenu_menuitem_child_append(root_menuitem, clear_attention); - g_signal_connect(G_OBJECT(dbus_interface), MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED, G_CALLBACK(clear_attention_handler), clear_attention); - g_signal_connect(G_OBJECT(clear_attention), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(clear_attention_activate), dbus_interface); - - /* Start up the libindicate listener */ - listener = indicate_listener_ref_default(); - serverList = NULL; - - g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_INDICATOR_ADDED, G_CALLBACK(indicator_added), root_menuitem); - g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_INDICATOR_REMOVED, G_CALLBACK(indicator_removed), root_menuitem); - g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_SERVER_ADDED, G_CALLBACK(server_added), root_menuitem); - g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_SERVER_REMOVED, G_CALLBACK(server_removed), root_menuitem); settings = g_settings_new ("com.canonical.indicator.messages"); diff --git a/src/status-items.c b/src/status-items.c index 70a2ad9..a2e3a02 100644 --- a/src/status-items.c +++ b/src/status-items.c @@ -22,10 +22,19 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include <glib.h> #include <glib/gi18n.h> #include <gio/gio.h> -#include <libdbusmenu-glib/dbusmenu-glib.h> #include "status-items.h" #include "status-provider.h" +#include "dbus-data.h" + +static const gchar * status_ids [STATUS_PROVIDER_STATUS_LAST] = { + /* STATUS_PROVIDER_STATUS_ONLINE, */ "available", + /* STATUS_PROVIDER_STATUS_AWAY, */ "away", + /* STATUS_PROVIDER_STATUS_DND */ "busy", + /* STATUS_PROVIDER_STATUS_INVISIBLE */ "invisible", + /* STATUS_PROVIDER_STATUS_OFFLINE, */ "offline", + /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ "offline" +}; static const gchar * status_strings [STATUS_PROVIDER_STATUS_LAST] = { /* STATUS_PROVIDER_STATUS_ONLINE, */ N_("Available"), @@ -66,39 +75,40 @@ static const gchar * panel_active_icons[STATUS_PROVIDER_STATUS_LAST] = { /* Prototypes */ static gboolean provider_directory_parse (gpointer dir); static gboolean load_status_provider (gpointer dir); -static void user_status_change (DbusmenuMenuitem * item, guint timestamp, gpointer pstatus); +static void user_status_change (GSimpleAction *action, + GVariant *value, + gpointer user_data); /* Globals */ static StatusProviderStatus current_status = STATUS_PROVIDER_STATUS_DISCONNECTED; -static GList * menuitems = NULL; +static GMenu * menu; +static GAction *status_action; static GList * status_providers = NULL; -static StatusUpdateFunc update_func = NULL; /* Build the inital status items and start kicking off the async code for handling all the statuses */ -GList * -status_items_build (StatusUpdateFunc status_update_func) +GMenuModel * +status_items_build (GAction *action) { int i; - for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_DISCONNECTED; i++) { - DbusmenuMenuitem * item = dbusmenu_menuitem_new(); + menu = g_menu_new (); - dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, _(status_strings[i])); - dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_ICON_NAME, status_icons[i]); + status_action = action; + g_signal_connect (action, "change-state", G_CALLBACK (user_status_change), NULL); - dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE); + for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_DISCONNECTED; i++) { + GMenuItem *item = g_menu_item_new (_(status_strings[i]), NULL); - dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_RADIO); - dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); + g_menu_item_set_action_and_target (item, g_action_get_name (action), "s", status_ids[i]); - g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(user_status_change), GINT_TO_POINTER(i)); + g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", status_icons[i]); + g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_VISIBLE, "b", TRUE); + g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ENABLED, "b", FALSE); - menuitems = g_list_append(menuitems, item); + g_menu_append_item (menu, item); + g_object_unref (item); } - update_func = status_update_func; - const gchar * status_providers_env = g_getenv("INDICATOR_MESSAGES_STATUS_PROVIDER_DIR"); if (status_providers_env == NULL) { g_idle_add(provider_directory_parse, STATUS_PROVIDER_DIR); @@ -106,7 +116,7 @@ status_items_build (StatusUpdateFunc status_update_func) g_idle_add(provider_directory_parse, (gpointer)status_providers_env); } - return menuitems; + return G_MENU_MODEL (menu); } /* Clean up our globals and stop with all this allocation @@ -155,38 +165,33 @@ update_status (void) current_status = status; - if (update_func != NULL) { - update_func(); - } - - GList * menu; - int i; - for (menu = menuitems, i = 0; menu != NULL && i < STATUS_PROVIDER_STATUS_DISCONNECTED; menu = g_list_next(menu), i++) { - /* If we're the seleced status or if we're disconnected - show the user that we're offline */ - if (i == current_status || (current_status == STATUS_PROVIDER_STATUS_DISCONNECTED && i == STATUS_PROVIDER_STATUS_OFFLINE)) { - dbusmenu_menuitem_property_set_int(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED); - } else { - dbusmenu_menuitem_property_set_int(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); - } - - if (current_status == STATUS_PROVIDER_STATUS_DISCONNECTED) { - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_ENABLED, FALSE); - } else { - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_ENABLED, TRUE); - } - } + g_action_change_state (status_action, g_variant_new_string (status_ids[current_status])); return; } /* Handle the user requesting a status change */ static void -user_status_change (DbusmenuMenuitem * item, guint timestamp, gpointer pstatus) +user_status_change (GSimpleAction *action, + GVariant *value, + gpointer user_data) { - StatusProviderStatus status = GPOINTER_TO_INT(pstatus); + const gchar *status_id; + int i; + StatusProviderStatus status = STATUS_PROVIDER_STATUS_DISCONNECTED; GList * provider; + g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)); + + status_id = g_variant_get_string (value, NULL); + + for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_DISCONNECTED; i++) { + if (!strcmp (status_id, status_ids [i])) { + status = i; + break; + } + } + /* Set each provider to this status */ for (provider = status_providers; provider != NULL; provider = g_list_next(provider)) { status_provider_set_status(STATUS_PROVIDER(provider->data), status); diff --git a/src/status-items.h b/src/status-items.h index fe7900c..ff35dfc 100644 --- a/src/status-items.h +++ b/src/status-items.h @@ -26,9 +26,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. G_BEGIN_DECLS -typedef void (*StatusUpdateFunc) (void); - -GList * status_items_build (StatusUpdateFunc update_func); +GMenuModel * status_items_build (GAction *action); const gchar * status_current_panel_icon (gboolean alert); void status_items_cleanup (void); |