From 7eb00e86d2d9f25dbc62c5a4479e99ea5543d722 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Fri, 10 Oct 2014 16:11:36 -0500 Subject: add gsettings for a mock battery to make QA tester's lives easier --- src/CMakeLists.txt | 1 + src/device-provider-mock.c | 107 +++++++++++++++++++++++++++++++++++++++++++++ src/device-provider-mock.h | 79 +++++++++++++++++++++++++++++++++ src/main.c | 70 ++++++++++++++++++++++++++--- 4 files changed, 252 insertions(+), 5 deletions(-) create mode 100644 src/device-provider-mock.c create mode 100644 src/device-provider-mock.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f7efb80..00b0ee2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,7 @@ add_definitions(-DG_LOG_DOMAIN="Indicator-Power") # handwritten sources set(SERVICE_MANUAL_SOURCES brightness.c + device-provider-mock.c device-provider-upower.c device-provider.c device.c diff --git a/src/device-provider-mock.c b/src/device-provider-mock.c new file mode 100644 index 0000000..ccb80f0 --- /dev/null +++ b/src/device-provider-mock.c @@ -0,0 +1,107 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Charles Kerr + */ + +#include "device.h" +#include "device-provider.h" +#include "device-provider-mock.h" + +/*** +**** GObject boilerplate +***/ + +static void indicator_power_device_provider_interface_init ( + IndicatorPowerDeviceProviderInterface * iface); + +G_DEFINE_TYPE_WITH_CODE ( + IndicatorPowerDeviceProviderMock, + indicator_power_device_provider_mock, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (INDICATOR_TYPE_POWER_DEVICE_PROVIDER, + indicator_power_device_provider_interface_init)) + +/*** +**** IndicatorPowerDeviceProvider virtual functions +***/ + +static GList * +my_get_devices (IndicatorPowerDeviceProvider * provider) +{ + IndicatorPowerDeviceProviderMock * self = INDICATOR_POWER_DEVICE_PROVIDER_MOCK(provider); + + return g_list_copy_deep (self->devices, (GCopyFunc)g_object_ref, NULL); +} + +/*** +**** GObject virtual functions +***/ + +static void +my_dispose (GObject * o) +{ + IndicatorPowerDeviceProviderMock * self = INDICATOR_POWER_DEVICE_PROVIDER_MOCK(o); + + g_list_free_full (self->devices, g_object_unref); + + G_OBJECT_CLASS (indicator_power_device_provider_mock_parent_class)->dispose (o); +} + +/*** +**** Instantiation +***/ + +static void +indicator_power_device_provider_mock_class_init (IndicatorPowerDeviceProviderMockClass * klass) +{ + GObjectClass * object_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = my_dispose; +} + +static void +indicator_power_device_provider_interface_init (IndicatorPowerDeviceProviderInterface * iface) +{ + iface->get_devices = my_get_devices; +} + +static void +indicator_power_device_provider_mock_init (IndicatorPowerDeviceProviderMock * self G_GNUC_UNUSED) +{ +} + +/*** +**** Public API +***/ + +IndicatorPowerDeviceProvider * +indicator_power_device_provider_mock_new (void) +{ + gpointer o = g_object_new (INDICATOR_TYPE_POWER_DEVICE_PROVIDER_MOCK, NULL); + + return INDICATOR_POWER_DEVICE_PROVIDER (o); +} + +void +indicator_power_device_provider_add_device (IndicatorPowerDeviceProviderMock * provider, + IndicatorPowerDevice * device) +{ + provider->devices = g_list_append (provider->devices, g_object_ref(device)); + + g_signal_connect_swapped (device, "notify", G_CALLBACK(indicator_power_device_provider_emit_devices_changed), provider); +} diff --git a/src/device-provider-mock.h b/src/device-provider-mock.h new file mode 100644 index 0000000..4d06924 --- /dev/null +++ b/src/device-provider-mock.h @@ -0,0 +1,79 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Charles Kerr + */ + +#ifndef __INDICATOR_POWER_DEVICE_PROVIDER_MOCK__H__ +#define __INDICATOR_POWER_DEVICE_PROVIDER_MOCK__H__ + +#include /* parent class */ + +#include "device.h" +#include "device-provider.h" + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_POWER_DEVICE_PROVIDER_MOCK \ + (indicator_power_device_provider_mock_get_type()) + +#define INDICATOR_POWER_DEVICE_PROVIDER_MOCK(o) \ + (G_TYPE_CHECK_INSTANCE_CAST ((o), \ + INDICATOR_TYPE_POWER_DEVICE_PROVIDER_MOCK, \ + IndicatorPowerDeviceProviderMock)) + +#define INDICATOR_POWER_DEVICE_PROVIDER_MOCK_GET_CLASS(o) \ + (G_TYPE_INSTANCE_GET_CLASS ((o), \ + INDICATOR_TYPE_POWER_DEVICE_PROVIDER_MOCK, \ + IndicatorPowerDeviceProviderMockClass)) + +#define INDICATOR_IS_POWER_DEVICE_PROVIDER_MOCK(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((o), \ + INDICATOR_TYPE_POWER_DEVICE_PROVIDER_MOCK)) + +typedef struct _IndicatorPowerDeviceProviderMock + IndicatorPowerDeviceProviderMock; +typedef struct _IndicatorPowerDeviceProviderMockPriv + IndicatorPowerDeviceProviderMockPriv; +typedef struct _IndicatorPowerDeviceProviderMockClass + IndicatorPowerDeviceProviderMockClass; + +/** + * An IndicatorPowerDeviceProvider which gets its devices from Mock. + */ +struct _IndicatorPowerDeviceProviderMock +{ + GObject parent_instance; + + /*< private >*/ + GList * devices; +}; + +struct _IndicatorPowerDeviceProviderMockClass +{ + GObjectClass parent_class; +}; + +GType indicator_power_device_provider_mock_get_type (void); + +IndicatorPowerDeviceProvider * indicator_power_device_provider_mock_new (void); + +void indicator_power_device_provider_add_device (IndicatorPowerDeviceProviderMock * provider, + IndicatorPowerDevice * device); + +G_END_DECLS + +#endif /* __INDICATOR_POWER_DEVICE_PROVIDER_MOCK__H__ */ diff --git a/src/main.c b/src/main.c index d7953e6..112c31e 100644 --- a/src/main.c +++ b/src/main.c @@ -24,9 +24,62 @@ #include #include "device.h" +#include "device-provider-mock.h" #include "device-provider-upower.h" #include "service.h" +/*** +**** MOCK +***/ + +static IndicatorPowerDevice* +get_mock_battery(GSettings * settings) +{ + const double percent = g_settings_get_int(settings, "mock-battery-level"); + + const UpDeviceState state = g_settings_get_boolean(settings, "mock-battery-charging") + ? UP_DEVICE_STATE_CHARGING + : UP_DEVICE_STATE_DISCHARGING; + + const int seconds_left = g_settings_get_int(settings, "mock-battery-minutes-left") * 60; + + return indicator_power_device_new ("/some/path", + UP_DEVICE_KIND_BATTERY, + percent, + state, + seconds_left); +} + +static IndicatorPowerDeviceProvider* +get_device_provider(GSettings * settings) +{ + IndicatorPowerDeviceProvider * provider = NULL; + + if (g_settings_get_boolean(settings, "mock-battery-enabled")) + { + IndicatorPowerDevice * battery = get_mock_battery(settings); + provider = indicator_power_device_provider_mock_new (); + indicator_power_device_provider_add_device (INDICATOR_POWER_DEVICE_PROVIDER_MOCK(provider), battery); + g_object_unref (battery); + } + else + { + provider = indicator_power_device_provider_upower_new (); + } + + return provider; +} + +static void +on_mock_settings_changed(GSettings* settings, + gchar * key G_GNUC_UNUSED, + gpointer service) +{ + IndicatorPowerDeviceProvider* provider = get_device_provider(settings); + indicator_power_service_set_device_provider (INDICATOR_POWER_SERVICE(service), provider); + g_object_unref(provider); +} + /*** **** ***/ @@ -41,18 +94,25 @@ on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop) int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) { - IndicatorPowerDeviceProvider * device_provider; - IndicatorPowerService * service; + GSettings * settings; GMainLoop * loop; + IndicatorPowerService * service; /* boilerplate i18n */ setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain (GETTEXT_PACKAGE); + /* mock settings */ + service = indicator_power_service_new (NULL); + settings = g_settings_new ("com.canonical.indicator.power"); + g_signal_connect(settings, "changed::mock-battery-enabled", G_CALLBACK(on_mock_settings_changed), service); + g_signal_connect(settings, "changed::mock-battery-level", G_CALLBACK(on_mock_settings_changed), service); + g_signal_connect(settings, "changed::mock-battery-charging", G_CALLBACK(on_mock_settings_changed), service); + g_signal_connect(settings, "changed::mock-battery-minutes-left", G_CALLBACK(on_mock_settings_changed), service); + on_mock_settings_changed(settings, NULL, service); + /* run */ - device_provider = indicator_power_device_provider_upower_new (); - service = indicator_power_service_new (device_provider); loop = g_main_loop_new (NULL, FALSE); g_signal_connect (service, INDICATOR_POWER_SERVICE_SIGNAL_NAME_LOST, G_CALLBACK(on_name_lost), loop); @@ -61,6 +121,6 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) /* cleanup */ g_main_loop_unref (loop); g_clear_object (&service); - g_clear_object (&device_provider); + g_clear_object (&settings); return 0; } -- cgit v1.2.3 From 1e530c28e3b72cdb130594a8c46c6db462f49af4 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 14 Oct 2014 14:07:50 -0500 Subject: make service's bus connection a property so that IndicatorPowerTesting can listen for it and export an object before the name is acquired --- src/service.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/service.c b/src/service.c index 32cec38..6bae06e 100644 --- a/src/service.c +++ b/src/service.c @@ -51,6 +51,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, + PROP_BUS, PROP_DEVICE_PROVIDER, LAST_PROP }; @@ -839,6 +840,7 @@ on_bus_acquired (GDBusConnection * connection, g_debug ("bus acquired: %s", name); p->conn = g_object_ref (G_OBJECT (connection)); + g_object_notify_by_pspec (G_OBJECT(self), properties[PROP_BUS]); /* export the battery properties */ indicator_power_notifier_set_bus (p->notifier, connection); @@ -977,6 +979,10 @@ my_get_property (GObject * o, switch (property_id) { + case PROP_BUS: + g_value_set_object (value, p->conn); + break; + case PROP_DEVICE_PROVIDER: g_value_set_object (value, p->device_provider); break; @@ -1113,6 +1119,13 @@ indicator_power_service_class_init (IndicatorPowerServiceClass * klass) properties[PROP_0] = NULL; + properties[PROP_BUS] = g_param_spec_object ( + "bus", + "Bus", + "GDBusConnection for exporting menus/actions", + G_TYPE_OBJECT, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + properties[PROP_DEVICE_PROVIDER] = g_param_spec_object ( "device-provider", "Device Provider", -- cgit v1.2.3 From 407c63c08ab7c08085230712cf0d1020f01f1cc3 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 14 Oct 2014 14:09:00 -0500 Subject: fix notify get-capabilities startup blocking bug found in testing --- src/notifier.c | 56 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/notifier.c b/src/notifier.c index 993e332..b0fce15 100644 --- a/src/notifier.c +++ b/src/notifier.c @@ -76,6 +76,8 @@ typedef struct GDBusConnection * bus; DbusBattery * dbus_battery; /* com.canonical.indicator.power.Battery skeleton */ + + guint notify_init_tag; } IndicatorPowerNotifierPrivate; @@ -332,6 +334,12 @@ my_dispose (GObject * o) IndicatorPowerNotifier * const self = INDICATOR_POWER_NOTIFIER(o); priv_t * const p = get_priv (self); + if (p->notify_init_tag) + { + g_source_remove(p->notify_init_tag); + p->notify_init_tag = 0; + } + indicator_power_notifier_set_bus (self, NULL); notification_clear (self); indicator_power_notifier_set_battery (self, NULL); @@ -354,6 +362,35 @@ my_finalize (GObject * o G_GNUC_UNUSED) **** Instantiation ***/ +static gboolean +notify_init_idle (gpointer gself) +{ + IndicatorPowerNotifier * self = INDICATOR_POWER_NOTIFIER(gself); + + actions_supported = FALSE; + + if (!notify_init("indicator-power-service")) + { + g_critical("Unable to initialize libnotify! Notifications might not be shown."); + } + else + { + GList * caps; + GList * l; + + /* see if actions are supported */ + caps = notify_get_server_caps(); + for (l=caps; l!=NULL && !actions_supported; l=l->next) + if (!g_strcmp0(l->data, "actions")) + actions_supported = TRUE; + + g_list_free_full(caps, g_free); + } + + get_priv(self)->notify_init_tag = 0; + return G_SOURCE_REMOVE; +} + static void indicator_power_notifier_init (IndicatorPowerNotifier * self) { @@ -367,24 +404,7 @@ indicator_power_notifier_init (IndicatorPowerNotifier * self) if (!instance_count++) { - actions_supported = FALSE; - - if (!notify_init("indicator-power-service")) - { - g_critical("Unable to initialize libnotify! Notifications might not be shown."); - } - else - { - GList * caps; - GList * l; - - /* see if actions are supported */ - caps = notify_get_server_caps(); - for (l=caps; l!=NULL && !actions_supported; l=l->next) - if (!g_strcmp0(l->data, "actions")) - actions_supported = TRUE; - g_list_free_full(caps, g_free); - } + p->notify_init_tag = g_idle_add (notify_init_idle, self); } } -- cgit v1.2.3 From f599c1b1f4b7bc40d71b36409826dcab47e4b7af Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 14 Oct 2014 14:09:32 -0500 Subject: move the mock battery from GSettings to DBus --- src/CMakeLists.txt | 5 + src/main.c | 75 ++--------- src/testing.c | 364 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/testing.h | 66 ++++++++++ tests/manual | 34 +++-- 5 files changed, 469 insertions(+), 75 deletions(-) create mode 100644 src/testing.c create mode 100644 src/testing.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 00b0ee2..6f4bfaf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,7 @@ set(SERVICE_MANUAL_SOURCES device-provider.c device.c notifier.c + testing.c service.c) # generated sources @@ -20,6 +21,10 @@ add_gdbus_codegen_with_namespace(SERVICE_GENERATED_SOURCES dbus-battery com.canonical.indicator.power Dbus ${CMAKE_SOURCE_DIR}/data/com.canonical.indicator.power.Battery.xml) +add_gdbus_codegen_with_namespace(SERVICE_GENERATED_SOURCES dbus-testing + com.canonical.indicator.power + Dbus + ${CMAKE_SOURCE_DIR}/data/com.canonical.indicator.power.Testing.xml) # add the bin dir to our include path so the code can find the generated header files include_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/src/main.c b/src/main.c index 112c31e..eaa4070 100644 --- a/src/main.c +++ b/src/main.c @@ -18,67 +18,13 @@ */ #include -#include /* exit() */ +#include #include -#include #include "device.h" -#include "device-provider-mock.h" -#include "device-provider-upower.h" #include "service.h" - -/*** -**** MOCK -***/ - -static IndicatorPowerDevice* -get_mock_battery(GSettings * settings) -{ - const double percent = g_settings_get_int(settings, "mock-battery-level"); - - const UpDeviceState state = g_settings_get_boolean(settings, "mock-battery-charging") - ? UP_DEVICE_STATE_CHARGING - : UP_DEVICE_STATE_DISCHARGING; - - const int seconds_left = g_settings_get_int(settings, "mock-battery-minutes-left") * 60; - - return indicator_power_device_new ("/some/path", - UP_DEVICE_KIND_BATTERY, - percent, - state, - seconds_left); -} - -static IndicatorPowerDeviceProvider* -get_device_provider(GSettings * settings) -{ - IndicatorPowerDeviceProvider * provider = NULL; - - if (g_settings_get_boolean(settings, "mock-battery-enabled")) - { - IndicatorPowerDevice * battery = get_mock_battery(settings); - provider = indicator_power_device_provider_mock_new (); - indicator_power_device_provider_add_device (INDICATOR_POWER_DEVICE_PROVIDER_MOCK(provider), battery); - g_object_unref (battery); - } - else - { - provider = indicator_power_device_provider_upower_new (); - } - - return provider; -} - -static void -on_mock_settings_changed(GSettings* settings, - gchar * key G_GNUC_UNUSED, - gpointer service) -{ - IndicatorPowerDeviceProvider* provider = get_device_provider(settings); - indicator_power_service_set_device_provider (INDICATOR_POWER_SERVICE(service), provider); - g_object_unref(provider); -} +#include "testing.h" /*** **** @@ -94,25 +40,18 @@ on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop) int main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) { - GSettings * settings; - GMainLoop * loop; IndicatorPowerService * service; + IndicatorPowerTesting * testing; + GMainLoop * loop; /* boilerplate i18n */ setlocale (LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain (GETTEXT_PACKAGE); - /* mock settings */ - service = indicator_power_service_new (NULL); - settings = g_settings_new ("com.canonical.indicator.power"); - g_signal_connect(settings, "changed::mock-battery-enabled", G_CALLBACK(on_mock_settings_changed), service); - g_signal_connect(settings, "changed::mock-battery-level", G_CALLBACK(on_mock_settings_changed), service); - g_signal_connect(settings, "changed::mock-battery-charging", G_CALLBACK(on_mock_settings_changed), service); - g_signal_connect(settings, "changed::mock-battery-minutes-left", G_CALLBACK(on_mock_settings_changed), service); - on_mock_settings_changed(settings, NULL, service); - /* run */ + service = indicator_power_service_new (NULL); + testing = indicator_power_testing_new (service); loop = g_main_loop_new (NULL, FALSE); g_signal_connect (service, INDICATOR_POWER_SERVICE_SIGNAL_NAME_LOST, G_CALLBACK(on_name_lost), loop); @@ -121,6 +60,6 @@ main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED) /* cleanup */ g_main_loop_unref (loop); g_clear_object (&service); - g_clear_object (&settings); + g_clear_object (&testing); return 0; } diff --git a/src/testing.c b/src/testing.c new file mode 100644 index 0000000..dadf942 --- /dev/null +++ b/src/testing.c @@ -0,0 +1,364 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Charles Kerr + */ + +#include "dbus-shared.h" +#include "device-provider-mock.h" +#include "device-provider-upower.h" +#include "dbus-testing.h" +#include "service.h" +#include "testing.h" + +#include + +/** +*** GObject Properties +**/ + +enum +{ + PROP_0, + PROP_BUS, + PROP_SERVICE, + LAST_PROP +}; + +static GParamSpec * properties[LAST_PROP]; + +/** +*** +**/ + +typedef struct +{ + GDBusConnection * bus; + DbusTesting * skeleton; + IndicatorPowerService * service; + IndicatorPowerDevice * battery_mock; + gpointer provider_mock; + gpointer provider_upower; +} +IndicatorPowerTestingPrivate; + +typedef IndicatorPowerTestingPrivate priv_t; + +G_DEFINE_TYPE_WITH_PRIVATE(IndicatorPowerTesting, + indicator_power_testing, + G_TYPE_OBJECT) + +#define get_priv(o) ((priv_t*)indicator_power_testing_get_instance_private(o)) + +/*** +**** +***/ + +static void +update_device_provider (IndicatorPowerTesting * self) +{ + priv_t * const p = get_priv(self); + IndicatorPowerDeviceProvider * device_provider; + + device_provider = dbus_testing_get_mock_battery_enabled(p->skeleton) + ? p->provider_mock + : p->provider_upower; + indicator_power_service_set_device_provider(p->service, device_provider); +} + +static void +on_mock_battery_enabled_changed(DbusTesting * skeleton G_GNUC_UNUSED, + GParamSpec * pspec G_GNUC_UNUSED, + IndicatorPowerTesting * self) +{ + update_device_provider (self); +} + +static void +on_mock_battery_level_changed(DbusTesting * skeleton, + GParamSpec * pspec G_GNUC_UNUSED, + IndicatorPowerTesting * self) +{ + g_object_set(get_priv(self)->battery_mock, + INDICATOR_POWER_DEVICE_PERCENTAGE, (gdouble)dbus_testing_get_mock_battery_level(skeleton), + NULL); +} + +static void +on_mock_battery_state_changed(DbusTesting * skeleton, + GParamSpec * pspec G_GNUC_UNUSED, + IndicatorPowerTesting * self) +{ + const gchar* state_str = dbus_testing_get_mock_battery_state(skeleton); + UpDeviceState state; + + if (!g_strcmp0(state_str, "charging")) + { + state = UP_DEVICE_STATE_CHARGING; + } + else if (!g_strcmp0(state_str, "discharging")) + { + state = UP_DEVICE_STATE_DISCHARGING; + } + else + { + g_warning("%s unsupported state: '%s'", G_STRLOC, state_str); + state = UP_DEVICE_STATE_UNKNOWN; + } + + g_object_set(get_priv(self)->battery_mock, + INDICATOR_POWER_DEVICE_STATE, (gint)state, + NULL); +} + +static void +on_mock_battery_minutes_left_changed(DbusTesting * skeleton, + GParamSpec * pspec G_GNUC_UNUSED, + IndicatorPowerTesting * self) +{ + g_object_set(get_priv(self)->battery_mock, + INDICATOR_POWER_DEVICE_TIME, (guint64)dbus_testing_get_mock_battery_minutes_left(skeleton), + NULL); +} + +static void +on_bus_changed(IndicatorPowerService * service, + GParamSpec * spec G_GNUC_UNUSED, + IndicatorPowerTesting * self) +{ + GObject * bus = NULL; + g_object_get(service, "bus", &bus, NULL); + indicator_power_testing_set_bus(self, G_DBUS_CONNECTION(bus)); + g_clear_object(&bus); +} + +/*** +**** GObject virtual functions +***/ + +static void +my_get_property(GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorPowerTesting * const self = INDICATOR_POWER_TESTING (o); + priv_t * const p = get_priv(self); + + switch (property_id) + { + case PROP_BUS: + g_value_set_object(value, p->bus); + break; + + case PROP_SERVICE: + g_value_set_object(value, p->service); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(o, property_id, pspec); + } +} + +static void +my_set_property(GObject * o, + guint property_id, + const GValue * value, + GParamSpec * pspec) +{ + IndicatorPowerTesting * const self = INDICATOR_POWER_TESTING (o); + priv_t * const p = get_priv(self); + + switch (property_id) + { + case PROP_BUS: + indicator_power_testing_set_bus(self, G_DBUS_CONNECTION(g_value_get_object(value))); + break; + + case PROP_SERVICE: + g_assert(p->service == NULL); /* G_PARAM_CONSTRUCT_ONLY */ + p->service = g_value_dup_object(value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(o, property_id, pspec); + } +} + +static void +my_dispose(GObject * o) +{ + IndicatorPowerTesting * const self = INDICATOR_POWER_TESTING(o); + priv_t * const p = get_priv (self); + + indicator_power_testing_set_bus(self, NULL); + g_clear_object(&p->skeleton); + g_clear_object(&p->provider_upower); + g_clear_object(&p->provider_mock); + g_clear_object(&p->battery_mock); + g_clear_object(&p->service); + + G_OBJECT_CLASS (indicator_power_testing_parent_class)->dispose(o); +} + +static void +my_finalize (GObject * o G_GNUC_UNUSED) +{ +} + +static void +my_constructed (GObject * o) +{ + IndicatorPowerTesting * const self = INDICATOR_POWER_TESTING(o); + priv_t * const p = get_priv (self); + + g_assert(p->service != NULL); /* G_PARAM_CONSTRUCT_ONLY */ + g_signal_connect(p->service, "notify::bus", G_CALLBACK(on_bus_changed), o); + on_bus_changed(p->service, NULL, self); + update_device_provider(self); +} + + +/*** +**** Instantiation +***/ + +static void +indicator_power_testing_init (IndicatorPowerTesting * self) +{ + priv_t * const p = get_priv (self); + + /* DBus Skeleton */ + + p->skeleton = dbus_testing_skeleton_new(); + dbus_testing_set_mock_battery_level(p->skeleton, 50u); + dbus_testing_set_mock_battery_state(p->skeleton, "discharging"); + dbus_testing_set_mock_battery_enabled(p->skeleton, FALSE); + dbus_testing_set_mock_battery_minutes_left(p->skeleton, 30); + + g_signal_connect(p->skeleton, "notify::mock-battery-enabled", + G_CALLBACK(on_mock_battery_enabled_changed), self); + g_signal_connect(p->skeleton, "notify::mock-battery-level", + G_CALLBACK(on_mock_battery_level_changed), self); + g_signal_connect(p->skeleton, "notify::mock-battery-state", + G_CALLBACK(on_mock_battery_state_changed), self); + g_signal_connect(p->skeleton, "notify::mock-battery-minutes-left", + G_CALLBACK(on_mock_battery_minutes_left_changed), self); + + /* Mock Battery */ + + p->battery_mock = indicator_power_device_new("/some/path", + UP_DEVICE_KIND_BATTERY, + 50.0, + UP_DEVICE_STATE_DISCHARGING, + 60*30); + + + /* Mock Provider */ + + p->provider_mock = indicator_power_device_provider_mock_new(); + + indicator_power_device_provider_add_device(INDICATOR_POWER_DEVICE_PROVIDER_MOCK(p->provider_mock), + p->battery_mock); + + /* UPower Provider */ + + p->provider_upower = indicator_power_device_provider_upower_new(); +} + +static void +indicator_power_testing_class_init (IndicatorPowerTestingClass * klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = my_dispose; + object_class->finalize = my_finalize; + object_class->constructed = my_constructed; + object_class->get_property = my_get_property; + object_class->set_property = my_set_property; + + properties[PROP_BUS] = g_param_spec_object ( + "bus", + "Bus", + "The GDBusConnection on which to export menus", + G_TYPE_OBJECT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + properties[PROP_SERVICE] = g_param_spec_object ( + "service", + "Servie", + "The IndicatorPower Service", + G_TYPE_OBJECT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, LAST_PROP, properties); +} + +/*** +**** Public API +***/ + +IndicatorPowerTesting * +indicator_power_testing_new (IndicatorPowerService * service) +{ + GObject * o = g_object_new (INDICATOR_TYPE_POWER_TESTING, "service", service, NULL); + + return INDICATOR_POWER_TESTING (o); +} + +void +indicator_power_testing_set_bus(IndicatorPowerTesting * self, + GDBusConnection * bus) +{ + priv_t * p; + GDBusInterfaceSkeleton * skel; + + g_return_if_fail(INDICATOR_IS_POWER_TESTING(self)); + g_return_if_fail((bus == NULL) || G_IS_DBUS_CONNECTION(bus)); + + p = get_priv (self); + + if (p->bus == bus) + return; + + skel = G_DBUS_INTERFACE_SKELETON(p->skeleton); + + if (p->bus != NULL) + { + if (skel != NULL) + g_dbus_interface_skeleton_unexport (skel); + + g_clear_object (&p->bus); + } + + if (bus != NULL) + { + GError * error; + + p->bus = g_object_ref (bus); + + error = NULL; + if (!g_dbus_interface_skeleton_export(skel, + bus, + BUS_PATH"/Testing", + &error)) + { + g_warning ("Unable to export Testing properties: %s", error->message); + g_error_free (error); + } + } +} + diff --git a/src/testing.h b/src/testing.h new file mode 100644 index 0000000..1370170 --- /dev/null +++ b/src/testing.h @@ -0,0 +1,66 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Charles Kerr + */ + +#ifndef __INDICATOR_POWER_TESTING_H__ +#define __INDICATOR_POWER_TESTING_H__ + +#include + +#include "service.h" + +G_BEGIN_DECLS + +/* standard GObject macros */ +#define INDICATOR_POWER_TESTING(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_POWER_TESTING, IndicatorPowerTesting)) +#define INDICATOR_TYPE_POWER_TESTING (indicator_power_testing_get_type()) +#define INDICATOR_IS_POWER_TESTING(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_POWER_TESTING)) +#define INDICATOR_POWER_TESTING_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), INDICATOR_TYPE_POWER_TESTING, IndicatorPowerTestingClass)) + +typedef struct _IndicatorPowerTesting IndicatorPowerTesting; +typedef struct _IndicatorPowerTestingClass IndicatorPowerTestingClass; + +/** + * The Indicator Power Testing. + */ +struct _IndicatorPowerTesting +{ + /*< private >*/ + GObject parent; +}; + +struct _IndicatorPowerTestingClass +{ + GObjectClass parent_class; +}; + +/*** +**** +***/ + +GType indicator_power_testing_get_type (void); + +IndicatorPowerTesting * indicator_power_testing_new (IndicatorPowerService * service); + +void indicator_power_testing_set_bus (IndicatorPowerTesting * self, + GDBusConnection * connection); + + +G_END_DECLS + +#endif /* __INDICATOR_POWER_TESTING_H__ */ diff --git a/tests/manual b/tests/manual index a7351bc..1e6febd 100644 --- a/tests/manual +++ b/tests/manual @@ -1,17 +1,37 @@ Notes on Battery Testing -Mock battery settings are available for testing purposes. +Mock battery propreties are available for testing purposes. -The indicator's schema name is "com.canonical.indicator.power" and there are four keys: "mock-battery-enabled" (a boolean), "mock-battery-level" (charger percent, an integer from 0-100), "mock-battery-charging" (a boolean of whether the mock battery is charging or discharging), and "mock-battery-minutes-left" (minutes remaining to charge/discharge). +The testing properties are DBus properties published on busname "com.canonical.indicator.power", object path "/com/canonical/indicator/power/Testing", and interface "com.canonical.indicator.power.Testing". The four properties are "MockBatteryEnabled" (boolean, default false), "MockBatteryLevel" (uint32 [0-100], default 50), "MockBatteryState" (string, default 'discharging'), "MockBatteryMinutesLeft" (minutes remaining to charge/discharge, uint32, default 30). Example use: -$ gsettings reset-recursively com.canonical.indicator.power # reset settings to the default state -$ gsettings list-recursively com.canonical.indicator.power | grep mock # show the current mock settings -$ gsettings set com.canonical.indicator.power mock-battery-enabled true # use the mock battery -$ gsettings set com.canonical.indicator.power mock-battery-level 10 # set the mock battery's charge to 10% -$ gsettings set com.canonical.indicator.power mock-battery-enabled false # go back to production settings +Show the testing properties: + +$ gdbus call --session --dest "com.canonical.indicator.power" \ + --object-path /com/canonical/indicator/power/Testing \ + --method org.freedesktop.DBus.Properties.GetAll \ + com.canonical.indicator.power.Testing +({'MockBatteryEnabled': , 'MockBatteryLevel': , 'MockBatteryState': <'discharging'>, 'MockBatteryMinutesLeft': },) + +Enable the mock battery: + +$ gdbus call --session --dest "com.canonical.indicator.power" \ + --object-path /com/canonical/indicator/power/Testing \ + --method org.freedesktop.DBus.Properties.Set \ + com.canonical.indicator.power.Testing \ + MockBatteryEnabled \ + "" + +Set the mock battery's charge to 10% + +$ gdbus call --session --dest "com.canonical.indicator.power" \ + --object-path /com/canonical/indicator/power/Testing \ + --method org.freedesktop.DBus.Properties.Set \ + com.canonical.indicator.power.Testing \ + MockBatteryLevel \ + "" Test-case indicator-power/unity7-items-check -- cgit v1.2.3 From 5f316dca4eab9f3b3048af82c680087949dc7d1f Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 14 Oct 2014 14:50:47 -0500 Subject: in testing.c, make 'bus' a private field instead of a public GObject property --- src/testing.c | 109 ++++++++++++++++++++++++++-------------------------------- 1 file changed, 48 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/testing.c b/src/testing.c index dadf942..2822b7e 100644 --- a/src/testing.c +++ b/src/testing.c @@ -33,7 +33,6 @@ enum { PROP_0, - PROP_BUS, PROP_SERVICE, LAST_PROP }; @@ -79,6 +78,52 @@ update_device_provider (IndicatorPowerTesting * self) indicator_power_service_set_device_provider(p->service, device_provider); } +static void +set_bus(IndicatorPowerTesting * self, GDBusConnection * bus) +{ + priv_t * p; + GDBusInterfaceSkeleton * skel; + + g_return_if_fail(INDICATOR_IS_POWER_TESTING(self)); + g_return_if_fail((bus == NULL) || G_IS_DBUS_CONNECTION(bus)); + + p = get_priv (self); + + if (p->bus == bus) + return; + + skel = G_DBUS_INTERFACE_SKELETON(p->skeleton); + + if (p->bus != NULL) + { + if (skel != NULL) + g_dbus_interface_skeleton_unexport (skel); + + g_clear_object (&p->bus); + } + + if (bus != NULL) + { + GError * error; + + p->bus = g_object_ref (bus); + + error = NULL; + if (!g_dbus_interface_skeleton_export(skel, + bus, + BUS_PATH"/Testing", + &error)) + { + g_warning ("Unable to export Testing properties: %s", error->message); + g_error_free (error); + } + } +} + +/*** +**** +***/ + static void on_mock_battery_enabled_changed(DbusTesting * skeleton G_GNUC_UNUSED, GParamSpec * pspec G_GNUC_UNUSED, @@ -141,7 +186,7 @@ on_bus_changed(IndicatorPowerService * service, { GObject * bus = NULL; g_object_get(service, "bus", &bus, NULL); - indicator_power_testing_set_bus(self, G_DBUS_CONNECTION(bus)); + set_bus(self, G_DBUS_CONNECTION(bus)); g_clear_object(&bus); } @@ -160,10 +205,6 @@ my_get_property(GObject * o, switch (property_id) { - case PROP_BUS: - g_value_set_object(value, p->bus); - break; - case PROP_SERVICE: g_value_set_object(value, p->service); break; @@ -184,10 +225,6 @@ my_set_property(GObject * o, switch (property_id) { - case PROP_BUS: - indicator_power_testing_set_bus(self, G_DBUS_CONNECTION(g_value_get_object(value))); - break; - case PROP_SERVICE: g_assert(p->service == NULL); /* G_PARAM_CONSTRUCT_ONLY */ p->service = g_value_dup_object(value); @@ -204,7 +241,7 @@ my_dispose(GObject * o) IndicatorPowerTesting * const self = INDICATOR_POWER_TESTING(o); priv_t * const p = get_priv (self); - indicator_power_testing_set_bus(self, NULL); + set_bus(self, NULL); g_clear_object(&p->skeleton); g_clear_object(&p->provider_upower); g_clear_object(&p->provider_mock); @@ -290,13 +327,6 @@ indicator_power_testing_class_init (IndicatorPowerTestingClass * klass) object_class->get_property = my_get_property; object_class->set_property = my_set_property; - properties[PROP_BUS] = g_param_spec_object ( - "bus", - "Bus", - "The GDBusConnection on which to export menus", - G_TYPE_OBJECT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - properties[PROP_SERVICE] = g_param_spec_object ( "service", "Servie", @@ -319,46 +349,3 @@ indicator_power_testing_new (IndicatorPowerService * service) return INDICATOR_POWER_TESTING (o); } -void -indicator_power_testing_set_bus(IndicatorPowerTesting * self, - GDBusConnection * bus) -{ - priv_t * p; - GDBusInterfaceSkeleton * skel; - - g_return_if_fail(INDICATOR_IS_POWER_TESTING(self)); - g_return_if_fail((bus == NULL) || G_IS_DBUS_CONNECTION(bus)); - - p = get_priv (self); - - if (p->bus == bus) - return; - - skel = G_DBUS_INTERFACE_SKELETON(p->skeleton); - - if (p->bus != NULL) - { - if (skel != NULL) - g_dbus_interface_skeleton_unexport (skel); - - g_clear_object (&p->bus); - } - - if (bus != NULL) - { - GError * error; - - p->bus = g_object_ref (bus); - - error = NULL; - if (!g_dbus_interface_skeleton_export(skel, - bus, - BUS_PATH"/Testing", - &error)) - { - g_warning ("Unable to export Testing properties: %s", error->message); - g_error_free (error); - } - } -} - -- cgit v1.2.3 From ee53f5d18009dba3cf69ddb2e2135ae2197c43b2 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 14 Oct 2014 20:58:28 -0500 Subject: r273 tried to fix the blocking bug listed at http://paste.ubuntu.com/8562226/, but in the process introduced a new bug that manifested in RTM. This removes r273 and uses a different fix. --- src/notifier.c | 74 +++++++++++++++++++++++++--------------------------------- 1 file changed, 32 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/notifier.c b/src/notifier.c index b0fce15..4888610 100644 --- a/src/notifier.c +++ b/src/notifier.c @@ -55,8 +55,6 @@ static GParamSpec * properties[LAST_PROP]; static int instance_count = 0; -static gboolean actions_supported = FALSE; - /** *** **/ @@ -77,7 +75,8 @@ typedef struct GDBusConnection * bus; DbusBattery * dbus_battery; /* com.canonical.indicator.power.Battery skeleton */ - guint notify_init_tag; + gboolean caps_queried; + gboolean actions_supported; } IndicatorPowerNotifierPrivate; @@ -184,6 +183,33 @@ on_dismiss_clicked(NotifyNotification * nn G_GNUC_UNUSED, /* no-op; libnotify warns if we have a NULL action callback */ } +static gboolean +are_actions_supported(IndicatorPowerNotifier * self) +{ + priv_t * const p = get_priv(self); + + if (!p->caps_queried) + { + gboolean actions_supported; + GList * caps; + GList * l; + + /* see if actions are supported */ + actions_supported = FALSE; + caps = notify_get_server_caps(); + for (l=caps; l!=NULL && !actions_supported; l=l->next) + if (!g_strcmp0(l->data, "actions")) + actions_supported = TRUE; + + p->actions_supported = actions_supported; + p->caps_queried = TRUE; + + g_list_free_full(caps, g_free); + } + + return p->actions_supported; +} + static void notification_show(IndicatorPowerNotifier * self) { @@ -216,7 +242,7 @@ notification_show(IndicatorPowerNotifier * self) g_strfreev (icon_names); g_free (body); - if (actions_supported) + if (are_actions_supported(self)) { notify_notification_set_hint(nn, "x-canonical-snap-decisions", g_variant_new_string("true")); notify_notification_set_hint(nn, "x-canonical-non-shaped-icon", g_variant_new_string("true")); @@ -334,12 +360,6 @@ my_dispose (GObject * o) IndicatorPowerNotifier * const self = INDICATOR_POWER_NOTIFIER(o); priv_t * const p = get_priv (self); - if (p->notify_init_tag) - { - g_source_remove(p->notify_init_tag); - p->notify_init_tag = 0; - } - indicator_power_notifier_set_bus (self, NULL); notification_clear (self); indicator_power_notifier_set_battery (self, NULL); @@ -362,34 +382,6 @@ my_finalize (GObject * o G_GNUC_UNUSED) **** Instantiation ***/ -static gboolean -notify_init_idle (gpointer gself) -{ - IndicatorPowerNotifier * self = INDICATOR_POWER_NOTIFIER(gself); - - actions_supported = FALSE; - - if (!notify_init("indicator-power-service")) - { - g_critical("Unable to initialize libnotify! Notifications might not be shown."); - } - else - { - GList * caps; - GList * l; - - /* see if actions are supported */ - caps = notify_get_server_caps(); - for (l=caps; l!=NULL && !actions_supported; l=l->next) - if (!g_strcmp0(l->data, "actions")) - actions_supported = TRUE; - - g_list_free_full(caps, g_free); - } - - get_priv(self)->notify_init_tag = 0; - return G_SOURCE_REMOVE; -} static void indicator_power_notifier_init (IndicatorPowerNotifier * self) @@ -402,10 +394,8 @@ indicator_power_notifier_init (IndicatorPowerNotifier * self) p->power_level = POWER_LEVEL_OK; - if (!instance_count++) - { - p->notify_init_tag = g_idle_add (notify_init_idle, self); - } + if (!instance_count++ && !notify_init("indicator-power-service")) + g_critical("Unable to initialize libnotify! Notifications might not be shown."); } static void -- cgit v1.2.3