From ff4aefe6c8d9c36881f26c2cf8514c2ce1f3edca Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 12 Aug 2013 21:19:42 +0200 Subject: Add ImMenu A base class for all messaging menus. ImPhoneMenu already subclasses from it, with a desktop version coming up. --- src/Makefile.am | 2 + src/im-menu.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++ src/im-menu.h | 56 +++++++++++++++++++ src/im-phone-menu.c | 38 ++++++++----- src/im-phone-menu.h | 6 +- src/messages-service.c | 45 +++++++-------- 6 files changed, 252 insertions(+), 43 deletions(-) create mode 100644 src/im-menu.c create mode 100644 src/im-menu.h diff --git a/src/Makefile.am b/src/Makefile.am index c011d5d..74a1142 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,6 +14,8 @@ indicator_messages_service_SOURCES = \ gsettingsstrv.h \ gmenuutils.c \ gmenuutils.h \ + im-menu.c \ + im-menu.h \ im-phone-menu.c \ im-phone-menu.h \ im-application-list.c \ diff --git a/src/im-menu.c b/src/im-menu.c new file mode 100644 index 0000000..9f4d3e0 --- /dev/null +++ b/src/im-menu.c @@ -0,0 +1,148 @@ +/* + * Copyright 2013 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 "im-menu.h" + +struct _ImMenuPrivate +{ + GMenu *toplevel_menu; + GMenu *menu; + ImApplicationList *applist; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (ImMenu, im_menu, G_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_APPLICATION_LIST, + NUM_PROPERTIES +}; + +static void +im_menu_finalize (GObject *object) +{ + ImMenuPrivate *priv = im_menu_get_instance_private (IM_MENU (object)); + + g_object_unref (priv->toplevel_menu); + g_object_unref (priv->menu); + g_object_unref (priv->applist); + + G_OBJECT_CLASS (im_menu_parent_class)->finalize (object); +} + +static void +im_menu_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + ImMenuPrivate *priv = im_menu_get_instance_private (IM_MENU (object)); + + switch (property_id) + { + case PROP_APPLICATION_LIST: + g_value_set_object (value, priv->applist); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +im_menu_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ImMenuPrivate *priv = im_menu_get_instance_private (IM_MENU (object)); + + switch (property_id) + { + case PROP_APPLICATION_LIST: /* construct only */ + priv->applist = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +im_menu_class_init (ImMenuClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = im_menu_finalize; + object_class->get_property = im_menu_get_property; + object_class->set_property = im_menu_set_property; + + g_object_class_install_property (object_class, PROP_APPLICATION_LIST, + g_param_spec_object ("application-list", "", "", + IM_TYPE_APPLICATION_LIST, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} + +static void +im_menu_init (ImMenu *menu) +{ + ImMenuPrivate *priv = im_menu_get_instance_private (menu); + GMenuItem *root; + + priv->toplevel_menu = g_menu_new (); + priv->menu = g_menu_new (); + + root = g_menu_item_new (NULL, "indicator.messages"); + g_menu_item_set_attribute (root, "x-canonical-type", "s", "com.canonical.indicator.root"); + g_menu_item_set_submenu (root, G_MENU_MODEL (priv->menu)); + g_menu_append_item (priv->toplevel_menu, root); + + g_object_unref (root); +} + +ImApplicationList * +im_menu_get_application_list (ImMenu *menu) +{ + ImMenuPrivate *priv; + + g_return_val_if_fail (IM_IS_MENU (menu), FALSE); + + priv = im_menu_get_instance_private (menu); + return priv->applist; +} + +gboolean +im_menu_export (ImMenu *menu, + GDBusConnection *connection, + const gchar *object_path, + GError **error) +{ + ImMenuPrivate *priv; + + g_return_val_if_fail (IM_IS_MENU (menu), FALSE); + + priv = im_menu_get_instance_private (menu); + return g_dbus_connection_export_menu_model (connection, + object_path, + G_MENU_MODEL (priv->toplevel_menu), + error) > 0; +} diff --git a/src/im-menu.h b/src/im-menu.h new file mode 100644 index 0000000..7276020 --- /dev/null +++ b/src/im-menu.h @@ -0,0 +1,56 @@ +/* + * Copyright 2013 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 __IM_MENU_H__ +#define __IM_MENU_H__ + +#include +#include "im-application-list.h" + +#define IM_TYPE_MENU (im_menu_get_type ()) +#define IM_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_MENU, ImMenu)) +#define IM_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_TYPE_MENU, ImMenuClass)) +#define IM_IS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_TYPE_MENU)) +#define IM_IS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_TYPE_MENU)) +#define IM_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_TYPE_MENU, ImMenuClass)) + +typedef struct _ImMenuClass ImMenuClass; +typedef struct _ImMenu ImMenu; +typedef struct _ImMenuPrivate ImMenuPrivate; + +struct _ImMenuClass +{ + GObjectClass parent_class; +}; + +struct _ImMenu +{ + GObject parent_instance; +}; + +GType im_menu_get_type (void) G_GNUC_CONST; + +ImApplicationList * im_menu_get_application_list (ImMenu *menu); + +gboolean im_menu_export (ImMenu *menu, + GDBusConnection *connection, + const gchar *object_path, + GError **error); + +#endif diff --git a/src/im-phone-menu.c b/src/im-phone-menu.c index 907749f..b24e235 100644 --- a/src/im-phone-menu.c +++ b/src/im-phone-menu.c @@ -21,19 +21,18 @@ #include -typedef GObjectClass ImPhoneMenuClass; +typedef ImMenuClass ImPhoneMenuClass; struct _ImPhoneMenu { - GObject parent; + ImMenu parent; GMenu *toplevel_menu; GMenu *message_section; GMenu *source_section; - }; -G_DEFINE_TYPE (ImPhoneMenu, im_phone_menu, G_TYPE_OBJECT); +G_DEFINE_TYPE (ImPhoneMenu, im_phone_menu, IM_TYPE_MENU); typedef void (*ImMenuForeachFunc) (GMenuModel *menu, gint pos); @@ -86,6 +85,22 @@ im_phone_menu_update_toplevel (ImPhoneMenu *menu) } } +static void +im_phone_menu_constructed (GObject *object) +{ + ImPhoneMenu *menu = IM_PHONE_MENU (object); + ImApplicationList *applist; + + applist = im_menu_get_application_list (IM_MENU (menu)); + + g_signal_connect_swapped (applist, "message-added", G_CALLBACK (im_phone_menu_add_message), menu); + g_signal_connect_swapped (applist, "message-removed", G_CALLBACK (im_phone_menu_remove_message), menu); + g_signal_connect_swapped (applist, "app-stopped", G_CALLBACK (im_phone_menu_remove_application), menu); + g_signal_connect_swapped (applist, "remove-all", G_CALLBACK (im_phone_menu_remove_all), menu); + + G_OBJECT_CLASS (im_phone_menu_parent_class)->constructed (object); +} + static void im_phone_menu_dispose (GObject *object) { @@ -109,6 +124,7 @@ im_phone_menu_class_init (ImPhoneMenuClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->constructed = im_phone_menu_constructed; object_class->dispose = im_phone_menu_dispose; object_class->finalize = im_phone_menu_finalize; } @@ -129,17 +145,13 @@ im_phone_menu_init (ImPhoneMenu *menu) } ImPhoneMenu * -im_phone_menu_new (void) -{ - return g_object_new (IM_TYPE_PHONE_MENU, NULL); -} - -GMenuModel * -im_phone_menu_get_model (ImPhoneMenu *menu) +im_phone_menu_new (ImApplicationList *applist) { - g_return_val_if_fail (IM_IS_PHONE_MENU (menu), NULL); + g_return_val_if_fail (IM_IS_APPLICATION_LIST (applist), NULL); - return G_MENU_MODEL (menu->toplevel_menu); + return g_object_new (IM_TYPE_PHONE_MENU, + "application-list", applist, + NULL); } static gint64 diff --git a/src/im-phone-menu.h b/src/im-phone-menu.h index 258ce73..9742f61 100644 --- a/src/im-phone-menu.h +++ b/src/im-phone-menu.h @@ -20,7 +20,7 @@ #ifndef __IM_PHONE_MENU_H__ #define __IM_PHONE_MENU_H__ -#include +#include "im-menu.h" #define IM_TYPE_PHONE_MENU (im_phone_menu_get_type ()) #define IM_PHONE_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_PHONE_MENU, ImPhoneMenu)) @@ -33,9 +33,7 @@ typedef struct _ImPhoneMenu ImPhoneMenu; GType im_phone_menu_get_type (void); -ImPhoneMenu * im_phone_menu_new (void); - -GMenuModel * im_phone_menu_get_model (ImPhoneMenu *menu); +ImPhoneMenu * im_phone_menu_new (ImApplicationList *applist); void im_phone_menu_add_message (ImPhoneMenu *menu, const gchar *app_id, diff --git a/src/messages-service.c b/src/messages-service.c index 94d6d29..781e261 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -39,8 +39,7 @@ with this program. If not, see . static ImApplicationList *applications; static IndicatorMessagesService *messages_service; -static GMenu *toplevel_menu; -static ImPhoneMenu *menu; +static GHashTable *menus; static GSettings *settings; static void @@ -82,6 +81,9 @@ on_bus_acquired (GDBusConnection *bus, gpointer user_data) { GError *error = NULL; + GHashTableIter it; + const gchar *profile; + ImMenu *menu; g_dbus_connection_export_action_group (bus, INDICATOR_MESSAGES_DBUS_OBJECT, im_application_list_get_action_group (applications), @@ -92,12 +94,17 @@ on_bus_acquired (GDBusConnection *bus, return; } - g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT "/phone", - G_MENU_MODEL (toplevel_menu), &error); - if (error) { - g_warning ("unable to export menu on dbus: %s", error->message); - g_error_free (error); - return; + g_hash_table_iter_init (&it, menus); + while (g_hash_table_iter_next (&it, (gpointer *) &profile, (gpointer *) &menu)) { + gchar *object_path; + + object_path = g_strconcat (INDICATOR_MESSAGES_DBUS_OBJECT, "/", profile, NULL); + if (!im_menu_export (menu, bus, object_path, &error)) { + g_warning ("unable to export menu for profile '%s': %s", profile, error->message); + g_clear_error (&error); + } + + g_free (object_path); } g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (messages_service), @@ -126,7 +133,6 @@ int main (int argc, char ** argv) { GMainLoop * mainloop = NULL; - GMenuItem *root; GBusNameOwnerFlags flags; /* Glib init */ @@ -157,30 +163,17 @@ main (int argc, char ** argv) g_signal_connect (messages_service, "handle-unregister-application", G_CALLBACK (unregister_application), NULL); - menu = im_phone_menu_new (); - - toplevel_menu = g_menu_new (); - root = g_menu_item_new (NULL, "indicator.messages"); - g_menu_item_set_attribute (root, "x-canonical-type", "s", "com.canonical.indicator.root"); - g_menu_item_set_submenu (root, im_phone_menu_get_model (menu)); - g_menu_append_item (toplevel_menu, root); - settings = g_settings_new ("com.canonical.indicator.messages"); applications = im_application_list_new (); - g_signal_connect_swapped (applications, "message-added", - G_CALLBACK (im_phone_menu_add_message), menu); - g_signal_connect_swapped (applications, "message-removed", - G_CALLBACK (im_phone_menu_remove_message), menu); - g_signal_connect_swapped (applications, "app-stopped", - G_CALLBACK (im_phone_menu_remove_application), menu); - g_signal_connect_swapped (applications, "remove-all", - G_CALLBACK (im_phone_menu_remove_all), menu); + + menus = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + g_hash_table_insert (menus, "phone", im_phone_menu_new (applications)); g_main_loop_run(mainloop); /* Clean up */ - g_object_unref (root); + g_hash_table_unref (menus); g_object_unref (messages_service); g_object_unref (settings); g_object_unref (applications); -- cgit v1.2.3