aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--src/dialog.c6
-rw-r--r--src/indicator-session.c11
-rw-r--r--src/user-widget.c56
-rw-r--r--tests/gtest-dbus-helper.h418
-rw-r--r--tests/test-service.cc3
6 files changed, 456 insertions, 40 deletions
diff --git a/configure.ac b/configure.ac
index 5968927..60722f9 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.0)
+AM_INIT_AUTOMAKE(indicator-session, 12.10.1)
AM_MAINTAINER_MODE
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 53ff87e..3038948 100644
--- a/src/indicator-session.c
+++ b/src/indicator-session.c
@@ -36,7 +36,6 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <libindicator/indicator.h>
#include <libindicator/indicator-object.h>
#include <libindicator/indicator-service-manager.h>
-#include <libindicator/indicator-image-helper.h>
#include "shared-names.h"
#include "user-widget.h"
@@ -117,6 +116,8 @@ 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. */
@@ -131,9 +132,8 @@ indicator_session_init (IndicatorSession *self)
self->entry.name_hint = PACKAGE;
self->entry.accessible_desc = _("Session Menu");
self->entry.label = GTK_LABEL (gtk_label_new ("User Name"));
- self->entry.image = greeter_mode
- ? indicator_image_helper (GREETER_ICON_DEFAULT)
- : indicator_image_helper (ICON_DEFAULT);
+ 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.menu = GTK_MENU (dbusmenu_gtkmenu_new(INDICATOR_SESSION_DBUS_NAME,
INDICATOR_SESSION_DBUS_OBJECT));
g_settings_bind (self->settings, "show-real-name-on-panel",
@@ -341,7 +341,8 @@ receive_signal (GDBusProxy * proxy,
}
else if (!g_strcmp0(signal_name, "RestartRequired"))
{
- indicator_image_helper_update (self->entry.image, greeter_mode ? GREETER_ICON_RESTART : ICON_RESTART);
+ 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);
}
diff --git a/src/user-widget.c b/src/user-widget.c
index b0d2dd4..79b87b0 100644
--- a/src/user-widget.c
+++ b/src/user-widget.c
@@ -89,9 +89,8 @@ user_widget_init (UserWidget *self)
// Create the UI elements.
priv->user_image = gtk_image_new ();
gtk_misc_set_alignment(GTK_MISC(priv->user_image), 0.0, 0.0);
- gtk_misc_set_padding (GTK_MISC(priv->user_image),0, 4.0);
- priv->user_name = gtk_label_new ("");
+ priv->user_name = gtk_label_new (NULL);
priv->container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
@@ -180,40 +179,43 @@ user_widget_primitive_draw_cb_gtk_3 (GtkWidget *widget,
****
***/
-static const int ICON_SIZE = 24;
-
static void
update_icon (UserWidget * self, DbusmenuMenuitem * mi)
{
- GdkPixbuf * pixbuf = NULL;
+ gboolean updated = FALSE;
+ GtkImage * image = GTK_IMAGE(self->priv->user_image);
- /* first, try the menuitem's icon property */
+ /* first try the menuitem's icon property */
const gchar * icon_name = dbusmenu_menuitem_property_get (mi, USER_ITEM_PROP_ICON);
- if (icon_name)
+ if (icon_name != NULL)
{
- GError* error = NULL;
- pixbuf = gdk_pixbuf_new_from_file_at_size (icon_name, ICON_SIZE, ICON_SIZE, &error);
- if (error != NULL)
+ int width = 18; /* arbitrary default values */
+ int height = 18;
+ GError * err = NULL;
+ GdkPixbuf * pixbuf = NULL;
+
+ /* load the image */
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height);
+ pixbuf = gdk_pixbuf_new_from_file_at_size (icon_name, width, height, &err);
+ if (err == NULL)
{
- g_warning ("Couldn't load the image \"%s\": %s", icon_name, error->message);
- g_clear_error (&error);
+ gtk_image_set_from_pixbuf (image, pixbuf);
+ g_object_unref (pixbuf);
+ updated = TRUE;
+ }
+ else
+ {
+ g_warning ("Couldn't load the image \"%s\": %s", icon_name, err->message);
+ g_clear_error (&err);
}
}
- /* as a fallback, try to use the default user icon */
- if (pixbuf == NULL)
- {
- pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
- USER_ITEM_ICON_DEFAULT,
- ICON_SIZE,
- GTK_ICON_LOOKUP_FORCE_SIZE,
- NULL);
- }
-
- if (pixbuf != NULL)
+ /* as a fallback, use the default user icon */
+ if (!updated)
{
- gtk_image_set_from_pixbuf (GTK_IMAGE(self->priv->user_image), pixbuf);
- g_object_unref (pixbuf);
+ gtk_image_set_from_icon_name (image,
+ USER_ITEM_ICON_DEFAULT,
+ GTK_ICON_SIZE_MENU);
}
}
@@ -277,7 +279,9 @@ user_widget_set_twin_item (UserWidget * self, DbusmenuMenuitem * mi)
/**
* user_widget_new:
- * @returns: a new #UserWidget.
+ * @item: the #DbusmenuMenuitem this widget will render.
+ *
+ * Returns: (transfer full): a new #UserWidget.
**/
GtkWidget*
user_widget_new (DbusmenuMenuitem *item)
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"
/***