From 97d0cafcae1f64107f786796ead442c0c5401f15 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 1 Nov 2012 17:53:29 +0100 Subject: libmessaging-menu: messaging-menu.[ch] -> messaing-menu-app.[ch] --- libmessaging-menu/Makefile.am | 5 +- libmessaging-menu/messaging-menu-app.c | 1141 ++++++++++++++++++++++++++++++++ libmessaging-menu/messaging-menu-app.h | 148 +++++ libmessaging-menu/messaging-menu.c | 1141 -------------------------------- libmessaging-menu/messaging-menu.h | 125 +--- 5 files changed, 1293 insertions(+), 1267 deletions(-) create mode 100644 libmessaging-menu/messaging-menu-app.c create mode 100644 libmessaging-menu/messaging-menu-app.h delete mode 100644 libmessaging-menu/messaging-menu.c (limited to 'libmessaging-menu') diff --git a/libmessaging-menu/Makefile.am b/libmessaging-menu/Makefile.am index 7a6ee31..ed5655f 100644 --- a/libmessaging-menu/Makefile.am +++ b/libmessaging-menu/Makefile.am @@ -4,12 +4,13 @@ lib_LTLIBRARIES = libmessaging-menu.la libmessaging_menu_ladir = $(includedir)/messaging-menu libmessaging_menu_la_SOURCES = \ - messaging-menu.c \ + messaging-menu-app.c \ gtupleaction.c \ gtupleaction.h \ $(BUILT_SOURCES) libmessaging_menu_la_HEADERS = \ + messaging-menu-app.h \ messaging-menu.h libmessaging_menu_la_LIBADD = $(GIO_LIBS) @@ -52,7 +53,7 @@ MessagingMenu_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 MessagingMenu_1_0_gir_CFLAGS = $(INCLUDES) $(GIO_CFLAGS) MessagingMenu_1_0_gir_SCANNERFLAGS = --c-include="messaging-menu.h" MessagingMenu_1_0_gir_LIBS = libmessaging-menu.la -MessagingMenu_1_0_gir_FILES = messaging-menu.c messaging-menu.h +MessagingMenu_1_0_gir_FILES = messaging-menu-app.c messaging-menu-app.h MessagingMenu_1_0_gir_EXPORT_PACKAGES = messaging-menu INTROSPECTION_GIRS += MessagingMenu-1.0.gir diff --git a/libmessaging-menu/messaging-menu-app.c b/libmessaging-menu/messaging-menu-app.c new file mode 100644 index 0000000..c6a5561 --- /dev/null +++ b/libmessaging-menu/messaging-menu-app.c @@ -0,0 +1,1141 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#include "messaging-menu-app.h" +#include "indicator-messages-service.h" +#include "gtupleaction.h" + +#include + +/** + * SECTION:messaging-menu + * @title: MessagingMenuApp + * @short_description: An application section in the messaging menu + * @include: messaging-menu.h + * + * A #MessagingMenuApp represents an application section in the + * Messaging Menu. An application section is tied to an installed + * application through a desktop file id, which must be passed to + * messaging_menu_app_new(). + * + * To register the application with the Messaging Menu, call + * messaging_menu_app_register(). This signifies that the application + * should be present in the menu and be marked as "running". + * + * The first menu item in an application section represents the + * application itself, using the name and icon found in the associated + * desktop file. Activating this item starts the application. + * + * Following the application item, the Messaging Menu inserts all + * shortcut actions found in the desktop file. Actions whose + * NotShowIn keyword contains "Messaging Menu" or whose + * OnlyShowIn keyword does not contain "Messaging Menu" + * will not appear (the + * desktop file specification contains a detailed explanation of + * shortcut actions.) An application cannot add, remove, or change + * these shortcut items while it is running. + * + * Next, an application section contains menu items for message sources. + * What exactly constitutes a message source depends on the type of + * application: an email client's message sources are folders + * containing new messages, while those of a chat program are persons + * that have contacted the user. + * + * A message source is represented in the menu by a label and optionally + * also an icon. It can be associated with either a count, a time, or + * an arbitrary string, which will appear on the right side of the menu + * item. + * + * When the user activates a source, the source is immediately removed + * from the menu and the "activate-source" signal is emitted. + * + * Applications should always expose all the message sources available. + * However, the Messaging Menu might limit the amount of sources it + * displays to the user. + * + * The Messaging Menu offers users a way to set their chat status + * (available, away, busy, invisible, or offline) for multiple + * applications at once. Applications that appear in the Messaging Menu + * can integrate with this by setting the + * "X-MessagingMenu-UsesChatSection" key in their desktop file to True. + * Use messaging_menu_app_set_status() to signify that the application's + * chat status has changed. When the user changes status through the + * Messaging Menu, the ::status-changed signal will be emitted. + * + * If the application stops running without calling + * messaging_menu_app_unregister(), it will be marked as "not running". + * Its application and shortcut items stay in the menu, but all message + * sources are removed. If messaging_menu_app_unregister() is called, + * the application section is removed completely. + * + * More information about the design and recommended usage of the + * Messaging Menu is available at https://wiki.ubuntu.com/MessagingMenu. + */ + +/** + * MessagingMenuApp: + * + * #MessagingMenuApp is an opaque structure. + */ +struct _MessagingMenuApp +{ + GObject parent_instance; + + GDesktopAppInfo *appinfo; + int registered; /* -1 for unknown */ + MessagingMenuStatus status; + gboolean status_set; + GSimpleActionGroup *source_actions; + GMenu *menu; + + IndicatorMessagesService *messages_service; + guint watch_id; + + GCancellable *cancellable; +}; + +G_DEFINE_TYPE (MessagingMenuApp, messaging_menu_app, G_TYPE_OBJECT); + +enum +{ + INDEX_COUNT, + INDEX_TIME, + INDEX_STRING, + INDEX_DRAWS_ATTENTION +}; + +enum { + PROP_0, + PROP_DESKTOP_ID, + N_PROPERTIES +}; + +enum { + ACTIVATE_SOURCE, + STATUS_CHANGED, + N_SIGNALS +}; + +static GParamSpec *properties[N_PROPERTIES]; +static guint signals[N_SIGNALS]; + +static const gchar *status_ids[] = { "available", "away", "busy", "invisible", "offline" }; + +static void global_status_changed (IndicatorMessagesService *service, + const gchar *status_str, + gpointer user_data); + +static gchar * +messaging_menu_app_get_dbus_object_path (MessagingMenuApp *app) +{ + gchar *path; + + if (!app->appinfo) + return NULL; + + path = g_strconcat ("/com/canonical/indicator/messages/", + g_app_info_get_id (G_APP_INFO (app->appinfo)), + NULL); + + g_strcanon (path, "/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", '_'); + + return path; +} + +static void +export_menus_and_actions (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + MessagingMenuApp *app = user_data; + GDBusConnection *bus; + GError *error = NULL; + guint id; + gchar *object_path; + + object_path = messaging_menu_app_get_dbus_object_path (app); + if (!object_path) + return; + + bus = g_bus_get_finish (res, &error); + if (bus == NULL) + { + g_warning ("unable to connect to session bus: %s", error->message); + g_error_free (error); + return; + } + + id = g_dbus_connection_export_action_group (bus, + object_path, + G_ACTION_GROUP (app->source_actions), + &error); + if (!id) + { + g_warning ("unable to export action group: %s", error->message); + g_error_free (error); + } + + id = g_dbus_connection_export_menu_model (bus, + object_path, + G_MENU_MODEL (app->menu), + &error); + if (!id) + { + g_warning ("unable to export menu: %s", error->message); + g_error_free (error); + } + + g_object_unref (bus); + g_free (object_path); +} + +static void +messaging_menu_app_set_desktop_id (MessagingMenuApp *app, + const gchar *desktop_id) +{ + g_return_if_fail (desktop_id != NULL); + + /* no need to clean up, it's construct only */ + app->appinfo = g_desktop_app_info_new (desktop_id); + if (app->appinfo == NULL) + { + g_warning ("could not find the desktop file for '%s'", + desktop_id); + } + + g_bus_get (G_BUS_TYPE_SESSION, + app->cancellable, + export_menus_and_actions, + app); +} + +static void +messaging_menu_app_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MessagingMenuApp *app = MESSAGING_MENU_APP (object); + + switch (prop_id) + { + case PROP_DESKTOP_ID: + messaging_menu_app_set_desktop_id (app, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +messaging_menu_app_finalize (GObject *object) +{ + G_OBJECT_CLASS (messaging_menu_app_parent_class)->finalize (object); +} + +static void +messaging_menu_app_dispose (GObject *object) +{ + MessagingMenuApp *app = MESSAGING_MENU_APP (object); + + if (app->watch_id > 0) + { + g_bus_unwatch_name (app->watch_id); + app->watch_id = 0; + } + + if (app->cancellable) + { + g_cancellable_cancel (app->cancellable); + g_object_unref (app->cancellable); + app->cancellable = NULL; + } + + if (app->messages_service) + { + g_signal_handlers_disconnect_by_func (app->messages_service, + global_status_changed, + app); + g_clear_object (&app->messages_service); + } + + g_clear_object (&app->appinfo); + g_clear_object (&app->source_actions); + g_clear_object (&app->menu); + + G_OBJECT_CLASS (messaging_menu_app_parent_class)->dispose (object); +} + +static void +messaging_menu_app_class_init (MessagingMenuAppClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->set_property = messaging_menu_app_set_property; + object_class->finalize = messaging_menu_app_finalize; + object_class->dispose = messaging_menu_app_dispose; + + /** + * MessagingMenuApp:desktop-id: + * + * The desktop id of the application associated with this application + * section. Must be given when the #MessagingMenuApp is created. + */ + properties[PROP_DESKTOP_ID] = g_param_spec_string ("desktop-id", + "Desktop Id", + "The desktop id of the associated application", + NULL, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, N_PROPERTIES, properties); + + /** + * MessagingMenuApp::activate-source: + * @mmapp: the #MessagingMenuApp + * @source_id: the source id that was activated + * + * Emitted when the user has activated the message source with id + * @source_id. The source is immediately removed from the menu, + * handlers of this signal do not need to call + * messaging_menu_app_remove_source(). + */ + signals[ACTIVATE_SOURCE] = g_signal_new ("activate-source", + MESSAGING_MENU_TYPE_APP, + G_SIGNAL_RUN_FIRST | + G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + /** + * MessagingMenuApp::status-changed: + * @mmapp: the #MessagingMenuApp + * @status: a #MessagingMenuStatus + * + * Emitted when the chat status is changed through the messaging menu. + * + * Applications which are registered to use the chat status should + * change their status to @status upon receiving this signal. Call + * messaging_menu_app_set_status() to acknowledge that the application + * changed its status. + */ + signals[STATUS_CHANGED] = g_signal_new ("status-changed", + MESSAGING_MENU_TYPE_APP, + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); +} + +static void +created_messages_service (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + MessagingMenuApp *app = user_data; + GError *error = NULL; + + app->messages_service = indicator_messages_service_proxy_new_finish (result, &error); + if (!app->messages_service) + { + g_warning ("unable to connect to the mesaging menu service: %s", error->message); + g_error_free (error); + return; + } + + g_signal_connect (app->messages_service, "status-changed", + G_CALLBACK (global_status_changed), app); + + /* sync current status */ + if (app->registered == TRUE) + messaging_menu_app_register (app); + else if (app->registered == FALSE) + messaging_menu_app_unregister (app); + if (app->status_set) + messaging_menu_app_set_status (app, app->status); +} + +static void +indicator_messages_appeared (GDBusConnection *bus, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + MessagingMenuApp *app = user_data; + + indicator_messages_service_proxy_new (bus, + G_DBUS_PROXY_FLAGS_NONE, + "com.canonical.indicator.messages", + "/com/canonical/indicator/messages/service", + app->cancellable, + created_messages_service, + app); +} + +static void +indicator_messages_vanished (GDBusConnection *bus, + const gchar *name, + gpointer user_data) +{ + MessagingMenuApp *app = user_data; + + if (app->messages_service) + { + g_signal_handlers_disconnect_by_func (app->messages_service, + global_status_changed, + app); + g_clear_object (&app->messages_service); + } +} + +static void +messaging_menu_app_init (MessagingMenuApp *app) +{ + app->registered = -1; + app->status_set = FALSE; + + app->cancellable = g_cancellable_new (); + + app->source_actions = g_simple_action_group_new (); + app->menu = g_menu_new (); + + app->cancellable = g_cancellable_new (); + + app->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "com.canonical.indicator.messages", + G_BUS_NAME_WATCHER_FLAGS_NONE, + indicator_messages_appeared, + indicator_messages_vanished, + app, + NULL); +} + +/** + * messaging_menu_new: + * @desktop_id: a desktop file id. See g_desktop_app_info_new() + * + * Creates a new #MessagingMenuApp for the application associated with + * @desktop_id. + * + * The application will not show up (nor be marked as "running") in the + * Messaging Menu before messaging_menu_app_register() has been called. + * + * Returns: (transfer full): a new #MessagingMenuApp + */ +MessagingMenuApp * +messaging_menu_app_new (const gchar *desktop_id) +{ + return g_object_new (MESSAGING_MENU_TYPE_APP, + "desktop-id", desktop_id, + NULL); +} + +/** + * messaging_menu_app_register: + * @app: a #MessagingMenuApp + * + * Registers @app with the Messaging Menu. + * + * If the application doesn't already have a section in the Messaging + * Menu, one will be created for it. The application will also be + * marked as "running". + * + * The application will be marked as "not running" as soon as @app is + * destroyed. The application launcher as well as shortcut actions will + * remain in the menu. To completely remove the application section + * from the Messaging Menu, call messaging_menu_app_unregister(). + */ +void +messaging_menu_app_register (MessagingMenuApp *app) +{ + gchar *object_path; + + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + + app->registered = TRUE; + + /* state will be synced right after connecting to the service */ + if (!app->messages_service) + return; + + object_path = messaging_menu_app_get_dbus_object_path (app); + if (!object_path) + return; + + indicator_messages_service_call_register_application (app->messages_service, + g_app_info_get_id (G_APP_INFO (app->appinfo)), + object_path, + app->cancellable, + NULL, NULL); + + g_free (object_path); +} + +/** + * messaging_menu_app_unregister: + * @app: a #MessagingMenuApp + * + * Completely removes the @app from the Messaging Menu. If the + * application's launcher and shortcut actions should remain in the + * menu, destroying @app with g_object_unref() suffices. + * + * Note: @app will remain valid and usable after this call. + */ +void +messaging_menu_app_unregister (MessagingMenuApp *app) +{ + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + + app->registered = FALSE; + + /* state will be synced right after connecting to the service */ + if (!app->messages_service) + return; + + if (!app->appinfo) + return; + + indicator_messages_service_call_unregister_application (app->messages_service, + g_app_info_get_id (G_APP_INFO (app->appinfo)), + app->cancellable, + NULL, NULL); +} + +/** + * messaging_menu_app_set_status: + * @app: a #MessagingMenuApp + * @status: a #MessagingMenuStatus + * + * Notify the Messaging Menu that the chat status of @app has changed to + * @status. + * + * Connect to the ::status-changed signal to receive notification about + * the user changing their global chat status through the Messaging + * Menu. + * + * This function does nothing for applications whose desktop file does + * not include X-MessagingMenu-UsesChatSection. + */ +void +messaging_menu_app_set_status (MessagingMenuApp *app, + MessagingMenuStatus status) +{ + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (status >= MESSAGING_MENU_STATUS_AVAILABLE && + status <= MESSAGING_MENU_STATUS_OFFLINE); + + app->status = status; + app->status_set = TRUE; + + /* state will be synced right after connecting to the service */ + if (!app->messages_service) + return; + + if (!app->appinfo) + return; + + indicator_messages_service_call_set_status (app->messages_service, + g_app_info_get_id (G_APP_INFO (app->appinfo)), + status_ids [status], + app->cancellable, + NULL, NULL); +} + +static int +status_from_string (const gchar *s) +{ + int i; + + if (!s) + return -1; + + for (i = 0; i <= MESSAGING_MENU_STATUS_OFFLINE; i++) + { + if (g_str_equal (s, status_ids[i])) + return i; + } + + return -1; +} + +static void +global_status_changed (IndicatorMessagesService *service, + const gchar *status_str, + gpointer user_data) +{ + MessagingMenuApp *app = user_data; + int status; + + status = status_from_string (status_str); + g_return_if_fail (status >= 0); + + g_signal_emit (app, signals[STATUS_CHANGED], 0, status); +} + +static void +source_action_activated (GTupleAction *action, + GVariant *parameter, + gpointer user_data) +{ + MessagingMenuApp *app = user_data; + const gchar *name = g_action_get_name (G_ACTION (action)); + GQuark q = g_quark_from_string (name); + + messaging_menu_app_remove_source (app, name); + + g_signal_emit (app, signals[ACTIVATE_SOURCE], q, name); +} + +static void +messaging_menu_app_insert_source_action (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + GVariant *state) +{ + GTupleAction *action; + GMenuItem *menuitem; + + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (id != NULL); + + if (g_simple_action_group_lookup (app->source_actions, id)) + { + g_warning ("a source with id '%s' already exists", id); + return; + } + + action = g_tuple_action_new (id, state); + g_signal_connect (action, "activate", + G_CALLBACK (source_action_activated), app); + g_simple_action_group_insert (app->source_actions, G_ACTION (action)); + g_object_unref (action); + + menuitem = g_menu_item_new (label, id); + g_menu_item_set_attribute (menuitem, "x-canonical-type", "s", "ImSourceMenuItem"); + if (icon) + { + gchar *iconstr = g_icon_to_string (icon); + g_menu_item_set_attribute (menuitem, "x-canonical-icon", "s", iconstr); + g_free (iconstr); + } + g_menu_insert_item (app->menu, position, menuitem); + g_object_unref (menuitem); +} + +static void +messaging_menu_app_set_source_action (MessagingMenuApp *app, + const gchar *source_id, + gsize index, + GVariant *child) +{ + GAction *action; + + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (source_id != NULL); + + action = g_simple_action_group_lookup (app->source_actions, source_id); + if (action == NULL) + { + g_warning ("a source with id '%s' doesn't exist", source_id); + return; + } + + g_tuple_action_set_child (G_TUPLE_ACTION (action), index, child); +} + +/** + * messaging_menu_app_insert_source: + * @app: a #MessagingMenuApp + * @position: the position at which to insert the source + * @id: a unique identifier for the source to be added + * @icon: the icon associated with the source + * @label: a user-visible string best describing the source + * + * Inserts a new message source into the section representing @app. Equivalent + * to calling messaging_menu_app_insert_source_with_time() with the current + * time. + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_insert_source (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label) +{ + messaging_menu_app_insert_source_with_time (app, position, id, icon, label, + g_get_real_time ()); +} + +/** + * messaging_menu_app_append_source: + * @app: a #MessagingMenuApp + * @id: a unique identifier for the source to be added + * @icon: (allow-none): the icon associated with the source + * @label: a user-visible string best describing the source + * + * Appends a new message source to the end of the section representing @app. + * Equivalent to calling messaging_menu_app_append_source_with_time() with the + * current time. + * + * It is an error to add a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_append_source (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label) +{ + messaging_menu_app_insert_source (app, -1, id, icon, label); +} + +/** + * messaging_menu_app_insert_source_with_count: + * @app: a #MessagingMenuApp + * @position: the position at which to insert the source + * @id: a unique identifier for the source to be added + * @icon: (allow-none): the icon associated with the source + * @label: a user-visible string best describing the source + * @count: the count for the source + * + * Inserts a new message source into the section representing @app and + * initializes it with @count. + * + * To update the count, use messaging_menu_app_set_source_count(). + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_insert_source_with_count (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + guint count) +{ + messaging_menu_app_insert_source_action (app, position, id, icon, label, + g_variant_new ("(uxsb)", count, 0, "", FALSE)); +} + +/** + * messaging_menu_app_append_source_with_count: + * @app: a #MessagingMenuApp + * @id: a unique identifier for the source to be added + * @icon: (allow-none): the icon associated with the source + * @label: a user-visible string best describing the source + * @count: the count for the source + * + * Appends a new message source to the end of the section representing @app and + * initializes it with @count. + * + * To update the count, use messaging_menu_app_set_source_count(). + * + * It is an error to add a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void messaging_menu_app_append_source_with_count (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + guint count) +{ + messaging_menu_app_insert_source_with_count (app, -1, id, icon, label, count); +} + +/** + * messaging_menu_app_insert_source_with_time: + * @app: a #MessagingMenuApp + * @position: the position at which to insert the source + * @id: a unique identifier for the source to be added + * @icon: (allow-none): the icon associated with the source + * @label: a user-visible string best describing the source + * @time: the time when the source was created, in microseconds + * + * Inserts a new message source into the section representing @app and + * initializes it with @time. Use messaging_menu_app_insert_source() to + * insert a source with the current time. + * + * To change the time, use messaging_menu_app_set_source_time(). + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_insert_source_with_time (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + gint64 time) +{ + messaging_menu_app_insert_source_action (app, position, id, icon, label, + g_variant_new ("(uxsb)", 0, time, "", FALSE)); +} + +/** + * messaging_menu_app_append_source_with_time: + * @app: a #MessagingMenuApp + * @id: a unique identifier for the source to be added + * @icon: (allow-none): the icon associated with the source + * @label: a user-visible string best describing the source + * @time: the time when the source was created, in microseconds + * + * Appends a new message source to the end of the section representing + * @app and initializes it with @time. Use + * messaging_menu_app_append_source() to append a source with the + * current time. + * + * To change the time, use messaging_menu_app_set_source_time(). + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_append_source_with_time (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + gint64 time) +{ + messaging_menu_app_insert_source_with_time (app, -1, id, icon, label, time); +} + +/** + * messaging_menu_app_insert_source_with_string: + * @app: a #MessagingMenuApp + * @position: the position at which to insert the source + * @id: a unique identifier for the source to be added + * @icon: (allow-none): the icon associated with the source + * @label: a user-visible string best describing the source + * @str: a string associated with the source + * + * Inserts a new message source into the section representing @app and + * initializes it with @str. + * + * To update the string, use messaging_menu_app_set_source_string(). + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_insert_source_with_string (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + const gchar *str) +{ + messaging_menu_app_insert_source_action (app, position, id, icon, label, + g_variant_new ("(uxsb)", 0, 0, str, FALSE)); +} + +/** + * messaging_menu_app_append_source_with_string: + * @app: a #MessagingMenuApp + * @id: a unique identifier for the source to be added + * @icon: (allow-none): the icon associated with the source + * @label: a user-visible string best describing the source + * @str: a string associated with the source + * + * Appends a new message source to the end of the section representing @app and + * initializes it with @str. + * + * To update the string, use messaging_menu_app_set_source_string(). + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_append_source_with_string (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + const gchar *str) +{ + messaging_menu_app_insert_source_with_string (app, -1, id, icon, label, str); +} + +/** + * messaging_menu_app_remove_source: + * @app: a #MessagingMenuApp + * @source_id: the id of the source to remove + * + * Removes the source corresponding to @source_id from the menu. + */ +void +messaging_menu_app_remove_source (MessagingMenuApp *app, + const gchar *source_id) +{ + int n_items; + int i; + + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (source_id != NULL); + + if (g_simple_action_group_lookup (app->source_actions, source_id) == NULL) + return; + + n_items = g_menu_model_get_n_items (G_MENU_MODEL (app->menu)); + for (i = 0; i < n_items; i++) + { + gchar *action; + + if (g_menu_model_get_item_attribute (G_MENU_MODEL (app->menu), i, + "action", "s", &action)) + { + if (!g_strcmp0 (action, source_id)) + { + g_menu_remove (app->menu, i); + break; + } + + g_free (action); + } + } + + g_simple_action_group_remove (app->source_actions, source_id); +} + +/** + * messaging_menu_app_has_source: + * @app: a #MessagingMenuApp + * @source_id: a source id + * + * Returns: TRUE if there is a source associated with @source_id + */ +gboolean +messaging_menu_app_has_source (MessagingMenuApp *app, + const gchar *source_id) +{ + g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), FALSE); + g_return_val_if_fail (source_id != NULL, FALSE); + + return g_simple_action_group_lookup (app->source_actions, source_id) != NULL; +} + +static GMenuItem * +g_menu_find_item_with_action (GMenu *menu, + const gchar *action, + gint *out_pos) +{ + gint i; + gint n_elements; + GMenuItem *item = NULL; + + n_elements = g_menu_model_get_n_items (G_MENU_MODEL (menu)); + + for (i = 0; i < n_elements && item == NULL; i++) + { + GVariant *attr; + + item = g_menu_item_new_from_model (G_MENU_MODEL (menu), i); + attr = g_menu_item_get_attribute_value (item, G_MENU_ATTRIBUTE_ACTION, G_VARIANT_TYPE_STRING); + + if (!g_str_equal (action, g_variant_get_string (attr, NULL))) + g_clear_object (&item); + + g_variant_unref (attr); + } + + if (item && out_pos) + *out_pos = i - 1; + + return item; +} + +static void +g_menu_replace_item (GMenu *menu, + gint pos, + GMenuItem *item) +{ + g_menu_remove (menu, pos); + g_menu_insert_item (menu, pos, item); +} + +/** + * messaging_menu_app_set_source_label: + * @app: a #MessagingMenuApp + * @source_id: a source id + * @label: the new label for the source + * + * Changes the label of @source_id to @label. + */ +void +messaging_menu_app_set_source_label (MessagingMenuApp *app, + const gchar *source_id, + const gchar *label) +{ + gint pos; + GMenuItem *item; + + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (source_id != NULL); + g_return_if_fail (label != NULL); + + item = g_menu_find_item_with_action (app->menu, source_id, &pos); + if (item == NULL) + return; + + g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_LABEL, "s", label); + g_menu_replace_item (app->menu, pos, item); + + g_object_unref (item); +} + +/** + * messaging_menu_app_set_source_icon: + * @app: a #MessagingMenuApp + * @source_id: a source id + * @icon: the new icon for the source + * + * Changes the icon of @source_id to @icon. + */ +void +messaging_menu_app_set_source_icon (MessagingMenuApp *app, + const gchar *source_id, + GIcon *icon) +{ + gint pos; + GMenuItem *item; + gchar *iconstr; + + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (source_id != NULL); + + item = g_menu_find_item_with_action (app->menu, source_id, &pos); + if (item == NULL) + return; + + iconstr = icon ? g_icon_to_string (icon) : NULL; + g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr); + g_menu_replace_item (app->menu, pos, item); + + g_free (iconstr); + g_object_unref (item); +} + +/** + * messaging_menu_app_set_source_count: + * @app: a #MessagingMenuApp + * @source_id: a source id + * @count: the new count for the source + * + * Updates the count of @source_id to @count. + */ +void messaging_menu_app_set_source_count (MessagingMenuApp *app, + const gchar *source_id, + guint count) +{ + messaging_menu_app_set_source_action (app, source_id, INDEX_COUNT, + g_variant_new_uint32 (count)); +} + +/** + * messaging_menu_app_set_source_time: + * @app: a #MessagingMenuApp + * @source_id: a source id + * @time: the new time for the source, in microseconds + * + * Updates the time of @source_id to @time. + * + * Note that the time is only displayed if the source does not also have a + * count associated with it. + */ +void +messaging_menu_app_set_source_time (MessagingMenuApp *app, + const gchar *source_id, + gint64 time) +{ + messaging_menu_app_set_source_action (app, source_id, INDEX_TIME, + g_variant_new_int64 (time)); +} + +/** + * messaging_menu_app_set_source_string: + * @app: a #MessagingMenuApp + * @source_id: a source id + * @str: the new string for the source + * + * Updates the string displayed next to @source_id to @str. + * + * Note that the string is only displayed if the source does not also have a + * count or time associated with it. + */ +void +messaging_menu_app_set_source_string (MessagingMenuApp *app, + const gchar *source_id, + const gchar *str) +{ + messaging_menu_app_set_source_action (app, source_id, INDEX_STRING, + g_variant_new_string (str)); +} + +/** + * messaging_menu_app_draw_attention: + * @app: a #MessagingMenuApp + * @source_id: a source id + * + * Indicates that @source_id has important unread messages. Currently, this + * means that the messaging menu's envelope icon will turn blue. + * + * Use messaging_menu_app_remove_attention() to stop indicating that the source + * needs attention. + */ +void +messaging_menu_app_draw_attention (MessagingMenuApp *app, + const gchar *source_id) +{ + messaging_menu_app_set_source_action (app, source_id, INDEX_DRAWS_ATTENTION, + g_variant_new_boolean (TRUE)); +} + +/** + * messaging_menu_app_remove_attention: + * @app: a #MessagingMenuApp + * @source_id: a source id + * + * Stop indicating that @source_id needs attention. + * + * This function does not need to be called when the source is removed + * with messaging_menu_app_remove_source() or the user has activated the + * source. + * + * Use messaging_menu_app_draw_attention() to make @source_id draw attention + * again. + */ +void +messaging_menu_app_remove_attention (MessagingMenuApp *app, + const gchar *source_id) +{ + messaging_menu_app_set_source_action (app, source_id, INDEX_DRAWS_ATTENTION, + g_variant_new_boolean (FALSE)); +} diff --git a/libmessaging-menu/messaging-menu-app.h b/libmessaging-menu/messaging-menu-app.h new file mode 100644 index 0000000..b9415ff --- /dev/null +++ b/libmessaging-menu/messaging-menu-app.h @@ -0,0 +1,148 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#ifndef __messaging_menu_app_h__ +#define __messaging_menu_app_h__ + +#include + +G_BEGIN_DECLS + +#define MESSAGING_MENU_TYPE_APP messaging_menu_app_get_type() +#define MESSAGING_MENU_APP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MESSAGING_MENU_TYPE_APP, MessagingMenuApp)) +#define MESSAGING_MENU_APP_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), MESSAGING_MENU_TYPE_APP, MessagingMenuAppClass)) +#define MESSAGING_MENU_IS_APP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MESSAGING_MENU_TYPE_APP)) + +/** + * MessagingMenuStatus: + * @MESSAGING_MENU_STATUS_AVAILABLE: available + * @MESSAGING_MENU_STATUS_AWAY: away + * @MESSAGING_MENU_STATUS_BUSY: busy + * @MESSAGING_MENU_STATUS_INVISIBLE: invisible + * @MESSAGING_MENU_STATUS_OFFLINE: offline + * + * An enumeration for the possible chat statuses the messaging menu can be in. + */ +typedef enum { + MESSAGING_MENU_STATUS_AVAILABLE, + MESSAGING_MENU_STATUS_AWAY, + MESSAGING_MENU_STATUS_BUSY, + MESSAGING_MENU_STATUS_INVISIBLE, + MESSAGING_MENU_STATUS_OFFLINE +} MessagingMenuStatus; + + +typedef GObjectClass MessagingMenuAppClass; +typedef struct _MessagingMenuApp MessagingMenuApp; + +GType messaging_menu_app_get_type (void) G_GNUC_CONST; + +MessagingMenuApp * messaging_menu_app_new (const gchar *desktop_id); + +void messaging_menu_app_register (MessagingMenuApp *app); +void messaging_menu_app_unregister (MessagingMenuApp *app); + +void messaging_menu_app_set_status (MessagingMenuApp *app, + MessagingMenuStatus status); + +void messaging_menu_app_insert_source (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label); + +void messaging_menu_app_append_source (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label); + +void messaging_menu_app_insert_source_with_count (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + guint count); + +void messaging_menu_app_append_source_with_count (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + guint count); + +void messaging_menu_app_insert_source_with_time (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + gint64 time); + +void messaging_menu_app_append_source_with_time (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + gint64 time); + +void messaging_menu_app_append_source_with_string (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + const gchar *str); + +void messaging_menu_app_insert_source_with_string (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + const gchar *str); + +void messaging_menu_app_remove_source (MessagingMenuApp *app, + const gchar *source_id); + +gboolean messaging_menu_app_has_source (MessagingMenuApp *app, + const gchar *source_id); + +void messaging_menu_app_set_source_label (MessagingMenuApp *app, + const gchar *source_id, + const gchar *label); + +void messaging_menu_app_set_source_icon (MessagingMenuApp *app, + const gchar *source_id, + GIcon *icon); + +void messaging_menu_app_set_source_count (MessagingMenuApp *app, + const gchar *source_id, + guint count); + +void messaging_menu_app_set_source_time (MessagingMenuApp *app, + const gchar *source_id, + gint64 time); + +void messaging_menu_app_set_source_string (MessagingMenuApp *app, + const gchar *source_id, + const gchar *str); + +void messaging_menu_app_draw_attention (MessagingMenuApp *app, + const gchar *source_id); + +void messaging_menu_app_remove_attention (MessagingMenuApp *app, + const gchar *source_id); + +G_END_DECLS + +#endif diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c deleted file mode 100644 index 70861d3..0000000 --- a/libmessaging-menu/messaging-menu.c +++ /dev/null @@ -1,1141 +0,0 @@ -/* - * Copyright 2012 Canonical Ltd. - * - * 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 . - * - * Authors: - * Lars Uebernickel - */ - -#include "messaging-menu.h" -#include "indicator-messages-service.h" -#include "gtupleaction.h" - -#include - -/** - * SECTION:messaging-menu - * @title: MessagingMenuApp - * @short_description: An application section in the messaging menu - * @include: messaging-menu.h - * - * A #MessagingMenuApp represents an application section in the - * Messaging Menu. An application section is tied to an installed - * application through a desktop file id, which must be passed to - * messaging_menu_app_new(). - * - * To register the application with the Messaging Menu, call - * messaging_menu_app_register(). This signifies that the application - * should be present in the menu and be marked as "running". - * - * The first menu item in an application section represents the - * application itself, using the name and icon found in the associated - * desktop file. Activating this item starts the application. - * - * Following the application item, the Messaging Menu inserts all - * shortcut actions found in the desktop file. Actions whose - * NotShowIn keyword contains "Messaging Menu" or whose - * OnlyShowIn keyword does not contain "Messaging Menu" - * will not appear (the - * desktop file specification contains a detailed explanation of - * shortcut actions.) An application cannot add, remove, or change - * these shortcut items while it is running. - * - * Next, an application section contains menu items for message sources. - * What exactly constitutes a message source depends on the type of - * application: an email client's message sources are folders - * containing new messages, while those of a chat program are persons - * that have contacted the user. - * - * A message source is represented in the menu by a label and optionally - * also an icon. It can be associated with either a count, a time, or - * an arbitrary string, which will appear on the right side of the menu - * item. - * - * When the user activates a source, the source is immediately removed - * from the menu and the "activate-source" signal is emitted. - * - * Applications should always expose all the message sources available. - * However, the Messaging Menu might limit the amount of sources it - * displays to the user. - * - * The Messaging Menu offers users a way to set their chat status - * (available, away, busy, invisible, or offline) for multiple - * applications at once. Applications that appear in the Messaging Menu - * can integrate with this by setting the - * "X-MessagingMenu-UsesChatSection" key in their desktop file to True. - * Use messaging_menu_app_set_status() to signify that the application's - * chat status has changed. When the user changes status through the - * Messaging Menu, the ::status-changed signal will be emitted. - * - * If the application stops running without calling - * messaging_menu_app_unregister(), it will be marked as "not running". - * Its application and shortcut items stay in the menu, but all message - * sources are removed. If messaging_menu_app_unregister() is called, - * the application section is removed completely. - * - * More information about the design and recommended usage of the - * Messaging Menu is available at https://wiki.ubuntu.com/MessagingMenu. - */ - -/** - * MessagingMenuApp: - * - * #MessagingMenuApp is an opaque structure. - */ -struct _MessagingMenuApp -{ - GObject parent_instance; - - GDesktopAppInfo *appinfo; - int registered; /* -1 for unknown */ - MessagingMenuStatus status; - gboolean status_set; - GSimpleActionGroup *source_actions; - GMenu *menu; - - IndicatorMessagesService *messages_service; - guint watch_id; - - GCancellable *cancellable; -}; - -G_DEFINE_TYPE (MessagingMenuApp, messaging_menu_app, G_TYPE_OBJECT); - -enum -{ - INDEX_COUNT, - INDEX_TIME, - INDEX_STRING, - INDEX_DRAWS_ATTENTION -}; - -enum { - PROP_0, - PROP_DESKTOP_ID, - N_PROPERTIES -}; - -enum { - ACTIVATE_SOURCE, - STATUS_CHANGED, - N_SIGNALS -}; - -static GParamSpec *properties[N_PROPERTIES]; -static guint signals[N_SIGNALS]; - -static const gchar *status_ids[] = { "available", "away", "busy", "invisible", "offline" }; - -static void global_status_changed (IndicatorMessagesService *service, - const gchar *status_str, - gpointer user_data); - -static gchar * -messaging_menu_app_get_dbus_object_path (MessagingMenuApp *app) -{ - gchar *path; - - if (!app->appinfo) - return NULL; - - path = g_strconcat ("/com/canonical/indicator/messages/", - g_app_info_get_id (G_APP_INFO (app->appinfo)), - NULL); - - g_strcanon (path, "/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", '_'); - - return path; -} - -static void -export_menus_and_actions (GObject *source, - GAsyncResult *res, - gpointer user_data) -{ - MessagingMenuApp *app = user_data; - GDBusConnection *bus; - GError *error = NULL; - guint id; - gchar *object_path; - - object_path = messaging_menu_app_get_dbus_object_path (app); - if (!object_path) - return; - - bus = g_bus_get_finish (res, &error); - if (bus == NULL) - { - g_warning ("unable to connect to session bus: %s", error->message); - g_error_free (error); - return; - } - - id = g_dbus_connection_export_action_group (bus, - object_path, - G_ACTION_GROUP (app->source_actions), - &error); - if (!id) - { - g_warning ("unable to export action group: %s", error->message); - g_error_free (error); - } - - id = g_dbus_connection_export_menu_model (bus, - object_path, - G_MENU_MODEL (app->menu), - &error); - if (!id) - { - g_warning ("unable to export menu: %s", error->message); - g_error_free (error); - } - - g_object_unref (bus); - g_free (object_path); -} - -static void -messaging_menu_app_set_desktop_id (MessagingMenuApp *app, - const gchar *desktop_id) -{ - g_return_if_fail (desktop_id != NULL); - - /* no need to clean up, it's construct only */ - app->appinfo = g_desktop_app_info_new (desktop_id); - if (app->appinfo == NULL) - { - g_warning ("could not find the desktop file for '%s'", - desktop_id); - } - - g_bus_get (G_BUS_TYPE_SESSION, - app->cancellable, - export_menus_and_actions, - app); -} - -static void -messaging_menu_app_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MessagingMenuApp *app = MESSAGING_MENU_APP (object); - - switch (prop_id) - { - case PROP_DESKTOP_ID: - messaging_menu_app_set_desktop_id (app, g_value_get_string (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -messaging_menu_app_finalize (GObject *object) -{ - G_OBJECT_CLASS (messaging_menu_app_parent_class)->finalize (object); -} - -static void -messaging_menu_app_dispose (GObject *object) -{ - MessagingMenuApp *app = MESSAGING_MENU_APP (object); - - if (app->watch_id > 0) - { - g_bus_unwatch_name (app->watch_id); - app->watch_id = 0; - } - - if (app->cancellable) - { - g_cancellable_cancel (app->cancellable); - g_object_unref (app->cancellable); - app->cancellable = NULL; - } - - if (app->messages_service) - { - g_signal_handlers_disconnect_by_func (app->messages_service, - global_status_changed, - app); - g_clear_object (&app->messages_service); - } - - g_clear_object (&app->appinfo); - g_clear_object (&app->source_actions); - g_clear_object (&app->menu); - - G_OBJECT_CLASS (messaging_menu_app_parent_class)->dispose (object); -} - -static void -messaging_menu_app_class_init (MessagingMenuAppClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - - object_class->set_property = messaging_menu_app_set_property; - object_class->finalize = messaging_menu_app_finalize; - object_class->dispose = messaging_menu_app_dispose; - - /** - * MessagingMenuApp:desktop-id: - * - * The desktop id of the application associated with this application - * section. Must be given when the #MessagingMenuApp is created. - */ - properties[PROP_DESKTOP_ID] = g_param_spec_string ("desktop-id", - "Desktop Id", - "The desktop id of the associated application", - NULL, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (object_class, N_PROPERTIES, properties); - - /** - * MessagingMenuApp::activate-source: - * @mmapp: the #MessagingMenuApp - * @source_id: the source id that was activated - * - * Emitted when the user has activated the message source with id - * @source_id. The source is immediately removed from the menu, - * handlers of this signal do not need to call - * messaging_menu_app_remove_source(). - */ - signals[ACTIVATE_SOURCE] = g_signal_new ("activate-source", - MESSAGING_MENU_TYPE_APP, - G_SIGNAL_RUN_FIRST | - G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); - - /** - * MessagingMenuApp::status-changed: - * @mmapp: the #MessagingMenuApp - * @status: a #MessagingMenuStatus - * - * Emitted when the chat status is changed through the messaging menu. - * - * Applications which are registered to use the chat status should - * change their status to @status upon receiving this signal. Call - * messaging_menu_app_set_status() to acknowledge that the application - * changed its status. - */ - signals[STATUS_CHANGED] = g_signal_new ("status-changed", - MESSAGING_MENU_TYPE_APP, - G_SIGNAL_RUN_FIRST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); -} - -static void -created_messages_service (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - MessagingMenuApp *app = user_data; - GError *error = NULL; - - app->messages_service = indicator_messages_service_proxy_new_finish (result, &error); - if (!app->messages_service) - { - g_warning ("unable to connect to the mesaging menu service: %s", error->message); - g_error_free (error); - return; - } - - g_signal_connect (app->messages_service, "status-changed", - G_CALLBACK (global_status_changed), app); - - /* sync current status */ - if (app->registered == TRUE) - messaging_menu_app_register (app); - else if (app->registered == FALSE) - messaging_menu_app_unregister (app); - if (app->status_set) - messaging_menu_app_set_status (app, app->status); -} - -static void -indicator_messages_appeared (GDBusConnection *bus, - const gchar *name, - const gchar *name_owner, - gpointer user_data) -{ - MessagingMenuApp *app = user_data; - - indicator_messages_service_proxy_new (bus, - G_DBUS_PROXY_FLAGS_NONE, - "com.canonical.indicator.messages", - "/com/canonical/indicator/messages/service", - app->cancellable, - created_messages_service, - app); -} - -static void -indicator_messages_vanished (GDBusConnection *bus, - const gchar *name, - gpointer user_data) -{ - MessagingMenuApp *app = user_data; - - if (app->messages_service) - { - g_signal_handlers_disconnect_by_func (app->messages_service, - global_status_changed, - app); - g_clear_object (&app->messages_service); - } -} - -static void -messaging_menu_app_init (MessagingMenuApp *app) -{ - app->registered = -1; - app->status_set = FALSE; - - app->cancellable = g_cancellable_new (); - - app->source_actions = g_simple_action_group_new (); - app->menu = g_menu_new (); - - app->cancellable = g_cancellable_new (); - - app->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, - "com.canonical.indicator.messages", - G_BUS_NAME_WATCHER_FLAGS_NONE, - indicator_messages_appeared, - indicator_messages_vanished, - app, - NULL); -} - -/** - * messaging_menu_new: - * @desktop_id: a desktop file id. See g_desktop_app_info_new() - * - * Creates a new #MessagingMenuApp for the application associated with - * @desktop_id. - * - * The application will not show up (nor be marked as "running") in the - * Messaging Menu before messaging_menu_app_register() has been called. - * - * Returns: (transfer full): a new #MessagingMenuApp - */ -MessagingMenuApp * -messaging_menu_app_new (const gchar *desktop_id) -{ - return g_object_new (MESSAGING_MENU_TYPE_APP, - "desktop-id", desktop_id, - NULL); -} - -/** - * messaging_menu_app_register: - * @app: a #MessagingMenuApp - * - * Registers @app with the Messaging Menu. - * - * If the application doesn't already have a section in the Messaging - * Menu, one will be created for it. The application will also be - * marked as "running". - * - * The application will be marked as "not running" as soon as @app is - * destroyed. The application launcher as well as shortcut actions will - * remain in the menu. To completely remove the application section - * from the Messaging Menu, call messaging_menu_app_unregister(). - */ -void -messaging_menu_app_register (MessagingMenuApp *app) -{ - gchar *object_path; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - - app->registered = TRUE; - - /* state will be synced right after connecting to the service */ - if (!app->messages_service) - return; - - object_path = messaging_menu_app_get_dbus_object_path (app); - if (!object_path) - return; - - indicator_messages_service_call_register_application (app->messages_service, - g_app_info_get_id (G_APP_INFO (app->appinfo)), - object_path, - app->cancellable, - NULL, NULL); - - g_free (object_path); -} - -/** - * messaging_menu_app_unregister: - * @app: a #MessagingMenuApp - * - * Completely removes the @app from the Messaging Menu. If the - * application's launcher and shortcut actions should remain in the - * menu, destroying @app with g_object_unref() suffices. - * - * Note: @app will remain valid and usable after this call. - */ -void -messaging_menu_app_unregister (MessagingMenuApp *app) -{ - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - - app->registered = FALSE; - - /* state will be synced right after connecting to the service */ - if (!app->messages_service) - return; - - if (!app->appinfo) - return; - - indicator_messages_service_call_unregister_application (app->messages_service, - g_app_info_get_id (G_APP_INFO (app->appinfo)), - app->cancellable, - NULL, NULL); -} - -/** - * messaging_menu_app_set_status: - * @app: a #MessagingMenuApp - * @status: a #MessagingMenuStatus - * - * Notify the Messaging Menu that the chat status of @app has changed to - * @status. - * - * Connect to the ::status-changed signal to receive notification about - * the user changing their global chat status through the Messaging - * Menu. - * - * This function does nothing for applications whose desktop file does - * not include X-MessagingMenu-UsesChatSection. - */ -void -messaging_menu_app_set_status (MessagingMenuApp *app, - MessagingMenuStatus status) -{ - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (status >= MESSAGING_MENU_STATUS_AVAILABLE && - status <= MESSAGING_MENU_STATUS_OFFLINE); - - app->status = status; - app->status_set = TRUE; - - /* state will be synced right after connecting to the service */ - if (!app->messages_service) - return; - - if (!app->appinfo) - return; - - indicator_messages_service_call_set_status (app->messages_service, - g_app_info_get_id (G_APP_INFO (app->appinfo)), - status_ids [status], - app->cancellable, - NULL, NULL); -} - -static int -status_from_string (const gchar *s) -{ - int i; - - if (!s) - return -1; - - for (i = 0; i <= MESSAGING_MENU_STATUS_OFFLINE; i++) - { - if (g_str_equal (s, status_ids[i])) - return i; - } - - return -1; -} - -static void -global_status_changed (IndicatorMessagesService *service, - const gchar *status_str, - gpointer user_data) -{ - MessagingMenuApp *app = user_data; - int status; - - status = status_from_string (status_str); - g_return_if_fail (status >= 0); - - g_signal_emit (app, signals[STATUS_CHANGED], 0, status); -} - -static void -source_action_activated (GTupleAction *action, - GVariant *parameter, - gpointer user_data) -{ - MessagingMenuApp *app = user_data; - const gchar *name = g_action_get_name (G_ACTION (action)); - GQuark q = g_quark_from_string (name); - - messaging_menu_app_remove_source (app, name); - - g_signal_emit (app, signals[ACTIVATE_SOURCE], q, name); -} - -static void -messaging_menu_app_insert_source_action (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label, - GVariant *state) -{ - GTupleAction *action; - GMenuItem *menuitem; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (id != NULL); - - if (g_simple_action_group_lookup (app->source_actions, id)) - { - g_warning ("a source with id '%s' already exists", id); - return; - } - - action = g_tuple_action_new (id, state); - g_signal_connect (action, "activate", - G_CALLBACK (source_action_activated), app); - g_simple_action_group_insert (app->source_actions, G_ACTION (action)); - g_object_unref (action); - - menuitem = g_menu_item_new (label, id); - g_menu_item_set_attribute (menuitem, "x-canonical-type", "s", "ImSourceMenuItem"); - if (icon) - { - gchar *iconstr = g_icon_to_string (icon); - g_menu_item_set_attribute (menuitem, "x-canonical-icon", "s", iconstr); - g_free (iconstr); - } - g_menu_insert_item (app->menu, position, menuitem); - g_object_unref (menuitem); -} - -static void -messaging_menu_app_set_source_action (MessagingMenuApp *app, - const gchar *source_id, - gsize index, - GVariant *child) -{ - GAction *action; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (source_id != NULL); - - action = g_simple_action_group_lookup (app->source_actions, source_id); - if (action == NULL) - { - g_warning ("a source with id '%s' doesn't exist", source_id); - return; - } - - g_tuple_action_set_child (G_TUPLE_ACTION (action), index, child); -} - -/** - * messaging_menu_app_insert_source: - * @app: a #MessagingMenuApp - * @position: the position at which to insert the source - * @id: a unique identifier for the source to be added - * @icon: the icon associated with the source - * @label: a user-visible string best describing the source - * - * Inserts a new message source into the section representing @app. Equivalent - * to calling messaging_menu_app_insert_source_with_time() with the current - * time. - * - * It is an error to insert a source with an @id which already exists. Use - * messaging_menu_app_has_source() to find out whether there is such a source. - */ -void -messaging_menu_app_insert_source (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label) -{ - messaging_menu_app_insert_source_with_time (app, position, id, icon, label, - g_get_real_time ()); -} - -/** - * messaging_menu_app_append_source: - * @app: a #MessagingMenuApp - * @id: a unique identifier for the source to be added - * @icon: (allow-none): the icon associated with the source - * @label: a user-visible string best describing the source - * - * Appends a new message source to the end of the section representing @app. - * Equivalent to calling messaging_menu_app_append_source_with_time() with the - * current time. - * - * It is an error to add a source with an @id which already exists. Use - * messaging_menu_app_has_source() to find out whether there is such a source. - */ -void -messaging_menu_app_append_source (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label) -{ - messaging_menu_app_insert_source (app, -1, id, icon, label); -} - -/** - * messaging_menu_app_insert_source_with_count: - * @app: a #MessagingMenuApp - * @position: the position at which to insert the source - * @id: a unique identifier for the source to be added - * @icon: (allow-none): the icon associated with the source - * @label: a user-visible string best describing the source - * @count: the count for the source - * - * Inserts a new message source into the section representing @app and - * initializes it with @count. - * - * To update the count, use messaging_menu_app_set_source_count(). - * - * It is an error to insert a source with an @id which already exists. Use - * messaging_menu_app_has_source() to find out whether there is such a source. - */ -void -messaging_menu_app_insert_source_with_count (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label, - guint count) -{ - messaging_menu_app_insert_source_action (app, position, id, icon, label, - g_variant_new ("(uxsb)", count, 0, "", FALSE)); -} - -/** - * messaging_menu_app_append_source_with_count: - * @app: a #MessagingMenuApp - * @id: a unique identifier for the source to be added - * @icon: (allow-none): the icon associated with the source - * @label: a user-visible string best describing the source - * @count: the count for the source - * - * Appends a new message source to the end of the section representing @app and - * initializes it with @count. - * - * To update the count, use messaging_menu_app_set_source_count(). - * - * It is an error to add a source with an @id which already exists. Use - * messaging_menu_app_has_source() to find out whether there is such a source. - */ -void messaging_menu_app_append_source_with_count (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label, - guint count) -{ - messaging_menu_app_insert_source_with_count (app, -1, id, icon, label, count); -} - -/** - * messaging_menu_app_insert_source_with_time: - * @app: a #MessagingMenuApp - * @position: the position at which to insert the source - * @id: a unique identifier for the source to be added - * @icon: (allow-none): the icon associated with the source - * @label: a user-visible string best describing the source - * @time: the time when the source was created, in microseconds - * - * Inserts a new message source into the section representing @app and - * initializes it with @time. Use messaging_menu_app_insert_source() to - * insert a source with the current time. - * - * To change the time, use messaging_menu_app_set_source_time(). - * - * It is an error to insert a source with an @id which already exists. Use - * messaging_menu_app_has_source() to find out whether there is such a source. - */ -void -messaging_menu_app_insert_source_with_time (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label, - gint64 time) -{ - messaging_menu_app_insert_source_action (app, position, id, icon, label, - g_variant_new ("(uxsb)", 0, time, "", FALSE)); -} - -/** - * messaging_menu_app_append_source_with_time: - * @app: a #MessagingMenuApp - * @id: a unique identifier for the source to be added - * @icon: (allow-none): the icon associated with the source - * @label: a user-visible string best describing the source - * @time: the time when the source was created, in microseconds - * - * Appends a new message source to the end of the section representing - * @app and initializes it with @time. Use - * messaging_menu_app_append_source() to append a source with the - * current time. - * - * To change the time, use messaging_menu_app_set_source_time(). - * - * It is an error to insert a source with an @id which already exists. Use - * messaging_menu_app_has_source() to find out whether there is such a source. - */ -void -messaging_menu_app_append_source_with_time (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label, - gint64 time) -{ - messaging_menu_app_insert_source_with_time (app, -1, id, icon, label, time); -} - -/** - * messaging_menu_app_insert_source_with_string: - * @app: a #MessagingMenuApp - * @position: the position at which to insert the source - * @id: a unique identifier for the source to be added - * @icon: (allow-none): the icon associated with the source - * @label: a user-visible string best describing the source - * @str: a string associated with the source - * - * Inserts a new message source into the section representing @app and - * initializes it with @str. - * - * To update the string, use messaging_menu_app_set_source_string(). - * - * It is an error to insert a source with an @id which already exists. Use - * messaging_menu_app_has_source() to find out whether there is such a source. - */ -void -messaging_menu_app_insert_source_with_string (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label, - const gchar *str) -{ - messaging_menu_app_insert_source_action (app, position, id, icon, label, - g_variant_new ("(uxsb)", 0, 0, str, FALSE)); -} - -/** - * messaging_menu_app_append_source_with_string: - * @app: a #MessagingMenuApp - * @id: a unique identifier for the source to be added - * @icon: (allow-none): the icon associated with the source - * @label: a user-visible string best describing the source - * @str: a string associated with the source - * - * Appends a new message source to the end of the section representing @app and - * initializes it with @str. - * - * To update the string, use messaging_menu_app_set_source_string(). - * - * It is an error to insert a source with an @id which already exists. Use - * messaging_menu_app_has_source() to find out whether there is such a source. - */ -void -messaging_menu_app_append_source_with_string (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label, - const gchar *str) -{ - messaging_menu_app_insert_source_with_string (app, -1, id, icon, label, str); -} - -/** - * messaging_menu_app_remove_source: - * @app: a #MessagingMenuApp - * @source_id: the id of the source to remove - * - * Removes the source corresponding to @source_id from the menu. - */ -void -messaging_menu_app_remove_source (MessagingMenuApp *app, - const gchar *source_id) -{ - int n_items; - int i; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (source_id != NULL); - - if (g_simple_action_group_lookup (app->source_actions, source_id) == NULL) - return; - - n_items = g_menu_model_get_n_items (G_MENU_MODEL (app->menu)); - for (i = 0; i < n_items; i++) - { - gchar *action; - - if (g_menu_model_get_item_attribute (G_MENU_MODEL (app->menu), i, - "action", "s", &action)) - { - if (!g_strcmp0 (action, source_id)) - { - g_menu_remove (app->menu, i); - break; - } - - g_free (action); - } - } - - g_simple_action_group_remove (app->source_actions, source_id); -} - -/** - * messaging_menu_app_has_source: - * @app: a #MessagingMenuApp - * @source_id: a source id - * - * Returns: TRUE if there is a source associated with @source_id - */ -gboolean -messaging_menu_app_has_source (MessagingMenuApp *app, - const gchar *source_id) -{ - g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), FALSE); - g_return_val_if_fail (source_id != NULL, FALSE); - - return g_simple_action_group_lookup (app->source_actions, source_id) != NULL; -} - -static GMenuItem * -g_menu_find_item_with_action (GMenu *menu, - const gchar *action, - gint *out_pos) -{ - gint i; - gint n_elements; - GMenuItem *item = NULL; - - n_elements = g_menu_model_get_n_items (G_MENU_MODEL (menu)); - - for (i = 0; i < n_elements && item == NULL; i++) - { - GVariant *attr; - - item = g_menu_item_new_from_model (G_MENU_MODEL (menu), i); - attr = g_menu_item_get_attribute_value (item, G_MENU_ATTRIBUTE_ACTION, G_VARIANT_TYPE_STRING); - - if (!g_str_equal (action, g_variant_get_string (attr, NULL))) - g_clear_object (&item); - - g_variant_unref (attr); - } - - if (item && out_pos) - *out_pos = i - 1; - - return item; -} - -static void -g_menu_replace_item (GMenu *menu, - gint pos, - GMenuItem *item) -{ - g_menu_remove (menu, pos); - g_menu_insert_item (menu, pos, item); -} - -/** - * messaging_menu_app_set_source_label: - * @app: a #MessagingMenuApp - * @source_id: a source id - * @label: the new label for the source - * - * Changes the label of @source_id to @label. - */ -void -messaging_menu_app_set_source_label (MessagingMenuApp *app, - const gchar *source_id, - const gchar *label) -{ - gint pos; - GMenuItem *item; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (source_id != NULL); - g_return_if_fail (label != NULL); - - item = g_menu_find_item_with_action (app->menu, source_id, &pos); - if (item == NULL) - return; - - g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_LABEL, "s", label); - g_menu_replace_item (app->menu, pos, item); - - g_object_unref (item); -} - -/** - * messaging_menu_app_set_source_icon: - * @app: a #MessagingMenuApp - * @source_id: a source id - * @icon: the new icon for the source - * - * Changes the icon of @source_id to @icon. - */ -void -messaging_menu_app_set_source_icon (MessagingMenuApp *app, - const gchar *source_id, - GIcon *icon) -{ - gint pos; - GMenuItem *item; - gchar *iconstr; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (source_id != NULL); - - item = g_menu_find_item_with_action (app->menu, source_id, &pos); - if (item == NULL) - return; - - iconstr = icon ? g_icon_to_string (icon) : NULL; - g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr); - g_menu_replace_item (app->menu, pos, item); - - g_free (iconstr); - g_object_unref (item); -} - -/** - * messaging_menu_app_set_source_count: - * @app: a #MessagingMenuApp - * @source_id: a source id - * @count: the new count for the source - * - * Updates the count of @source_id to @count. - */ -void messaging_menu_app_set_source_count (MessagingMenuApp *app, - const gchar *source_id, - guint count) -{ - messaging_menu_app_set_source_action (app, source_id, INDEX_COUNT, - g_variant_new_uint32 (count)); -} - -/** - * messaging_menu_app_set_source_time: - * @app: a #MessagingMenuApp - * @source_id: a source id - * @time: the new time for the source, in microseconds - * - * Updates the time of @source_id to @time. - * - * Note that the time is only displayed if the source does not also have a - * count associated with it. - */ -void -messaging_menu_app_set_source_time (MessagingMenuApp *app, - const gchar *source_id, - gint64 time) -{ - messaging_menu_app_set_source_action (app, source_id, INDEX_TIME, - g_variant_new_int64 (time)); -} - -/** - * messaging_menu_app_set_source_string: - * @app: a #MessagingMenuApp - * @source_id: a source id - * @str: the new string for the source - * - * Updates the string displayed next to @source_id to @str. - * - * Note that the string is only displayed if the source does not also have a - * count or time associated with it. - */ -void -messaging_menu_app_set_source_string (MessagingMenuApp *app, - const gchar *source_id, - const gchar *str) -{ - messaging_menu_app_set_source_action (app, source_id, INDEX_STRING, - g_variant_new_string (str)); -} - -/** - * messaging_menu_app_draw_attention: - * @app: a #MessagingMenuApp - * @source_id: a source id - * - * Indicates that @source_id has important unread messages. Currently, this - * means that the messaging menu's envelope icon will turn blue. - * - * Use messaging_menu_app_remove_attention() to stop indicating that the source - * needs attention. - */ -void -messaging_menu_app_draw_attention (MessagingMenuApp *app, - const gchar *source_id) -{ - messaging_menu_app_set_source_action (app, source_id, INDEX_DRAWS_ATTENTION, - g_variant_new_boolean (TRUE)); -} - -/** - * messaging_menu_app_remove_attention: - * @app: a #MessagingMenuApp - * @source_id: a source id - * - * Stop indicating that @source_id needs attention. - * - * This function does not need to be called when the source is removed - * with messaging_menu_app_remove_source() or the user has activated the - * source. - * - * Use messaging_menu_app_draw_attention() to make @source_id draw attention - * again. - */ -void -messaging_menu_app_remove_attention (MessagingMenuApp *app, - const gchar *source_id) -{ - messaging_menu_app_set_source_action (app, source_id, INDEX_DRAWS_ATTENTION, - g_variant_new_boolean (FALSE)); -} diff --git a/libmessaging-menu/messaging-menu.h b/libmessaging-menu/messaging-menu.h index 6c405c7..929b229 100644 --- a/libmessaging-menu/messaging-menu.h +++ b/libmessaging-menu/messaging-menu.h @@ -20,129 +20,6 @@ #ifndef __messaging_menu_h__ #define __messaging_menu_h__ -#include - -G_BEGIN_DECLS - -#define MESSAGING_MENU_TYPE_APP messaging_menu_app_get_type() -#define MESSAGING_MENU_APP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MESSAGING_MENU_TYPE_APP, MessagingMenuApp)) -#define MESSAGING_MENU_APP_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), MESSAGING_MENU_TYPE_APP, MessagingMenuAppClass)) -#define MESSAGING_MENU_IS_APP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MESSAGING_MENU_TYPE_APP)) - -/** - * MessagingMenuStatus: - * @MESSAGING_MENU_STATUS_AVAILABLE: available - * @MESSAGING_MENU_STATUS_AWAY: away - * @MESSAGING_MENU_STATUS_BUSY: busy - * @MESSAGING_MENU_STATUS_INVISIBLE: invisible - * @MESSAGING_MENU_STATUS_OFFLINE: offline - * - * An enumeration for the possible chat statuses the messaging menu can be in. - */ -typedef enum { - MESSAGING_MENU_STATUS_AVAILABLE, - MESSAGING_MENU_STATUS_AWAY, - MESSAGING_MENU_STATUS_BUSY, - MESSAGING_MENU_STATUS_INVISIBLE, - MESSAGING_MENU_STATUS_OFFLINE -} MessagingMenuStatus; - - -typedef GObjectClass MessagingMenuAppClass; -typedef struct _MessagingMenuApp MessagingMenuApp; - -GType messaging_menu_app_get_type (void) G_GNUC_CONST; - -MessagingMenuApp * messaging_menu_app_new (const gchar *desktop_id); - -void messaging_menu_app_register (MessagingMenuApp *app); -void messaging_menu_app_unregister (MessagingMenuApp *app); - -void messaging_menu_app_set_status (MessagingMenuApp *app, - MessagingMenuStatus status); - -void messaging_menu_app_insert_source (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label); - -void messaging_menu_app_append_source (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label); - -void messaging_menu_app_insert_source_with_count (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label, - guint count); - -void messaging_menu_app_append_source_with_count (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label, - guint count); - -void messaging_menu_app_insert_source_with_time (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label, - gint64 time); - -void messaging_menu_app_append_source_with_time (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label, - gint64 time); - -void messaging_menu_app_append_source_with_string (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label, - const gchar *str); - -void messaging_menu_app_insert_source_with_string (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label, - const gchar *str); - -void messaging_menu_app_remove_source (MessagingMenuApp *app, - const gchar *source_id); - -gboolean messaging_menu_app_has_source (MessagingMenuApp *app, - const gchar *source_id); - -void messaging_menu_app_set_source_label (MessagingMenuApp *app, - const gchar *source_id, - const gchar *label); - -void messaging_menu_app_set_source_icon (MessagingMenuApp *app, - const gchar *source_id, - GIcon *icon); - -void messaging_menu_app_set_source_count (MessagingMenuApp *app, - const gchar *source_id, - guint count); - -void messaging_menu_app_set_source_time (MessagingMenuApp *app, - const gchar *source_id, - gint64 time); - -void messaging_menu_app_set_source_string (MessagingMenuApp *app, - const gchar *source_id, - const gchar *str); - -void messaging_menu_app_draw_attention (MessagingMenuApp *app, - const gchar *source_id); - -void messaging_menu_app_remove_attention (MessagingMenuApp *app, - const gchar *source_id); - -G_END_DECLS +#include "messaging-menu-app.h" #endif -- cgit v1.2.3