diff options
-rw-r--r-- | ChangeLog | 84 | ||||
-rw-r--r-- | NEWS | 13 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/Makefile.in | 22 | ||||
-rw-r--r-- | src/dialog.c | 6 | ||||
-rw-r--r-- | src/indicator-session.c | 174 | ||||
-rw-r--r-- | src/online-accounts-mgr.c | 166 | ||||
-rw-r--r-- | src/online-accounts-mgr.h | 50 | ||||
-rw-r--r-- | src/session-menu-mgr.c | 38 | ||||
-rw-r--r-- | src/shared-names.h | 4 | ||||
-rw-r--r-- | tests/Makefile.am | 4 | ||||
-rw-r--r-- | tests/Makefile.in | 21 | ||||
-rw-r--r-- | tests/gtest-dbus-helper.h | 418 | ||||
-rw-r--r-- | tests/test-service.cc | 3 |
17 files changed, 980 insertions, 32 deletions
@@ -1,5 +1,89 @@ # Generated by Makefile. Do not edit. +2012-08-31 Charles Kerr <charles.kerr@canonical.com> + + add gtest-dbus-helper.h to test_service_SOURCES s.t. it gets bundled in the tarball + +2012-08-31 Charles Kerr <charles.kerr@canonical.com> + + 12.10.2 + +2012-08-31 Charles Kerr <charles.kerr@canonical.com> + + merge lp:~charlesk/indicator-session/lp-1044015 to add disposition highlighting to the session indicator's icon + +2012-08-31 Charles Kerr <charles.kerr@canonical.com> + + add a11y case for attention needed, but username display disabled + +2012-08-31 Charles Kerr <charles.kerr@canonical.com> + + revise indicator_session_update_a11y_from_disposition() to be easier to internationalize + +2012-08-31 Charles Kerr <charles.kerr@canonical.com> + + have the a11y text follow the SystemMenu spec + +2012-08-30 Charles Kerr <charles.kerr@canonical.com> + + add a disposition handler to indicator-session + +2012-08-30 Alberto Mardegan <alberto.mardegan@canonical.com> + + Add the "Online Accounts" item to the session menu. + + This item, beside opening the Online Accounts applet of the GNOME Control Center, also acts as an indicator, by turning red when some accounts need to be re-authenticated.. Approved by Charles Kerr, Matthew Paul Thomas, jenkins. + +2012-08-23 Alberto Mardegan <alberto.mardegan@canonical.com> + + Show Online Accounts only when needed + +2012-08-21 Alberto Mardegan <alberto.mardegan@canonical.com> + + Fix build + +2012-08-21 Alberto Mardegan <alberto.mardegan@canonical.com> + + Class rename + + Rename the class from Webcredentials to OnlineAccounts, for improved + consistency. + +2012-08-21 Alberto Mardegan <alberto.mardegan@canonical.com> + + Add Online Accounts item to session menu. + +2012-08-21 Alberto Mardegan <alberto.mardegan@canonical.com> + + Apply old webcredentials patch to trunk + +2012-03-07 Alberto Mardegan <alberto.mardegan@canonical.com> + + Add Web Accounts menu item + + Also, listen for the webcredentials service signals, to know when to set the + alert disposition on the menu item. + +2012-03-07 Alberto Mardegan <alberto.mardegan@canonical.com> + + Fix a build error: include locale.h + +2012-08-23 Charles Kerr <charles.kerr@canonical.com> + + merge lp:~charlesk/indicator-session/add-dbus-test-harness to get the unit tests building correctly. + +2012-08-23 Charles Kerr <charles.kerr@canonical.com> + + add a local implementation of indicator-service-test.h + +2012-08-23 Charles Kerr <charles.kerr@canonical.com> + + merge lp:~charlesk/indicator-session/lp-1027952 to remove the Restart button from the shutdown dialog + +2012-08-22 Charles Kerr <charles.kerr@canonical.com> + + in gtk-logout-helper's 'switch off' dialog, don't show a 'restart' button anymore + 2012-08-22 Charles Kerr <charles.kerr@canonical.com> 12.10.1 @@ -0,0 +1,13 @@ +12.10.2 + - Add an 'Online Accounts' menuitem (lp: #1044464) + - Add disposition highlighting to the indicator icon (lp: #1044015) + - Fix build issue in the unit tests directory (lp: #1040678) + - Remove the Restart button from the shutdown dialog (lp: #1027952) + +12.10.1 + - Fix user menuitems' icon sizes (lp: #1024395) + - Make explicit in configure.ac that we need a newer glib (lp: #1023533) + - Separate testing-strings into a separate Makefile.am for reuse + +12.10.0 + - First version of the 12.10 System Menu redesign @@ -3109,7 +3109,7 @@ fi # Define the identity of the package. PACKAGE=indicator-session - VERSION=12.10.1 + VERSION=12.10.2 cat >>confdefs.h <<_ACEOF diff --git a/configure.ac b/configure.ac index 60722f9..6e647ca 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ AC_INIT(src/indicator-session.c) AC_PREREQ(2.53) AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(indicator-session, 12.10.1) +AM_INIT_AUTOMAKE(indicator-session, 12.10.2) AM_MAINTAINER_MODE diff --git a/po/POTFILES.in b/po/POTFILES.in index 6392590..f2cafb0 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -5,6 +5,7 @@ src/dialog.c src/gen-session-dbus.xml.c src/gtk-logout-helper.c src/indicator-session.c +src/online-accounts-mgr.c src/session-dbus.c src/session-menu-mgr.c src/session-service.c diff --git a/src/Makefile.am b/src/Makefile.am index 7bc6306..cd82812 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -133,7 +133,9 @@ indicator_session_service_SOURCES = \ users-service-dbus.h \ users-service-dbus.c \ session-menu-mgr.h \ - session-menu-mgr.c + session-menu-mgr.c \ + online-accounts-mgr.c \ + online-accounts-mgr.h indicator_session_service_CFLAGS = \ $(SESSIONSERVICE_CFLAGS) \ diff --git a/src/Makefile.in b/src/Makefile.in index 73b2cdb..6993860 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -147,7 +147,8 @@ am_indicator_session_service_OBJECTS = $(am__objects_2) \ indicator_session_service-session-dbus.$(OBJEXT) \ indicator_session_service-gen-session-dbus.xml.$(OBJEXT) \ indicator_session_service-users-service-dbus.$(OBJEXT) \ - indicator_session_service-session-menu-mgr.$(OBJEXT) + indicator_session_service-session-menu-mgr.$(OBJEXT) \ + indicator_session_service-online-accounts-mgr.$(OBJEXT) indicator_session_service_OBJECTS = \ $(am_indicator_session_service_OBJECTS) indicator_session_service_DEPENDENCIES = $(am__DEPENDENCIES_1) @@ -461,7 +462,9 @@ indicator_session_service_SOURCES = \ users-service-dbus.h \ users-service-dbus.c \ session-menu-mgr.h \ - session-menu-mgr.c + session-menu-mgr.c \ + online-accounts-mgr.c \ + online-accounts-mgr.h indicator_session_service_CFLAGS = \ $(SESSIONSERVICE_CFLAGS) \ @@ -658,6 +661,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_session_service-dbus-upower.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_session_service-dbus-user.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_session_service-gen-session-dbus.xml.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_session_service-online-accounts-mgr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_session_service-session-dbus.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_session_service-session-menu-mgr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_session_service-session-service.Po@am__quote@ @@ -910,6 +914,20 @@ indicator_session_service-session-menu-mgr.obj: session-menu-mgr.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_session_service_CFLAGS) $(CFLAGS) -c -o indicator_session_service-session-menu-mgr.obj `if test -f 'session-menu-mgr.c'; then $(CYGPATH_W) 'session-menu-mgr.c'; else $(CYGPATH_W) '$(srcdir)/session-menu-mgr.c'; fi` +indicator_session_service-online-accounts-mgr.o: online-accounts-mgr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_session_service_CFLAGS) $(CFLAGS) -MT indicator_session_service-online-accounts-mgr.o -MD -MP -MF $(DEPDIR)/indicator_session_service-online-accounts-mgr.Tpo -c -o indicator_session_service-online-accounts-mgr.o `test -f 'online-accounts-mgr.c' || echo '$(srcdir)/'`online-accounts-mgr.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/indicator_session_service-online-accounts-mgr.Tpo $(DEPDIR)/indicator_session_service-online-accounts-mgr.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='online-accounts-mgr.c' object='indicator_session_service-online-accounts-mgr.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_session_service_CFLAGS) $(CFLAGS) -c -o indicator_session_service-online-accounts-mgr.o `test -f 'online-accounts-mgr.c' || echo '$(srcdir)/'`online-accounts-mgr.c + +indicator_session_service-online-accounts-mgr.obj: online-accounts-mgr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_session_service_CFLAGS) $(CFLAGS) -MT indicator_session_service-online-accounts-mgr.obj -MD -MP -MF $(DEPDIR)/indicator_session_service-online-accounts-mgr.Tpo -c -o indicator_session_service-online-accounts-mgr.obj `if test -f 'online-accounts-mgr.c'; then $(CYGPATH_W) 'online-accounts-mgr.c'; else $(CYGPATH_W) '$(srcdir)/online-accounts-mgr.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/indicator_session_service-online-accounts-mgr.Tpo $(DEPDIR)/indicator_session_service-online-accounts-mgr.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='online-accounts-mgr.c' object='indicator_session_service-online-accounts-mgr.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(indicator_session_service_CFLAGS) $(CFLAGS) -c -o indicator_session_service-online-accounts-mgr.obj `if test -f 'online-accounts-mgr.c'; then $(CYGPATH_W) 'online-accounts-mgr.c'; else $(CYGPATH_W) '$(srcdir)/online-accounts-mgr.c'; fi` + mostlyclean-libtool: -rm -f *.lo diff --git a/src/dialog.c b/src/dialog.c index c46ac80..7c562d5 100644 --- a/src/dialog.c +++ b/src/dialog.c @@ -227,12 +227,6 @@ logout_dialog_new (LogoutDialogType type) NULL); } - if (type == LOGOUT_DIALOG_TYPE_SHUTDOWN) { - const gchar * restart_text; - restart_text = g_dpgettext2 (NULL, "button", button_strings[LOGOUT_DIALOG_TYPE_RESTART]); - gtk_dialog_add_button (GTK_DIALOG(dialog), restart_text, GTK_RESPONSE_HELP); - } - gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); /* The following is a workaround to fix an issue in GtkMessageDialog diff --git a/src/indicator-session.c b/src/indicator-session.c index 3038948..aa328dd 100644 --- a/src/indicator-session.c +++ b/src/indicator-session.c @@ -63,6 +63,7 @@ struct _IndicatorSession GCancellable * service_proxy_cancel; GDBusProxy * service_proxy; GSettings * settings; + DbusmenuClient * menu_client; }; static gboolean greeter_mode; @@ -82,6 +83,8 @@ static gboolean build_restart_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data); +static void on_menu_layout_updated (DbusmenuClient * client, IndicatorSession * session); +static void indicator_session_update_icon_and_a11y (IndicatorSession * self); static void indicator_session_update_users_label (IndicatorSession* self, const gchar* name); static void service_connection_cb (IndicatorServiceManager * sm, gboolean connected, gpointer user_data); @@ -116,8 +119,6 @@ indicator_session_class_init (IndicatorSessionClass *klass) static void indicator_session_init (IndicatorSession *self) { - const gchar * icon_name; - self->settings = g_settings_new ("com.canonical.indicator.session"); /* Now let's fire these guys up. */ @@ -130,30 +131,38 @@ indicator_session_init (IndicatorSession *self) greeter_mode = !g_strcmp0(g_getenv("INDICATOR_GREETER_MODE"), "1"); self->entry.name_hint = PACKAGE; - self->entry.accessible_desc = _("Session Menu"); self->entry.label = GTK_LABEL (gtk_label_new ("User Name")); - icon_name = greeter_mode ? GREETER_ICON_DEFAULT : ICON_DEFAULT; - self->entry.image = GTK_IMAGE (gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON)); + self->entry.image = GTK_IMAGE (gtk_image_new()); self->entry.menu = GTK_MENU (dbusmenu_gtkmenu_new(INDICATOR_SESSION_DBUS_NAME, INDICATOR_SESSION_DBUS_OBJECT)); + indicator_session_update_icon_and_a11y (self); g_settings_bind (self->settings, "show-real-name-on-panel", self->entry.label, "visible", G_SETTINGS_BIND_GET); + /* show-real-name-on-panel affects the a11y string */ + g_signal_connect_swapped (self->settings, + "notify::show-real-name-on-panel", + G_CALLBACK(indicator_session_update_icon_and_a11y), + self); + gtk_widget_show (GTK_WIDGET(self->entry.menu)); gtk_widget_show (GTK_WIDGET(self->entry.image)); g_object_ref_sink (self->entry.menu); g_object_ref_sink (self->entry.image); // set up the handlers - DbusmenuClient * menu_client = DBUSMENU_CLIENT(dbusmenu_gtkmenu_get_client(DBUSMENU_GTKMENU(self->entry.menu))); - dbusmenu_client_add_type_handler (menu_client, + self->menu_client = DBUSMENU_CLIENT(dbusmenu_gtkmenu_get_client(DBUSMENU_GTKMENU(self->entry.menu))); + g_signal_connect (self->menu_client, "layout-updated", + G_CALLBACK(on_menu_layout_updated), self); + + dbusmenu_client_add_type_handler (self->menu_client, USER_ITEM_TYPE, new_user_item); - dbusmenu_client_add_type_handler (menu_client, + dbusmenu_client_add_type_handler (self->menu_client, RESTART_ITEM_TYPE, build_restart_item); - dbusmenu_gtkclient_set_accel_group (DBUSMENU_GTKCLIENT(menu_client), + dbusmenu_gtkclient_set_accel_group (DBUSMENU_GTKCLIENT(self->menu_client), gtk_accel_group_new()); } @@ -339,13 +348,6 @@ receive_signal (GDBusProxy * proxy, g_variant_get (parameters, "(&s)", &username); indicator_session_update_users_label (self, username); } - else if (!g_strcmp0(signal_name, "RestartRequired")) - { - const gchar * icon_name = greeter_mode ? GREETER_ICON_RESTART : ICON_RESTART; - gtk_image_set_from_icon_name (GTK_IMAGE(self->entry.image), icon_name, GTK_ICON_SIZE_MENU); - self->entry.accessible_desc = _("Device Menu (reboot required)"); - g_signal_emit (G_OBJECT(self), INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE_ID, 0, &self->entry); - } } @@ -412,3 +414,143 @@ indicator_session_update_users_label (IndicatorSession * self, { gtk_label_set_text (self->entry.label, name ? name : ""); } + +/*** +**** Disposition +***/ + +enum +{ + DISPOSITION_NORMAL, + DISPOSITION_INFO, + DISPOSITION_WARNING, + DISPOSITION_ALERT +}; + +static void +indicator_session_update_a11y_from_disposition (IndicatorSession * indicator, + int disposition) +{ + gchar * a11y; + const gchar * username = gtk_label_get_text (indicator->entry.label); + const gboolean need_attn = disposition != DISPOSITION_NORMAL; + const gboolean show_name = g_settings_get_boolean (indicator->settings, + "show-real-name-on-panel"); + + if (show_name && need_attn) + a11y = g_strdup_printf (_("System %s (Attention Required)"), username); + else if (show_name) + a11y = g_strdup_printf (_("System %s"), username); + else if (need_attn) + a11y = g_strdup (_("System (Attention Required)")); + else + a11y = g_strdup (_("System")); + + g_debug (G_STRLOC" setting a11y to \"%s\"", a11y); + g_clear_pointer (&indicator->entry.accessible_desc, g_free); + indicator->entry.accessible_desc = a11y; + g_signal_emit (indicator, + INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE_ID, + 0, + &indicator->entry); +} + +static void +indicator_session_update_icon_from_disposition (IndicatorSession * indicator, + int disposition) +{ + const gchar * icon; + + if (greeter_mode) + { + if (disposition == DISPOSITION_NORMAL) + icon = GREETER_ICON_DEFAULT; + else + icon = GREETER_ICON_RESTART; + } + else + { + if (disposition == DISPOSITION_NORMAL) + icon = ICON_DEFAULT; + else if (disposition == DISPOSITION_INFO) + icon = ICON_INFO; + else + icon = ICON_ALERT; + } + + g_debug (G_STRLOC" setting icon to \"%s\"", icon); + gtk_image_set_from_icon_name (GTK_IMAGE(indicator->entry.image), + icon, + GTK_ICON_SIZE_BUTTON); +} + +static int +calculate_disposition (IndicatorSession * indicator) +{ + GList * l; + DbusmenuMenuitem * root = dbusmenu_client_get_root (indicator->menu_client); + GList * children = dbusmenu_menuitem_get_children (root); + int ret = DISPOSITION_NORMAL; + + for (l=children; l!=NULL; l=l->next) + { + int val; + const gchar * key = DBUSMENU_MENUITEM_PROP_DISPOSITION; + const gchar * val_str = dbusmenu_menuitem_property_get (l->data, key); + + if (!g_strcmp0 (val_str, DBUSMENU_MENUITEM_DISPOSITION_ALERT)) + val = DISPOSITION_ALERT; + else if (!g_strcmp0 (val_str, DBUSMENU_MENUITEM_DISPOSITION_WARNING)) + val = DISPOSITION_WARNING; + else if (!g_strcmp0 (val_str, DBUSMENU_MENUITEM_DISPOSITION_INFORMATIVE)) + val = DISPOSITION_INFO; + else + val = DISPOSITION_NORMAL; + + if (ret < val) + ret = val; + } + + return ret; +} + +static void +indicator_session_update_icon_and_a11y (IndicatorSession * indicator) +{ + const int disposition = calculate_disposition (indicator); + indicator_session_update_a11y_from_disposition (indicator, disposition); + indicator_session_update_icon_from_disposition (indicator, disposition); +} + +static void +on_menuitem_property_changed (DbusmenuMenuitem * mi, + gchar * property, + GValue * value, + gpointer indicator) +{ + if (!g_strcmp0 (property, DBUSMENU_MENUITEM_PROP_DISPOSITION)) + indicator_session_update_icon_and_a11y (indicator); +} + +static void +on_menu_layout_updated (DbusmenuClient * client, IndicatorSession * session) +{ + GList * l; + DbusmenuMenuitem * root = dbusmenu_client_get_root (client); + GList * children = dbusmenu_menuitem_get_children (root); + static GQuark tag = 0; + + if (G_UNLIKELY (tag == 0)) + { + tag = g_quark_from_static_string ("x-tagged-by-indicator-session"); + } + + for (l=children; l!=NULL; l=l->next) + { + if (g_object_get_qdata (l->data, tag) == NULL) + { + g_object_set_qdata (l->data, tag, GINT_TO_POINTER(1)); + g_signal_connect (l->data, "property-changed", G_CALLBACK(on_menuitem_property_changed), session); + } + } +} diff --git a/src/online-accounts-mgr.c b/src/online-accounts-mgr.c new file mode 100644 index 0000000..4abba00 --- /dev/null +++ b/src/online-accounts-mgr.c @@ -0,0 +1,166 @@ +/* +Copyright 2012 Canonical Ltd. + +Authors: + Alberto Mardegan <alberto.mardegan@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <gio/gio.h> +#include <glib/gi18n.h> + +#include "online-accounts-mgr.h" + +#include <libdbusmenu-glib/client.h> + +struct _OnlineAccountsMgr +{ + GObject parent_instance; + GDBusProxy *proxy; + DbusmenuMenuitem *menu_item; +}; + +#define ONLINE_ACCOUNTS_OBJECT_PATH "/com/canonical/indicators/webcredentials" +#define ONLINE_ACCOUNTS_BUS_NAME "com.canonical.indicators.webcredentials" +#define ONLINE_ACCOUNTS_INTERFACE ONLINE_ACCOUNTS_BUS_NAME + +G_DEFINE_TYPE (OnlineAccountsMgr, online_accounts_mgr, G_TYPE_OBJECT); + +static void +update_disposition (OnlineAccountsMgr *self, GVariant *error_status_prop) +{ + gboolean error_status; + + error_status = g_variant_get_boolean (error_status_prop); + dbusmenu_menuitem_property_set (self->menu_item, + DBUSMENU_MENUITEM_PROP_DISPOSITION, + error_status ? + DBUSMENU_MENUITEM_DISPOSITION_ALERT : + DBUSMENU_MENUITEM_DISPOSITION_NORMAL); +} + +static void +on_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + GStrv invalidated_properties, + OnlineAccountsMgr *self) +{ + if (g_variant_n_children (changed_properties) > 0) { + GVariantIter *iter; + const gchar *key; + GVariant *value; + + g_variant_get (changed_properties, "a{sv}", &iter); + while (g_variant_iter_loop (iter, "{&sv}", &key, &value)) { + if (g_strcmp0 (key, "ErrorStatus") == 0) { + update_disposition (self, value); + } + } + g_variant_iter_free (iter); + } +} + +static void +on_menu_item_activated (DbusmenuMenuitem *menu_item, + guint timestamp, + OnlineAccountsMgr *self) +{ + GError *error = NULL; + + if (!g_spawn_command_line_async("gnome-control-center credentials", &error)) + { + g_warning("Unable to show control center: %s", error->message); + g_error_free(error); + } +} + +static void +online_accounts_mgr_init (OnlineAccountsMgr *self) +{ + GError *error = NULL; + GVariant *error_status_prop; + + self->menu_item = dbusmenu_menuitem_new (); + dbusmenu_menuitem_property_set (self->menu_item, + DBUSMENU_MENUITEM_PROP_TYPE, + DBUSMENU_CLIENT_TYPES_DEFAULT); + dbusmenu_menuitem_property_set (self->menu_item, + DBUSMENU_MENUITEM_PROP_LABEL, + _("Online Accounts\342\200\246")); + g_signal_connect (self->menu_item, + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK (on_menu_item_activated), + self); + + self->proxy = + g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + ONLINE_ACCOUNTS_BUS_NAME, + ONLINE_ACCOUNTS_OBJECT_PATH, + ONLINE_ACCOUNTS_INTERFACE, + NULL, + &error); + if (G_UNLIKELY (error != NULL)) { + g_warning ("Couldn't create online_accounts proxy: %s", error->message); + g_clear_error (&error); + return; + } + + g_signal_connect (self->proxy, "g-properties-changed", + G_CALLBACK (on_properties_changed), self); + + error_status_prop = + g_dbus_proxy_get_cached_property (self->proxy, "ErrorStatus"); + if (error_status_prop != NULL) { + update_disposition (self, error_status_prop); + g_variant_unref (error_status_prop); + } +} + +static void +online_accounts_mgr_dispose (GObject *object) +{ + OnlineAccountsMgr *self = ONLINE_ACCOUNTS_MGR (object); + + if (self->proxy != NULL) { + g_object_unref (self->proxy); + self->proxy = NULL; + } + + if (self->menu_item != NULL) { + g_object_unref (self->menu_item); + self->menu_item = NULL; + } + + G_OBJECT_CLASS (online_accounts_mgr_parent_class)->dispose (object); +} + +static void +online_accounts_mgr_class_init (OnlineAccountsMgrClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->dispose = online_accounts_mgr_dispose; +} + +OnlineAccountsMgr *online_accounts_mgr_new () +{ + return g_object_new (ONLINE_ACCOUNTS_TYPE_MGR, NULL); +} + +DbusmenuMenuitem *online_accounts_mgr_get_menu_item (OnlineAccountsMgr *self) +{ + g_return_val_if_fail (ONLINE_ACCOUNTS_IS_MGR (self), NULL); + return self->menu_item; +} diff --git a/src/online-accounts-mgr.h b/src/online-accounts-mgr.h new file mode 100644 index 0000000..16c0461 --- /dev/null +++ b/src/online-accounts-mgr.h @@ -0,0 +1,50 @@ +/* +Copyright 2012 Canonical Ltd. + +Authors: + Alberto Mardegan <alberto.mardegan@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _ONLINE_ACCOUNTS_MGR_H_ +#define _ONLINE_ACCOUNTS_MGR_H_ + +#include <glib-object.h> +#include <libdbusmenu-glib/menuitem.h> + +G_BEGIN_DECLS + +#define ONLINE_ACCOUNTS_TYPE_MGR (online_accounts_mgr_get_type ()) +#define ONLINE_ACCOUNTS_MGR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ONLINE_ACCOUNTS_TYPE_MGR, OnlineAccountsMgr)) +#define ONLINE_ACCOUNTS_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ONLINE_ACCOUNTS_TYPE_MGR, OnlineAccountsMgrClass)) +#define ONLINE_ACCOUNTS_IS_MGR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ONLINE_ACCOUNTS_TYPE_MGR)) +#define ONLINE_ACCOUNTS_IS_MGR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ONLINE_ACCOUNTS_TYPE_MGR)) +#define ONLINE_ACCOUNTS_MGR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ONLINE_ACCOUNTS_TYPE_MGR, OnlineAccountsMgrClass)) + +typedef struct _OnlineAccountsMgrClass OnlineAccountsMgrClass; +typedef struct _OnlineAccountsMgr OnlineAccountsMgr; + +struct _OnlineAccountsMgrClass +{ + GObjectClass parent_class; +}; + +GType online_accounts_mgr_get_type (void) G_GNUC_CONST; +OnlineAccountsMgr *online_accounts_mgr_new (void); + +DbusmenuMenuitem *online_accounts_mgr_get_menu_item (OnlineAccountsMgr *self); + +G_END_DECLS + +#endif /* _ONLINE_ACCOUNTS_MGR_H_ */ diff --git a/src/session-menu-mgr.c b/src/session-menu-mgr.c index 96fc2a0..643abd1 100644 --- a/src/session-menu-mgr.c +++ b/src/session-menu-mgr.c @@ -33,6 +33,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include "session-menu-mgr.h" #include "shared-names.h" #include "users-service-dbus.h" +#include "online-accounts-mgr.h" #define DEBUG_SHOW_ALL FALSE @@ -88,6 +89,7 @@ struct _SessionMenuMgr DbusmenuMenuitem * lock_mi; DbusmenuMenuitem * lock_switch_mi; DbusmenuMenuitem * guest_mi; + DbusmenuMenuitem * online_accounts_mi; DbusmenuMenuitem * logout_mi; DbusmenuMenuitem * suspend_mi; DbusmenuMenuitem * hibernate_mi; @@ -113,6 +115,7 @@ struct _SessionMenuMgr DBusUPower * upower_proxy; SessionDbus * session_dbus; UsersServiceDbus * users_dbus_facade; + OnlineAccountsMgr * online_accounts_mgr; }; static SwitcherMode get_switcher_mode (SessionMenuMgr *); @@ -192,6 +195,9 @@ session_menu_mgr_init (SessionMenuMgr *mgr) G_CALLBACK(on_guest_logged_in_changed), mgr); init_upower_proxy (mgr); + + /* Online accounts menu item */ + mgr->online_accounts_mgr = online_accounts_mgr_new (); } static void @@ -212,6 +218,7 @@ session_menu_mgr_dispose (GObject *object) g_clear_object (&mgr->users_dbus_facade); g_clear_object (&mgr->top_mi); g_clear_object (&mgr->session_dbus); + g_clear_object (&mgr->online_accounts_mgr); g_slist_free (mgr->user_menuitems); mgr->user_menuitems = NULL; @@ -362,6 +369,29 @@ mi_new (const char * label) return mi; } +static void +check_online_accounts_status (SessionMenuMgr * mgr, DbusmenuMenuitem * mi) +{ + const gchar *disposition; + gboolean on_alert; + + disposition = + dbusmenu_menuitem_property_get (mi, DBUSMENU_MENUITEM_PROP_DISPOSITION); + on_alert = g_strcmp0 (disposition, DBUSMENU_MENUITEM_DISPOSITION_ALERT) == 0; + + mi_set_visible (mi, on_alert); +} + +static void +on_online_accounts_changed (SessionMenuMgr * mgr, const gchar * property, + GVariant *value, DbusmenuMenuitem *mi) +{ + if (g_strcmp0 (property, DBUSMENU_MENUITEM_PROP_DISPOSITION) == 0) + { + check_online_accounts_status(mgr, mi); + } +} + /*** **** Admin Menuitems **** <https://wiki.ubuntu.com/SystemMenu#Admin_items> @@ -396,6 +426,14 @@ build_admin_menuitems (SessionMenuMgr * mgr) G_CALLBACK(action_func_spawn_async), CMD_SYSTEM_SETTINGS); + mi = mgr->online_accounts_mi = + online_accounts_mgr_get_menu_item (mgr->online_accounts_mgr); + dbusmenu_menuitem_child_append (mgr->top_mi, mi); + g_signal_connect_swapped (mi, DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, + G_CALLBACK(on_online_accounts_changed), + mgr); + check_online_accounts_status (mgr, mi); + mi = mi_new_separator (); dbusmenu_menuitem_child_append (mgr->top_mi, mi); } diff --git a/src/shared-names.h b/src/shared-names.h index dcda182..e82aef8 100644 --- a/src/shared-names.h +++ b/src/shared-names.h @@ -41,7 +41,9 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #define RESTART_ITEM_ICON "restart-icon" #define ICON_DEFAULT "system-devices-panel" -#define ICON_RESTART "system-devices-panel-alert" +#define ICON_INFO "system-devices-panel-information" +#define ICON_ALERT "system-devices-panel-alert" + #define GREETER_ICON_DEFAULT "system-shutdown-panel" #define GREETER_ICON_RESTART "system-shutdown-panel-restart" diff --git a/tests/Makefile.am b/tests/Makefile.am index 5f22130..9371c2e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -14,7 +14,9 @@ AM_CXXFLAGS = $(GTEST_CXXFLAGS) TESTS = test-service check_PROGRAMS = test-service -test_service_SOURCES = test-service.cc +test_service_SOURCES = \ + test-service.cc \ + gtest-dbus-helper.h test_service_LDADD = $(TEST_SERVICE_LIBS) libgtest.a $(XORG_GTEST_MAIN_LIBS) $(X11_LIBS) test_service_CPPFLAGS = \ $(TEST_SERVICE_CFLAGS) \ diff --git a/tests/Makefile.in b/tests/Makefile.in index 85f4e2b..290e5ed 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -107,6 +107,22 @@ CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; @@ -322,7 +338,10 @@ AM_CPPFLAGS = \ -Wall -Werror AM_CXXFLAGS = $(GTEST_CXXFLAGS) -test_service_SOURCES = test-service.cc +test_service_SOURCES = \ + test-service.cc \ + gtest-dbus-helper.h + test_service_LDADD = $(TEST_SERVICE_LIBS) libgtest.a $(XORG_GTEST_MAIN_LIBS) $(X11_LIBS) test_service_CPPFLAGS = \ $(TEST_SERVICE_CFLAGS) \ diff --git a/tests/gtest-dbus-helper.h b/tests/gtest-dbus-helper.h new file mode 100644 index 0000000..c893606 --- /dev/null +++ b/tests/gtest-dbus-helper.h @@ -0,0 +1,418 @@ +/* +Copyright 2012 Canonical Ltd. + +Authors: + Charles Kerr <charles.kerr@canonical.com> + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef INDICATOR_SERVICE_TEST_H +#define INDICATOR_SERVICE_TEST_H + +#include <algorithm> +#include <functional> +#include <string> +#include <vector> + +#include <gio/gio.h> +#include <gtest/gtest.h> +#include <libdbustest/dbus-test.h> +#include <libdbusmenu-glib/client.h> + +/*** +**** +***/ + +/** + * Convenience class for looking at a DbusmenuClient's items for testing + * + * Examples: + * + * // confirm that there are N menuitems of type T + * TEST_EQ (helper.count_type(T), N); + * + * // confirm that there are N visible menuitems + * TEST_EQ (helper.count_property_bool(DBUSMENU_MENUITEM_PROP_VISIBLE,true), N); + * + * // get a sorted list of all the menuitems of type T + * std::vector<DbusmenuMenuitem*> items = helper.find_type(T); + */ +class DbusmenuClientHelper +{ + public: + + DbusmenuClientHelper (DbusmenuClient * client_): client(client_) { + g_object_ref (G_OBJECT(client)); + } + ~DbusmenuClientHelper() { + g_object_unref(G_OBJECT(client)); + client = NULL; + } + + private: + + static void foreach_accumulate_func (DbusmenuMenuitem * mi, gpointer gset) { + static_cast<std::vector<DbusmenuMenuitem*>*>(gset)->push_back (mi); + } + + public: + + std::vector<DbusmenuMenuitem*> + get_all_menuitems () const + { + std::vector<DbusmenuMenuitem*> items; + + DbusmenuMenuitem * root = dbusmenu_client_get_root (client); + if (root != NULL) + dbusmenu_menuitem_foreach (root, foreach_accumulate_func, &items); + + return items; + } + + private: + + template<typename value_type> class PropertyPredicate: + public std::unary_function<DbusmenuMenuitem*,bool> { + protected: + const std::string _key; + const value_type _value; + virtual value_type get_value(DbusmenuMenuitem * mi) const = 0; + public: + PropertyPredicate (const char * propertyName, value_type propertyValue): + _key(propertyName), _value(propertyValue) { } + bool operator()(const DbusmenuMenuitem* cmi) const { + // FIXME: remove const_cast after the dbusmenu_menuitem_propperty_get*() functions are constified + DbusmenuMenuitem * mi = const_cast<DbusmenuMenuitem*>(cmi); + return dbusmenu_menuitem_property_exist (mi, _key.c_str()) && (_value == get_value(mi)); + } + }; + + class StringPropertyPredicate: public PropertyPredicate<std::string> { + protected: + virtual std::string get_value (DbusmenuMenuitem * mi) const { + return dbusmenu_menuitem_property_get(mi, _key.c_str()); + } + public: + StringPropertyPredicate (const char * propName, const char * propValue): + PropertyPredicate (propName, propValue) {} + }; + + class IntPropertyPredicate: public PropertyPredicate<int> { + protected: + virtual int get_value (DbusmenuMenuitem * mi) const { + return dbusmenu_menuitem_property_get_int(mi, _key.c_str()); + } + public: + IntPropertyPredicate (const char * propName, int propValue): + PropertyPredicate (propName, propValue) {} + }; + + class BoolPropertyPredicate: public PropertyPredicate<bool> { + protected: + virtual bool get_value (DbusmenuMenuitem * mi) const { + return dbusmenu_menuitem_property_get_bool(mi, _key.c_str()); + } + public: + BoolPropertyPredicate (const char * propName, bool propValue): + PropertyPredicate (propName, propValue) {} + }; + + public: + + typedef std::vector<DbusmenuMenuitem*> menuitems_t; + + void + match_property (menuitems_t& items, const char * key, const char * value) const + { + const StringPropertyPredicate pred (key, value); + items.erase (std::remove_if (items.begin(), items.end(), std::not1(pred)), items.end()); + } + + void + match_property_int (menuitems_t& items, const char * key, int value) const + { + const IntPropertyPredicate pred (key, value); + items.erase (std::remove_if (items.begin(), items.end(), std::not1(pred)), items.end()); + } + + void + match_property_bool (menuitems_t& items, const char * key, bool value) const + { + const BoolPropertyPredicate pred (key, value); + items.erase (std::remove_if (items.begin(), items.end(), std::not1(pred)), items.end()); + } + + menuitems_t find_property (const char * prop_name, const char * prop_value) const + { + menuitems_t items; + g_return_val_if_fail (prop_name!=NULL, items); + g_return_val_if_fail (prop_value!=NULL, items); + + items = get_all_menuitems (); + match_property (items, prop_name, prop_value); + return items; + } + + menuitems_t find_property_int (const char * prop_name, int prop_value) const + { + std::vector<DbusmenuMenuitem*> items; + g_return_val_if_fail (prop_name!=NULL, items); + + items = get_all_menuitems (); + match_property_int (items, prop_name, prop_value); + return items; + } + + menuitems_t find_property_bool (const char * prop_name, bool prop_value) const + { + std::vector<DbusmenuMenuitem*> items; + g_return_val_if_fail (prop_name!=NULL, items); + + items = get_all_menuitems (); + match_property_bool (items, prop_name, prop_value); + return items; + } + + menuitems_t find_type (const char * type) const + { + return find_property (DBUSMENU_MENUITEM_PROP_TYPE, type); + } + + int count_property (const char * propName, const char * propValue) const + { + return find_property (propName, propValue).size(); + } + + int count_type (const char * type) const + { + return count_property (DBUSMENU_MENUITEM_PROP_TYPE, type); + } + + int count_property_int (const char * propName, int propValue) const + { + return find_property_int (propName, propValue).size(); + } + + int count_property_bool (const char * propName, bool propValue) const + { + return find_property_bool (propName, propValue).size(); + } + + private: + + DbusmenuClient * client; +}; + +/** + * Fixture class for using Google Test on an indicator-service's + * com.canonical.dbusmenu interface. + * + * The SetUp() function starts the service up, waits for it to + * be visible on the bus, then creates a DbusmenuClient and waits + * for its layout-changed signal. This way the test function + * is reached after the menu is available and populated. + * + * TearDown() cleans up the DBus scaffolding and stops the service. + */ +class IndicatorServiceTest : public ::testing::Test +{ + public: + + IndicatorServiceTest(const char * service_name_, + const char * menu_object_path_, + const char * executable_): + menu_client(0), + menu_helper(0), + test_service(0), + indicator_service_proxy(0), + handler_id(0), + executable(executable_), + service_name(service_name_), + menu_object_path(menu_object_path_) + { + // glib one-time init stuff + g_type_init(); + g_assert (g_thread_supported()); + mainloop = g_main_loop_new (NULL, FALSE); + } + + private: + + static void + on_layout_updated_static (DbusmenuClient * client, IndicatorServiceTest * self) + { + g_debug ("LAYOUT UPDATED"); + self->on_layout_updated (client); + } + void + on_layout_updated (DbusmenuClient * client) + { + ASSERT_EQ (client, menu_client); + ASSERT_NE (handler_id, 0); + ASSERT_TRUE (g_signal_handler_is_connected (client, handler_id)); + + // stop listening for this event + g_signal_handler_disconnect (client, handler_id); + handler_id = 0; + + ready(); + } + + private: + + static gboolean + on_timeout_static (gpointer self) + { + static_cast<IndicatorServiceTest*>(self)->on_timeout(); + return false; + } + void + on_timeout() + { + ASSERT_NE (handler_id, 0ul); + g_source_remove (handler_id); + handler_id = 0; + ready(); + } + + protected: + + virtual void + SetUp() + { + ASSERT_EQ (NULL, test_service); + ASSERT_EQ (NULL, menu_helper); + ASSERT_EQ (NULL, indicator_service_proxy); + + test_service = dbus_test_service_new (NULL); + + // Start the executable and wait until it shows up on the bus. + // Unset the NO_WATCHERS env var to ensure that the service + // will shut down when there are no watchers... otherwise + // this task will never finish + g_unsetenv("INDICATOR_ALLOW_NO_WATCHERS"); + DbusTestProcess * indicator_service_task = dbus_test_process_new (executable.c_str()); + dbus_test_service_add_task (test_service, DBUS_TEST_TASK(indicator_service_task)); + g_object_unref (G_OBJECT(indicator_service_task)); + + // create a menu task that waits for our service before it runs + DbusTestTask * wait_task = dbus_test_task_new (); + dbus_test_task_set_wait_for (wait_task, service_name.c_str()); + dbus_test_service_add_task (test_service, wait_task); + g_object_unref (G_OBJECT(wait_task)); + + g_debug ("starting tasks"); + dbus_test_service_start_tasks(test_service); + + // at this point the indicator service is running, let's Watch it + // to ensure it stays alive for the duration of the test + GError * error = NULL; + GDBusConnection * bus_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + indicator_service_proxy = g_dbus_proxy_new_sync (bus_connection, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + service_name.c_str(), + "/org/ayatana/indicator/service", + "org.ayatana.indicator.service", + NULL, + &error); + GVariant * result = g_dbus_proxy_call_sync (indicator_service_proxy, "Watch", + NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, NULL, &error); + guint a, b; + g_variant_get (result, "(uu)", &a, &b); + g_debug ("Sending 'Watch' to proxy %p yielded %u %u", indicator_service_proxy, a, b); + g_variant_unref (result); + EXPECT_EQ(NULL, error); + if (error != NULL) { + g_message ("%s Unable to Watch indicator-service : %s", G_STRFUNC, error->message); + g_clear_error (&error); + } + g_object_unref (G_OBJECT(bus_connection)); + + menu_client = dbusmenu_client_new (service_name.c_str(), menu_object_path.c_str()); + menu_helper = new DbusmenuClientHelper (menu_client); + + // wait for a "layout-updated" signal before we let SetUp finish + wait_for_layout_update(); + } + + virtual void + TearDown() + { + ASSERT_EQ (handler_id, 0); + + // tear down the mainloop + ASSERT_TRUE (mainloop != NULL); + g_main_loop_unref (mainloop); + mainloop = NULL; + + // tear down the menu client + if (menu_helper != NULL) { + delete menu_helper; + menu_helper = NULL; + } + if (menu_client != NULL) { + g_object_unref(G_OBJECT(menu_client)); + menu_client = NULL; + } + + // tear down the indicator proxy + EXPECT_TRUE (G_IS_DBUS_PROXY(indicator_service_proxy)); + g_object_unref (G_OBJECT(indicator_service_proxy)); + indicator_service_proxy = NULL; + } + + void wait_for_layout_update() + { + ASSERT_EQ (handler_id, 0ul); + handler_id = g_signal_connect (menu_client, + DBUSMENU_CLIENT_SIGNAL_LAYOUT_UPDATED, + G_CALLBACK(on_layout_updated_static), + this); + g_debug ("waiting for layout update..."); + g_main_loop_run (mainloop); + } + + void wait_seconds (int seconds) + { + ASSERT_EQ (handler_id, 0ul); + handler_id = g_timeout_add_seconds (seconds, on_timeout_static, this); + g_debug ("waiting %d seconds...", seconds); + g_main_loop_run (mainloop); + } + + protected: + + DbusmenuClient * menu_client; + DbusmenuClientHelper * menu_helper; + + private: + + void ready() + { + g_debug("done waiting"); + g_main_loop_quit (mainloop); + } + + GMainLoop * mainloop; + DbusTestService * test_service; + GDBusProxy * indicator_service_proxy; + gulong handler_id; + const std::string executable; + const std::string service_name; + const std::string menu_object_path; +}; + +#endif // #ifndef INDICATOR_SERVICE_TEST_H diff --git a/tests/test-service.cc b/tests/test-service.cc index 73d905b..37ba4a9 100644 --- a/tests/test-service.cc +++ b/tests/test-service.cc @@ -17,8 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <libindicator/indicator-service-test.h> - +#include "gtest-dbus-helper.h" #include "shared-names.h" /*** |