aboutsummaryrefslogtreecommitdiff
path: root/libmessaging-menu/messaging-menu.c
diff options
context:
space:
mode:
authorLars Uebernickel <lars.uebernickel@canonical.com>2013-08-19 16:51:38 +0000
committerTarmac <Unknown>2013-08-19 16:51:38 +0000
commit8adc1d9acb001ea99937d2b8cbccb2fc4adf1ed2 (patch)
tree2d325350e2a5510a9075d207d69dc8b2f25c43d9 /libmessaging-menu/messaging-menu.c
parent97d88bc9bc34f0bf654281d32c3e0aab85fa0f4d (diff)
parent41bd58d41cd15a8ca8e4499b2abe945a4fe1667d (diff)
downloadayatana-indicator-messages-8adc1d9acb001ea99937d2b8cbccb2fc4adf1ed2.tar.gz
ayatana-indicator-messages-8adc1d9acb001ea99937d2b8cbccb2fc4adf1ed2.tar.bz2
ayatana-indicator-messages-8adc1d9acb001ea99937d2b8cbccb2fc4adf1ed2.zip
Merge in phablet branch.
Approved by PS Jenkins bot, Pete Woods.
Diffstat (limited to 'libmessaging-menu/messaging-menu.c')
-rw-r--r--libmessaging-menu/messaging-menu.c1200
1 files changed, 0 insertions, 1200 deletions
diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c
deleted file mode 100644
index 467a67a..0000000
--- a/libmessaging-menu/messaging-menu.c
+++ /dev/null
@@ -1,1200 +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 <http://www.gnu.org/licenses/>.
- *
- * Authors:
- * Lars Uebernickel <lars.uebernickel@canonical.com>
- */
-
-#include "messaging-menu.h"
-#include "indicator-messages-service.h"
-
-#include <gio/gdesktopappinfo.h>
-
-/**
- * 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
- * <code>NotShowIn</code> keyword contains "Messaging Menu" or whose
- * <code>OnlyShowIn</code> keyword does not contain "Messaging Menu"
- * will not appear (the <ulink
- * url="http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#extra-actions">
- * desktop file specification</ulink> 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 <ulink
- * url="https://wiki.ubuntu.com/MessagingMenu">https://wiki.ubuntu.com/MessagingMenu</ulink>.
- */
-
-/**
- * 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;
- GDBusConnection *bus;
-
- IndicatorMessagesService *messages_service;
- guint watch_id;
- guint action_export_id;
- guint menu_export_id;
-
- GCancellable *cancellable;
-};
-
-G_DEFINE_TYPE (MessagingMenuApp, messaging_menu_app, G_TYPE_OBJECT);
-
-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;
- GError *error = NULL;
- gchar *object_path;
-
- object_path = messaging_menu_app_get_dbus_object_path (app);
- if (!object_path)
- return;
-
- app->bus = g_bus_get_finish (res, &error);
- if (app->bus == NULL)
- {
- g_warning ("unable to connect to session bus: %s", error->message);
- g_error_free (error);
- return;
- }
-
- app->action_export_id = g_dbus_connection_export_action_group (app->bus,
- object_path,
- G_ACTION_GROUP (app->source_actions),
- &error);
- if (!app->action_export_id)
- {
- g_warning ("unable to export action group: %s", error->message);
- g_clear_error (&error);
- }
-
- app->menu_export_id = g_dbus_connection_export_menu_model (app->bus,
- object_path,
- G_MENU_MODEL (app->menu),
- &error);
- if (!app->menu_export_id)
- {
- g_warning ("unable to export menu: %s", error->message);
- g_clear_error (&error);
- }
-
- 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->bus)
- {
- if (app->action_export_id > 0)
- g_dbus_connection_unexport_action_group (app->bus, app->action_export_id);
-
- if (app->menu_export_id > 0)
- g_dbus_connection_unexport_menu_model (app->bus, app->menu_export_id);
-
- app->action_export_id = 0;
- app->menu_export_id = 0;
- g_object_unref (app->bus);
- app->bus = NULL;
- }
-
- 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)
- {
- indicator_messages_service_call_application_stopped_running (app->messages_service,
- g_app_info_get_id (G_APP_INFO (app->appinfo)),
- NULL, NULL, NULL);
-
- 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->bus = NULL;
-
- app->action_export_id = 0;
- app->menu_export_id = 0;
-
- 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 (GSimpleAction *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)
-{
- GSimpleAction *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_simple_action_new_stateful (id, NULL, 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, NULL);
- g_menu_item_set_action_and_target_value (menuitem, id, NULL);
- 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 GSimpleAction *
-messaging_menu_app_get_source_action (MessagingMenuApp *app,
- const gchar *source_id)
-
-{
- GAction *action;
-
- g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), NULL);
- g_return_val_if_fail (source_id != NULL, 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_SIMPLE_ACTION (action);
-}
-
-static void
-messaging_menu_app_set_source_action (MessagingMenuApp *app,
- const gchar *source_id,
- guint count,
- gint64 time,
- const gchar *string)
-{
- GSimpleAction *action;
- GVariant *state;
- gboolean draws_attention;
- GVariant *new_state;
-
- action = messaging_menu_app_get_source_action (app, source_id);
- if (!action)
- return;
-
- state = g_action_get_state (G_ACTION (action));
- g_variant_get_child (state, 3, "b", &draws_attention);
-
- new_state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
- g_simple_action_set_state (action, new_state);
-
- g_variant_unref (state);
-}
-
-static void
-messaging_menu_app_set_draws_attention (MessagingMenuApp *app,
- const gchar *source_id,
- gboolean draws_attention)
-{
- GSimpleAction *action;
- GVariant *state;
- guint count;
- gint64 time;
- const gchar *string;
- GVariant *new_state;
-
- action = messaging_menu_app_get_source_action (app, source_id);
- if (!action)
- return;
-
- state = g_action_get_state (G_ACTION (action));
- g_variant_get (state, "(ux&sb)", &count, &time, &string, NULL);
-
- new_state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
- g_simple_action_set_state (action, new_state);
-
- g_variant_unref (state);
-}
-
-/**
- * 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: (allow-none): 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;
-
- 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;
-
- if (icon)
- {
- gchar *iconstr;
-
- iconstr = g_icon_to_string (icon);
- g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
-
- g_free (iconstr);
- }
- else
- {
- g_menu_item_set_attribute_value (item, "x-canonical-icon", NULL);
- }
-
- g_menu_replace_item (app->menu, pos, item);
-
- 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, count, 0, "");
-}
-
-/**
- * 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.
- */
-void
-messaging_menu_app_set_source_time (MessagingMenuApp *app,
- const gchar *source_id,
- gint64 time)
-{
- messaging_menu_app_set_source_action (app, source_id, 0, 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.
- */
-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, 0, 0, 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_draws_attention (app, source_id, 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_draws_attention (app, source_id, FALSE);
-}