aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog84
-rw-r--r--NEWS13
-rwxr-xr-xconfigure2
-rw-r--r--configure.ac2
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.in22
-rw-r--r--src/dialog.c6
-rw-r--r--src/indicator-session.c174
-rw-r--r--src/online-accounts-mgr.c166
-rw-r--r--src/online-accounts-mgr.h50
-rw-r--r--src/session-menu-mgr.c38
-rw-r--r--src/shared-names.h4
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/Makefile.in21
-rw-r--r--tests/gtest-dbus-helper.h418
-rw-r--r--tests/test-service.cc3
17 files changed, 980 insertions, 32 deletions
diff --git a/ChangeLog b/ChangeLog
index f707534..864babb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/NEWS b/NEWS
index e69de29..5ac155d 100644
--- a/NEWS
+++ b/NEWS
@@ -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
diff --git a/configure b/configure
index 5e657cc..2117db9 100755
--- a/configure
+++ b/configure
@@ -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"
/***