diff options
author | Charles Kerr <charles.kerr@canonical.com> | 2014-09-12 18:49:31 +0000 |
---|---|---|
committer | CI bot <ps-jenkins@lists.canonical.com> | 2014-09-12 18:49:31 +0000 |
commit | 2982ab517ab6a9d9a148e9c3d032a2f5ab9d212b (patch) | |
tree | da10f0ba8affc79a2b654ad5482885c7835b86e9 | |
parent | dd89ffe37091001d94a6198fd30f65668ec4d810 (diff) | |
parent | e5abeb9845281e0c1f3fec5ba343f9bf4becbad5 (diff) | |
download | ayatana-indicator-power-2982ab517ab6a9d9a148e9c3d032a2f5ab9d212b.tar.gz ayatana-indicator-power-2982ab517ab6a9d9a148e9c3d032a2f5ab9d212b.tar.bz2 ayatana-indicator-power-2982ab517ab6a9d9a148e9c3d032a2f5ab9d212b.zip |
Restore the the brightness slider and have the brightness setting persist between reboots. Fixes: 1289470, 1364453
Approved by: Ted Gould, PS Jenkins bot
-rw-r--r-- | src/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/brightness.c | 509 | ||||
-rw-r--r-- | src/brightness.h | 67 | ||||
-rw-r--r-- | src/ib-brightness-control.c | 156 | ||||
-rw-r--r-- | src/ib-brightness-control.h | 33 | ||||
-rw-r--r-- | src/ib-brightness-uscreen-control.c | 202 | ||||
-rw-r--r-- | src/ib-brightness-uscreen-control.h | 43 | ||||
-rw-r--r-- | src/service.c | 193 | ||||
-rw-r--r-- | tests/manual | 100 |
9 files changed, 754 insertions, 552 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9b3d815..f7efb80 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,9 +5,8 @@ add_definitions(-DG_LOG_DOMAIN="Indicator-Power") # handwritten sources set(SERVICE_MANUAL_SOURCES + brightness.c device-provider-upower.c - ib-brightness-control.c - ib-brightness-uscreen-control.c device-provider.c device.c notifier.c diff --git a/src/brightness.c b/src/brightness.c new file mode 100644 index 0000000..5e7c5e5 --- /dev/null +++ b/src/brightness.c @@ -0,0 +1,509 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Charles Kerr <charles.kerr@canonical.com> + */ + +#include "brightness.h" + +#include <gio/gio.h> + +#define SCHEMA_NAME "com.ubuntu.touch.system" +#define KEY_AUTO "auto-brightness" +#define KEY_AUTO_SUPPORTED "auto-brightness-supported" +#define KEY_BRIGHTNESS "brightness" +#define KEY_NEED_DEFAULT "brightness-needs-hardware-default" + +enum +{ + PROP_0, + PROP_PERCENTAGE, + PROP_AUTO, + PROP_AUTO_SUPPORTED, + LAST_PROP +}; + +static GParamSpec* properties[LAST_PROP]; + +typedef struct +{ + GDBusConnection * system_bus; + GCancellable * cancellable; + + GSettings * settings; + + guint powerd_name_tag; + + double percentage; + + /* powerd brightness params */ + gint powerd_dim; + gint powerd_min; + gint powerd_max; + gint powerd_default_value; + gboolean powerd_ab_supported; + gboolean have_powerd_params; +} +IndicatorPowerBrightnessPrivate; + +typedef IndicatorPowerBrightnessPrivate priv_t; + +G_DEFINE_TYPE_WITH_PRIVATE(IndicatorPowerBrightness, + indicator_power_brightness, + G_TYPE_OBJECT) + +#define get_priv(o) ((priv_t*)indicator_power_brightness_get_instance_private(o)) + +/*** +**** GObject virtual functions +***/ + +static void +my_get_property(GObject * o, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + IndicatorPowerBrightness * self = INDICATOR_POWER_BRIGHTNESS(o); + priv_t * p = get_priv(self); + + switch (property_id) + { + case PROP_PERCENTAGE: + g_value_set_double(value, indicator_power_brightness_get_percentage(self)); + break; + + case PROP_AUTO: + g_value_set_boolean(value, p->settings ? g_settings_get_boolean(p->settings, KEY_AUTO) : FALSE); + break; + + case PROP_AUTO_SUPPORTED: + g_value_set_boolean(value, p->powerd_ab_supported); + 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) +{ + IndicatorPowerBrightness * self = INDICATOR_POWER_BRIGHTNESS(o); + priv_t * p = get_priv(self); + + switch (property_id) + { + case PROP_PERCENTAGE: + indicator_power_brightness_set_percentage(self, g_value_get_double(value)); + break; + + case PROP_AUTO: + if (p->settings != NULL) + g_settings_set_boolean (p->settings, KEY_AUTO, g_value_get_boolean(value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(o, property_id, pspec); + } +} + +static void +my_dispose(GObject * o) +{ + IndicatorPowerBrightness * self = INDICATOR_POWER_BRIGHTNESS(o); + priv_t * p = get_priv(self); + + if (p->cancellable != NULL) + { + g_cancellable_cancel(p->cancellable); + g_clear_object(&p->cancellable); + } + + if (p->powerd_name_tag) + { + g_bus_unwatch_name(p->powerd_name_tag); + p->powerd_name_tag = 0; + } + + g_clear_object(&p->settings); + g_clear_object(&p->system_bus); + + G_OBJECT_CLASS(indicator_power_brightness_parent_class)->dispose(o); +} + +/*** +**** Percentage <-> Brightness Int conversion helpers +***/ + +static gdouble +brightness_to_percentage(IndicatorPowerBrightness * self, int brightness) +{ + const priv_t * p; + gdouble percentage; + + p = get_priv(self); + if (p->have_powerd_params) + { + const int lo = p->powerd_min; + const int hi = p->powerd_max; + percentage = (brightness-lo) / (double)(hi-lo); + } + else + { + percentage = 0; + } + + return percentage; +} + +static int +percentage_to_brightness(IndicatorPowerBrightness * self, double percentage) +{ + const priv_t * p; + int brightness; + + p = get_priv(self); + if (p->have_powerd_params) + { + const int lo = p->powerd_min; + const int hi = p->powerd_max; + brightness = (int)(lo + (percentage*(hi-lo))); + } + else + { + brightness = 0; + } + + return brightness; +} + +/** + * DBus Chatter: com.canonical.powerd + * + * This is used to get default value, and upper and lower bounds, + * of the brightness setting + */ + +static void set_brightness_global(IndicatorPowerBrightness*, int); + +static void +on_powerd_brightness_params_ready(GObject * source, + GAsyncResult * res, + gpointer gself) +{ + GError * error; + GVariant * v; + + error = NULL; + v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error); + if (v == NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning("Unable to get system bus: %s", error->message); + + g_error_free(error); + } + else + { + IndicatorPowerBrightness * self = INDICATOR_POWER_BRIGHTNESS(gself); + priv_t * p = get_priv(self); + const gboolean old_ab_supported = p->powerd_ab_supported; + + p->have_powerd_params = TRUE; + g_variant_get(v, "((iiiib))", &p->powerd_dim, + &p->powerd_min, + &p->powerd_max, + &p->powerd_default_value, + &p->powerd_ab_supported); + g_debug("powerd brightness settings: dim=%d, min=%d, max=%d, default=%d, ab_supported=%d", + p->powerd_dim, + p->powerd_min, + p->powerd_max, + p->powerd_default_value, + (int)p->powerd_ab_supported); + + if (old_ab_supported != p->powerd_ab_supported) + g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_AUTO_SUPPORTED]); + + if (p->settings != NULL) + { + if (g_settings_get_boolean(p->settings, KEY_NEED_DEFAULT)) + { + /* user's first session, so init the schema's default + brightness from powerd's hardware-specific params */ + g_debug("%s is true, so initializing brightness to powerd default '%d'", KEY_NEED_DEFAULT, p->powerd_default_value); + set_brightness_global(self, p->powerd_default_value); + g_settings_set_boolean(p->settings, KEY_NEED_DEFAULT, FALSE); + } + else + { + /* not the first time, so restore the previous session's brightness */ + set_brightness_global(self, g_settings_get_int(p->settings, KEY_BRIGHTNESS)); + } + } + + /* cleanup */ + g_variant_unref(v); + } +} + +static void +call_powerd_get_brightness_params(IndicatorPowerBrightness * self) +{ + priv_t * p = get_priv(self); + + g_dbus_connection_call(p->system_bus, + "com.canonical.powerd", + "/com/canonical/powerd", + "com.canonical.powerd", + "getBrightnessParams", + NULL, + G_VARIANT_TYPE("((iiiib))"), + G_DBUS_CALL_FLAGS_NONE, + -1, /* default timeout */ + p->cancellable, + on_powerd_brightness_params_ready, + self); +} + +static void +on_powerd_appeared(GDBusConnection * connection, + const gchar * bus_name G_GNUC_UNUSED, + const gchar * name_owner G_GNUC_UNUSED, + gpointer gself) +{ + IndicatorPowerBrightness * self = INDICATOR_POWER_BRIGHTNESS(gself); + priv_t * p = get_priv(self); + + /* keep a handle to the system bus */ + g_clear_object(&p->system_bus); + p->system_bus = g_object_ref(connection); + + /* update our cache of powerd's brightness params */ + call_powerd_get_brightness_params(self); +} + +static void +on_powerd_vanished(GDBusConnection * connection G_GNUC_UNUSED, + const gchar * bus_name G_GNUC_UNUSED, + gpointer gself) +{ + priv_t * p = get_priv(INDICATOR_POWER_BRIGHTNESS(gself)); + + p->have_powerd_params = FALSE; +} + +/** + * DBus Chatter: com.canonical.Unity.Screen + * + * Used to set the backlight brightness via setUserBrightness + */ + +/* setUserBrightness doesn't return anything, + so this function is just to check for bus error messages */ +static void +on_set_uscreen_user_brightness_result(GObject * system_bus, + GAsyncResult * res, + gpointer gself G_GNUC_UNUSED) +{ + GError * error; + GVariant * v; + + error = NULL; + v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(system_bus), res, &error); + if (error != NULL) + { + if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning("Unable to call uscreen.setBrightness: %s", error->message); + + g_error_free(error); + } + + g_clear_pointer(&v, g_variant_unref); +} + +static void +set_uscreen_user_brightness(IndicatorPowerBrightness * self, + int value) +{ + priv_t * p = get_priv(self); + + g_dbus_connection_call(p->system_bus, + "com.canonical.Unity.Screen", + "/com/canonical/Unity/Screen", + "com.canonical.Unity.Screen", + "setUserBrightness", + g_variant_new("(i)", value), + NULL, /* no return args */ + G_DBUS_CALL_FLAGS_NONE, + -1, /* default timeout */ + p->cancellable, + on_set_uscreen_user_brightness_result, + self); +} + +/*** +**** +***/ + +static void +set_brightness_local(IndicatorPowerBrightness * self, int brightness) +{ + priv_t * p = get_priv(self); + p->percentage = brightness_to_percentage(self, brightness); + g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_PERCENTAGE]); +} + +static void +on_brightness_changed_in_schema(GSettings * settings, + gchar * key, + gpointer gself) +{ + set_brightness_local(INDICATOR_POWER_BRIGHTNESS(gself), + g_settings_get_int(settings, key)); +} + +static void +set_brightness_global(IndicatorPowerBrightness * self, int brightness) +{ + priv_t * p = get_priv(self); + + set_uscreen_user_brightness(self, brightness); + + if (p->settings != NULL) + g_settings_set_int(p->settings, KEY_BRIGHTNESS, brightness); + else + set_brightness_local(self, brightness); +} + +static void +on_auto_changed_in_schema(IndicatorPowerBrightness * self) +{ + g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_AUTO]); +} + + +/*** +**** Instantiation +***/ + +static void +indicator_power_brightness_init(IndicatorPowerBrightness * self) +{ + priv_t * p; + GSettingsSchema * schema; + + p = get_priv(self); + p->cancellable = g_cancellable_new(); + + schema = g_settings_schema_source_lookup(g_settings_schema_source_get_default(), + SCHEMA_NAME, + TRUE); + + /* "brightness" is only spec'ed for the phone profile, + so fail gracefully & silently if we don't have the + schema for it. */ + if (schema != NULL) + { + if (g_settings_schema_has_key(schema, KEY_BRIGHTNESS)) + { + p->settings = g_settings_new(SCHEMA_NAME); + g_signal_connect(p->settings, "changed::" KEY_BRIGHTNESS, + G_CALLBACK(on_brightness_changed_in_schema), self); + g_signal_connect_swapped(p->settings, "changed::" KEY_AUTO, + G_CALLBACK(on_auto_changed_in_schema), self); + } + g_settings_schema_unref(schema); + } + + p->powerd_name_tag = g_bus_watch_name(G_BUS_TYPE_SYSTEM, + "com.canonical.powerd", + G_BUS_NAME_WATCHER_FLAGS_NONE, + on_powerd_appeared, + on_powerd_vanished, + self, + NULL); +} + +static void +indicator_power_brightness_class_init(IndicatorPowerBrightnessClass * klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS(klass); + + object_class->dispose = my_dispose; + object_class->get_property = my_get_property; + object_class->set_property = my_set_property; + + properties[PROP_0] = NULL; + + properties[PROP_PERCENTAGE] = g_param_spec_double( + "percentage", + "Percentage", + "Brightness percentage", + 0.0, /* minimum */ + 1.0, /* maximum */ + 0.8, + G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS); + + properties[PROP_AUTO] = g_param_spec_boolean( + "auto-brightness", + "Auto-Brightness", + "Automatically adjust brightness level", + FALSE, + G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS); + + properties[PROP_AUTO_SUPPORTED] = g_param_spec_boolean( + "auto-brightness-supported", + "Auto-Brightness Supported", + "True if the device can automatically adjust brightness", + FALSE, + G_PARAM_READABLE|G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, LAST_PROP, properties); +} + +/*** +**** Public API +***/ + +IndicatorPowerBrightness * +indicator_power_brightness_new(void) +{ + gpointer o = g_object_new(INDICATOR_TYPE_POWER_BRIGHTNESS, NULL); + + return INDICATOR_POWER_BRIGHTNESS(o); +} + +void +indicator_power_brightness_set_percentage(IndicatorPowerBrightness * self, + double percentage) +{ + g_return_if_fail(INDICATOR_IS_POWER_BRIGHTNESS(self)); + + set_brightness_global(self, percentage_to_brightness(self, percentage)); +} + +double +indicator_power_brightness_get_percentage(IndicatorPowerBrightness * self) +{ + g_return_val_if_fail(INDICATOR_IS_POWER_BRIGHTNESS(self), 0.0); + + return get_priv(self)->percentage; +} diff --git a/src/brightness.h b/src/brightness.h new file mode 100644 index 0000000..d2fcc61 --- /dev/null +++ b/src/brightness.h @@ -0,0 +1,67 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Charles Kerr <charles.kerr@canonical.com> + */ + +#ifndef INDICATOR_POWER_BRIGHTNESS__H +#define INDICATOR_POWER_BRIGHTNESS__H + +#include <glib.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +/* standard GObject macros */ +#define INDICATOR_POWER_BRIGHTNESS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), INDICATOR_TYPE_POWER_BRIGHTNESS, IndicatorPowerBrightness)) +#define INDICATOR_TYPE_POWER_BRIGHTNESS (indicator_power_brightness_get_type()) +#define INDICATOR_IS_POWER_BRIGHTNESS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), INDICATOR_TYPE_POWER_BRIGHTNESS)) + +typedef struct _IndicatorPowerBrightness IndicatorPowerBrightness; +typedef struct _IndicatorPowerBrightnessClass IndicatorPowerBrightnessClass; + +/* property keys */ +#define INDICATOR_POWER_BRIGHTNESS_PROP_PERCENTAGE "percentage" + +/** + * The Indicator Power Brightness. + */ +struct _IndicatorPowerBrightness +{ + /*< private >*/ + GObject parent; +}; + +struct _IndicatorPowerBrightnessClass +{ + GObjectClass parent_class; +}; + +/*** +**** +***/ + +GType indicator_power_brightness_get_type(void); + +IndicatorPowerBrightness * indicator_power_brightness_new(void); + +void indicator_power_brightness_set_percentage(IndicatorPowerBrightness * self, double percentage); + +double indicator_power_brightness_get_percentage(IndicatorPowerBrightness * self); + +G_END_DECLS + +#endif /* INDICATOR_POWER_BRIGHTNESS__H */ diff --git a/src/ib-brightness-control.c b/src/ib-brightness-control.c deleted file mode 100644 index 67da10c..0000000 --- a/src/ib-brightness-control.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2012 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 <http://www.gnu.org/licenses/>. - * - * Authors: - * Renato Araujo Oliveira Filho <renato@canonical.com> - */ - -#include <gudev/gudev.h> - -#include <errno.h> -#include <stdlib.h> -#include <fcntl.h> -#include <string.h> - -#include "ib-brightness-control.h" - -struct _IbBrightnessControl -{ - gchar *path; -}; - -IbBrightnessControl* -ib_brightness_control_new (void) -{ - IbBrightnessControl *control; - GUdevClient *client; - gchar *path = NULL; - GList *devices; - - // detect device - client = g_udev_client_new (NULL); - devices = g_udev_client_query_by_subsystem (client, "backlight"); - if (devices != NULL) { - GList *device; - const gchar *device_type; - - for (device = devices; device != NULL; device = device->next) { - device_type = g_udev_device_get_sysfs_attr (device->data, "type"); - if ((g_strcmp0 (device_type, "firmware") == 0) || - (g_strcmp0 (device_type, "platform") == 0) || - (g_strcmp0 (device_type, "raw") == 0)) { - path = g_strdup (g_udev_device_get_sysfs_path (device->data)); - g_debug ("found: %s", path); - break; - } - } - - g_list_free_full (devices, g_object_unref); - } - else { - g_warning ("Fail to query backlight devices."); - } - - control = g_new0 (IbBrightnessControl, 1); - control->path = path; - - g_object_unref (client); - return control; -} - -void -ib_brightness_control_set_value (IbBrightnessControl* self, gint value) -{ - gint fd; - gchar *filename; - gchar *svalue; - size_t length; - gint err; - - if (self->path == NULL) - return; - - filename = g_build_filename (self->path, "brightness", NULL); - fd = open(filename, O_WRONLY); - if (fd < 0) { - g_warning ("Fail to set brightness."); - g_free (filename); - return; - } - - svalue = g_strdup_printf ("%i", value); - length = strlen (svalue); - - err = errno; - errno = 0; - if (write (fd, svalue, length) != (ssize_t)length) { - g_warning ("Fail to write brightness information: %s", g_strerror(errno)); - } - errno = err; - - close (fd); - g_free (svalue); - g_free (filename); -} - -static gint -ib_brightness_control_get_value_from_file (IbBrightnessControl *self, const gchar *file) -{ - GError *error; - gchar *svalue; - gint value; - gchar *filename; - - if (self->path == NULL) - return 0; - - svalue = NULL; - error = NULL; - filename = g_build_filename (self->path, file, NULL); - g_file_get_contents (filename, &svalue, NULL, &error); - if (error) { - g_warning ("Fail to get brightness value: %s", error->message); - value = -1; - g_error_free (error); - } else { - value = atoi (svalue); - g_free (svalue); - } - - g_free (filename); - - return value; - -} - -gint -ib_brightness_control_get_value (IbBrightnessControl* self) -{ - return ib_brightness_control_get_value_from_file (self, "brightness"); -} - -gint -ib_brightness_control_get_max_value (IbBrightnessControl* self) -{ - return ib_brightness_control_get_value_from_file (self, "max_brightness"); -} - -void -ib_brightness_control_free (IbBrightnessControl *self) -{ - g_free (self->path); - g_free (self); -} - diff --git a/src/ib-brightness-control.h b/src/ib-brightness-control.h deleted file mode 100644 index 87711e4..0000000 --- a/src/ib-brightness-control.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2012 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 <http://www.gnu.org/licenses/>. - * - * Authors: - * Renato Araujo Oliveira Filho <renato@canonical.com> - */ - -#ifndef __IB_BRIGHTNESS_CONTROL_H__ -#define __IB_BRIGHTNESS_CONTROL_H__ - -#include <gio/gio.h> - -typedef struct _IbBrightnessControl IbBrightnessControl; - -IbBrightnessControl* ib_brightness_control_new (void); -void ib_brightness_control_set_value (IbBrightnessControl* self, gint value); -gint ib_brightness_control_get_value (IbBrightnessControl* self); -gint ib_brightness_control_get_max_value (IbBrightnessControl* self); -void ib_brightness_control_free (IbBrightnessControl *self); - -#endif diff --git a/src/ib-brightness-uscreen-control.c b/src/ib-brightness-uscreen-control.c deleted file mode 100644 index ad2c155..0000000 --- a/src/ib-brightness-uscreen-control.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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 <http://www.gnu.org/licenses/>. - * - * Authors: - * Yuan-Chen Cheng <yc.cheng@canonical.com> - */ - -#include "ib-brightness-uscreen-control.h" - -static gboolean getBrightnessParams(GDBusProxy* powerd_proxy, int *dim, int *min, - int *max, int *dflt, gboolean *ab_supported); - -GDBusProxy* -uscreen_get_proxy(brightness_params_t *params) -{ - GError *error = NULL; - gboolean ret; - - g_return_val_if_fail (params != NULL, NULL); - - /* For now we still need to obtain the brigthness params from powerd */ - GDBusProxy* powerd_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - "com.canonical.powerd", - "/com/canonical/powerd", - "com.canonical.powerd", - NULL, - &error); - - if (error != NULL) - { - g_debug ("could not connect to powerd: %s", error->message); - g_error_free (error); - return NULL; - } - - ret = getBrightnessParams(powerd_proxy, &(params->dim), &(params->min), - &(params->max), &(params->dflt), &(params->ab_supported)); - - if (! ret) - { - g_debug ("can't get brightness parameters from powerd"); - g_object_unref (powerd_proxy); - return NULL; - } - - g_clear_object (&powerd_proxy); - - GDBusProxy* uscreen_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - "com.canonical.Unity.Screen", - "/com/canonical/Unity/Screen", - "com.canonical.Unity.Screen", - NULL, - &error); - - if (error != NULL) - { - g_debug ("could not connect to unity screen: %s", error->message); - g_error_free (error); - return NULL; - } - - return uscreen_proxy; -} - - -static gboolean -getBrightnessParams(GDBusProxy* powerd_proxy, int *dim, int *min, int *max, int *dflt, gboolean *ab_supported) -{ - GVariant *ret = NULL; - GError *error = NULL; - - ret = g_dbus_proxy_call_sync(powerd_proxy, - "getBrightnessParams", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 400, NULL, &error); // timeout: 400 ms - if (!ret) - { - if (error != NULL) - { - if (!g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) - { - g_warning("getBrightnessParams from powerd failed: %s", error->message); - } - g_error_free(error); - } - return FALSE; - } - - g_variant_get(ret, "((iiiib))", dim, min, max, dflt, ab_supported); - g_variant_unref(ret); - return TRUE; -} - -static gboolean setUserBrightness(GDBusProxy* uscreen_proxy, GCancellable *gcancel, int brightness) -{ - GVariant *ret = NULL; - GError *error = NULL; - - ret = g_dbus_proxy_call_sync(uscreen_proxy, - "setUserBrightness", - g_variant_new("(i)", brightness), - G_DBUS_CALL_FLAGS_NONE, - -1, gcancel, &error); - if (!ret) { - g_warning("setUserBrightness via unity.screen failed: %s", error->message); - g_error_free(error); - return FALSE; - } else { - g_variant_unref(ret); - return TRUE; - } -} - -struct _IbBrightnessUScreenControl -{ - GDBusProxy *uscreen_proxy; - GCancellable *gcancel; - - int dim; - int min; - int max; - int dflt; // defalut value - gboolean ab_supported; - - int current; -}; - -IbBrightnessUscreenControl* -ib_brightness_uscreen_control_new (GDBusProxy* uscreen_proxy, brightness_params_t params) -{ - IbBrightnessUscreenControl *control; - - control = g_new0 (IbBrightnessUscreenControl, 1); - control->uscreen_proxy = uscreen_proxy; - control->gcancel = g_cancellable_new(); - - control->dim = params.dim; - control->min = params.min; - control->max = params.max; - control->dflt = params.dflt; - control->ab_supported = params.ab_supported; - - // XXX: set the brightness value is the only way to sync the brightness value with - // unity.screen, and we should set the user prefered / last set brightness value upon startup. - // Before we have code to store last set brightness value or other mechanism, we set - // it to default brightness that powerd proposed. - ib_brightness_uscreen_control_set_value(control, control->dflt); - - return control; -} - -void -ib_brightness_uscreen_control_set_value (IbBrightnessUscreenControl* self, gint value) -{ - gboolean ret; - - value = CLAMP(value, self->min, self->max); - ret = setUserBrightness(self->uscreen_proxy, self->gcancel, value); - if (ret) - { - self->current = value; - } -} - -gint -ib_brightness_uscreen_control_get_value (IbBrightnessUscreenControl* self) -{ - return self->current; -} - -gint -ib_brightness_uscreen_control_get_max_value (IbBrightnessUscreenControl* self) -{ - return self->max; -} - -void -ib_brightness_uscreen_control_free (IbBrightnessUscreenControl *self) -{ - g_cancellable_cancel (self->gcancel); - g_object_unref (self->gcancel); - g_object_unref (self->uscreen_proxy); - g_free (self); -} - diff --git a/src/ib-brightness-uscreen-control.h b/src/ib-brightness-uscreen-control.h deleted file mode 100644 index 3d026a9..0000000 --- a/src/ib-brightness-uscreen-control.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 <http://www.gnu.org/licenses/>. - * - * Authors: - * Y.C Cheng <yc.cheng@canonical.com> - */ - -#ifndef __IB_BRIGHTNESS_USCREEN_CONTROL_H__ -#define __IB_BRIGHTNESS_USCREEN_CONTROL_H__ - -#include <gio/gio.h> - -typedef struct { - int dim; - int min; - int max; - int dflt; - gboolean ab_supported; -} brightness_params_t; - -GDBusProxy* uscreen_get_proxy(brightness_params_t *); - -typedef struct _IbBrightnessUScreenControl IbBrightnessUscreenControl; - -IbBrightnessUscreenControl* ib_brightness_uscreen_control_new (GDBusProxy* uscreen_proxy, brightness_params_t params); -void ib_brightness_uscreen_control_set_value (IbBrightnessUscreenControl* self, gint value); -gint ib_brightness_uscreen_control_get_value (IbBrightnessUscreenControl* self); -gint ib_brightness_uscreen_control_get_max_value (IbBrightnessUscreenControl* self); -void ib_brightness_uscreen_control_free (IbBrightnessUscreenControl *self); - -#endif diff --git a/src/service.c b/src/service.c index 0cd448b..665151c 100644 --- a/src/service.c +++ b/src/service.c @@ -22,12 +22,11 @@ #include <gio/gio.h> #include <url-dispatcher.h> +#include "brightness.h" #include "dbus-shared.h" #include "device.h" #include "device-provider.h" #include "notifier.h" -#include "ib-brightness-control.h" -#include "ib-brightness-uscreen-control.h" #include "service.h" #define BUS_NAME "com.canonical.indicator.power" @@ -104,8 +103,7 @@ struct _IndicatorPowerServicePrivate GSettings * settings; - IbBrightnessControl * brightness_control; - IbBrightnessUscreenControl * brightness_uscreen_control; + IndicatorPowerBrightness * brightness; guint own_id; guint actions_export_id; @@ -459,53 +457,26 @@ create_phone_devices_section (IndicatorPowerService * self G_GNUC_UNUSED) **** ***/ -static void -get_brightness_range (IndicatorPowerService * self, gint * low, gint * high) +static GMenuItem * +create_brightness_menu_item(void) { - priv_t * p = self->priv; - int max = 0; - if (p->brightness_control) - { - max = ib_brightness_control_get_max_value (self->priv->brightness_control); - } - else if (p->brightness_uscreen_control) - { - max = ib_brightness_uscreen_control_get_max_value (self->priv->brightness_uscreen_control); - } - *low = (gint)(max * 0.05); /* 5% minimum -- don't let the screen go completely dark */ - *high = max; -} + GMenuItem * item; -static gdouble -brightness_to_percentage (IndicatorPowerService * self, int brightness) -{ - int lo, hi; - get_brightness_range (self, &lo, &hi); - return (brightness-lo) / (double)(hi-lo); -} + item = g_menu_item_new(NULL, "indicator.brightness"); + g_menu_item_set_attribute(item, "x-canonical-type", "s", "com.canonical.unity.slider"); + g_menu_item_set_attribute(item, "min-value", "d", 0.0); + g_menu_item_set_attribute(item, "max-value", "d", 1.0); + g_menu_item_set_attribute(item, "min-icon", "s", "torch-off" ); + g_menu_item_set_attribute(item, "max-icon", "s", "torch-on" ); -static int -percentage_to_brightness (IndicatorPowerService * self, double percentage) -{ - int lo, hi; - get_brightness_range (self, &lo, &hi); - return (int)(lo + (percentage*(hi-lo))); + return item; } static GVariant * action_state_for_brightness (IndicatorPowerService * self) { - priv_t * p = self->priv; - gint brightness = 0; - if (p->brightness_control) - { - brightness = ib_brightness_control_get_value (p->brightness_control); - } - else if (p->brightness_uscreen_control) - { - brightness = ib_brightness_uscreen_control_get_value (p->brightness_uscreen_control); - } - return g_variant_new_double (brightness_to_percentage (self, brightness)); + IndicatorPowerBrightness * b = self->priv->brightness; + return g_variant_new_double(indicator_power_brightness_get_percentage(b)); } static void @@ -521,19 +492,9 @@ on_brightness_change_requested (GSimpleAction * action G_GNUC_UNUSED, gpointer gself) { IndicatorPowerService * self = INDICATOR_POWER_SERVICE (gself); - const gdouble percentage = g_variant_get_double (parameter); - const int brightness = percentage_to_brightness (self, percentage); - if (self->priv->brightness_control) - { - ib_brightness_control_set_value (self->priv->brightness_control, brightness); - } - else if (self->priv->brightness_uscreen_control) - { - ib_brightness_uscreen_control_set_value (self->priv->brightness_uscreen_control, brightness); - } - - update_brightness_action_state (self); + indicator_power_brightness_set_percentage(self->priv->brightness, + g_variant_get_double (parameter)); } static GMenuModel * @@ -557,15 +518,34 @@ create_desktop_settings_section (IndicatorPowerService * self G_GNUC_UNUSED) } static GMenuModel * -create_phone_settings_section (IndicatorPowerService * self) +create_phone_settings_section(IndicatorPowerService * self) { GMenu * section; + GMenuItem * item; + gboolean ab_supported; + + section = g_menu_new(); + + item = create_brightness_menu_item(); + g_menu_append_item(section, item); + update_brightness_action_state(self); + g_object_unref(item); + + g_object_get(self->priv->brightness, + "auto-brightness-supported", &ab_supported, + NULL); + + if (ab_supported) + { + item = g_menu_item_new(_("Adjust brightness automatically"), "indicator.auto-brightness"); + g_menu_item_set_attribute(item, "x-canonical-type", "s", "com.canonical.indicator.switch"); + g_menu_append_item(section, item); + g_object_unref(item); + } - section = g_menu_new (); - update_brightness_action_state (self); - g_menu_append (section, _("Battery settings…"), "indicator.activate-phone-settings"); + g_menu_append(section, _("Battery settings…"), "indicator.activate-phone-settings"); - return G_MENU_MODEL (section); + return G_MENU_MODEL(section); } /*** @@ -612,7 +592,7 @@ rebuild_now (IndicatorPowerService * self, guint sections) if (sections & SECTION_SETTINGS) { rebuild_section (desktop->submenu, 1, create_desktop_settings_section (self)); - rebuild_section (phone->submenu, 1, create_desktop_settings_section (self)); + rebuild_section (phone->submenu, 1, create_phone_settings_section (self)); } } @@ -752,6 +732,28 @@ on_phone_settings_activated (GSimpleAction * a G_GNUC_UNUSED, **** ***/ +static gboolean +convert_auto_prop_to_state(GBinding * binding G_GNUC_UNUSED, + const GValue * from_value, + GValue * to_value, + gpointer user_data G_GNUC_UNUSED) +{ + const gboolean b = g_value_get_boolean(from_value); + g_value_set_variant(to_value, g_variant_new_boolean(b)); + return TRUE; +} + +static gboolean +convert_auto_state_to_prop(GBinding * binding G_GNUC_UNUSED, + const GValue * from_value, + GValue * to_value, + gpointer user_data G_GNUC_UNUSED) +{ + GVariant * v = g_value_get_variant(from_value); + g_value_set_boolean(to_value, g_variant_get_boolean(v)); + return TRUE; +} + static void init_gactions (IndicatorPowerService * self) { @@ -784,6 +786,16 @@ init_gactions (IndicatorPowerService * self) g_action_map_add_action (G_ACTION_MAP(p->actions), G_ACTION(a)); p->battery_level_action = a; + /* add the auto-brightness action */ + a = g_simple_action_new_stateful("auto-brightness", NULL, g_variant_new_boolean(FALSE)); + g_object_bind_property_full(p->brightness, "auto-brightness", + a, "state", + G_BINDING_SYNC_CREATE|G_BINDING_BIDIRECTIONAL, + convert_auto_prop_to_state, + convert_auto_state_to_prop, + NULL, NULL); + g_action_map_add_action(G_ACTION_MAP(p->actions), G_ACTION(a)); + /* add the brightness action */ a = g_simple_action_new_stateful ("brightness", NULL, action_state_for_brightness (self)); g_action_map_add_action (G_ACTION_MAP(p->actions), G_ACTION(a)); @@ -848,9 +860,6 @@ on_bus_acquired (GDBusConnection * connection, g_string_printf (path, "%s/%s", BUS_PATH, menu_names[i]); - if (menu->menu == NULL) - create_menu (self, i); - if ((id = g_dbus_connection_export_menu_model (connection, path->str, G_MENU_MODEL (menu->menu), @@ -942,6 +951,12 @@ on_devices_changed (IndicatorPowerService * self) rebuild_now (self, SECTION_HEADER | SECTION_DEVICES); } +static void +on_auto_brightness_supported_changed(IndicatorPowerService * self) +{ + rebuild_now(self, SECTION_SETTINGS); +} + /*** **** GObject virtual functions @@ -1015,16 +1030,13 @@ my_dispose (GObject * o) g_clear_object (&p->notifier); g_clear_object (&p->brightness_action); + g_clear_object (&p->brightness); g_clear_object (&p->battery_level_action); g_clear_object (&p->header_action); g_clear_object (&p->actions); g_clear_object (&p->conn); - // g_clear_pointer has NULL check inside. - g_clear_pointer (&p->brightness_control, ib_brightness_control_free); - g_clear_pointer (&p->brightness_uscreen_control, ib_brightness_uscreen_control_free); - indicator_power_service_set_device_provider (self, NULL); G_OBJECT_CLASS (indicator_power_service_parent_class)->dispose (o); @@ -1037,11 +1049,12 @@ my_dispose (GObject * o) static void indicator_power_service_init (IndicatorPowerService * self) { - GDBusProxy *uscreen_proxy; - brightness_params_t brightness_params; - priv_t * p = G_TYPE_INSTANCE_GET_PRIVATE (self, - INDICATOR_TYPE_POWER_SERVICE, - IndicatorPowerServicePrivate); + priv_t * p; + int i; + + p = G_TYPE_INSTANCE_GET_PRIVATE (self, + INDICATOR_TYPE_POWER_SERVICE, + IndicatorPowerServicePrivate); self->priv = p; p->cancellable = g_cancellable_new (); @@ -1050,28 +1063,28 @@ indicator_power_service_init (IndicatorPowerService * self) p->notifier = indicator_power_notifier_new (); - uscreen_proxy = uscreen_get_proxy(&brightness_params); - if (uscreen_proxy != NULL) - { - p->brightness_uscreen_control = ib_brightness_uscreen_control_new(uscreen_proxy, brightness_params); - } - else - { - p->brightness_control = ib_brightness_control_new (); - } + p->brightness = indicator_power_brightness_new(); + g_signal_connect_swapped(p->brightness, "notify::percentage", + G_CALLBACK(update_brightness_action_state), self); init_gactions (self); g_signal_connect_swapped (p->settings, "changed", G_CALLBACK(rebuild_header_now), self); - p->own_id = g_bus_own_name (G_BUS_TYPE_SESSION, - BUS_NAME, - G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, - on_bus_acquired, - NULL, - on_name_lost, - self, - NULL); + for (i=0; i<N_PROFILES; ++i) + create_menu(self, i); + + g_signal_connect_swapped(p->brightness, "notify::auto-brightness-supported", + G_CALLBACK(on_auto_brightness_supported_changed), self); + + p->own_id = g_bus_own_name(G_BUS_TYPE_SESSION, + BUS_NAME, + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, + on_bus_acquired, + NULL, + on_name_lost, + self, + NULL); } static void diff --git a/tests/manual b/tests/manual index a542cac..1ec1524 100644 --- a/tests/manual +++ b/tests/manual @@ -1,41 +1,89 @@ +Notes on Battery Testing + +When building from source, an executable 'indicator-power-service-cmdline-battery' will be built in the tests/ directory. This has the same code as indicator-power-service, except instead of listening to UPower it has a single fake battery that can be set from the command line to set its charge level and whether it's charging or discharging. + +You'll need to stop the current indicator-power-service before starting the test one. After that, you enter in a number, or 'charging', or 'discharging', to set the fake battery. ctrl-c exits. + +Example: + +$ stop indicator-power # stop the real indicator-power service +$ build/tests/indicator-power-service-cmdline-battery # start the test service +50 # sets the fake battery level to 50% +30 # sets the fake battery level to 30% +charging # sets the fake battery to charging +discharging # sets the fake battery to discharging +ctrl-c # exits the test service +$ start indicator-power # restart the real service + + + Test-case indicator-power/unity7-items-check <dl> - <dt>Log in to a Unity 7 user session</dt> - <dt>Go to the panel and click on the Power indicator</dt> - <dd>Ensure there are items in the menu</dd> + <dt>Log in to a Unity 7 user session</dt> + <dt>Go to the panel and click on the Power indicator</dt> + <dd>Ensure there are items in the menu</dd> </dl> Test-case indicator-power/unity7-greeter-items-check <dl> - <dt>Start a system and wait for the greeter or logout of the current user session</dt> - <dt>Go to the panel and click on the Power indicator</dt> - <dd>Ensure there are items in the menu</dd> + <dt>Start a system and wait for the greeter or logout of the current user session</dt> + <dt>Go to the panel and click on the Power indicator</dt> + <dd>Ensure there are items in the menu</dd> </dl> Test-case indicator-power/unity8-items-check <dl> - <dt>Login to a user session running Unity 8</dt> - <dt>Pull down the top panel until it sticks open</dt> - <dt>Navigate through the tabs until "Battery" is shown</dt> - <dd>Battery is at the top of the menu</dd> - <dd>The menu is populated with items</dd> + <dt>Login to a user session running Unity 8</dt> + <dt>Pull down the top panel until it sticks open</dt> + <dt>Navigate through the tabs until "Battery" is shown</dt> + <dd>Battery is at the top of the menu</dd> + <dd>The menu is populated with items</dd> +</dl> + +Test-case indicator-power/detect-charging-or-discharging +<dl> + <dt>Begin with a discharging device</dt> + <dd>The indicator's icon should denote a discharging battery; e.g. an icon without the '⚡' sign</dd> + <dt>Plug it in so that its battery is charging</dt> + <dd>The indicator's icon should change to show a charging battery</dd> + <dt>Unplug it again</dt> + <dd>The indicator's icon should revert back to the same one in step one</dd> +</dl> + +Test-case indicator-power/low-power-notifications +<dl> + <dt>Wait for the system's battery level to drop to 10% (or fake it, see 'Notes on Battery Testing' above)</dt> + <dd>A notification should appear</dd> + <dd>Its title should read "Battery Low"</dd> + <dd>Its text should read "10% charge remaining"</dd> + <dd>The icon should be a low power icon</dd> + <dd>It should have two actions, "Battery settings" and "OK". </dd> + <dt>Tap OK to dismiss the popup</dt> + <dt>Wait (or fake) the battery level to drop to 9%</dt> + <dd>No new notification should appear -- we're still at the "Low" level </dd> + <dt>Wait (or fake) the battery level to drop to 4%</dt> + <dd>A notification should appear</dd> + <dd>Its title should read "Battery Critical"</dd> + <dd>Its text should read "4% charge remaining"</dd> + <dd>The icon should be a critical power icon</dd> + <dd>It should have two actions, "Battery settings" and "OK". </dd> + <dt>Tap 'Battery Settings'</dt> + <dd>ubuntu-system-settings should be launched to the Battery page </dd> </dl> -Test-case indicator-power/low-battery-popups +Test-case indicator-power/device-brightness-slider <dl> - <dt>Open a terminal</dt> - <dt>Stop the currently-running power indicator: "stop indicator-power"</dt> - <dt>Start the fake battery harness in the tests/build/ directory: "indicator-power-service-cmdline-battery"</dt> - <dd>Battery indicator should update, showing a discharging battery with a 50% charge</dd> - <dt>Type: "10" (no quotes) and press Enter</dt> - <dd>A popup should appear saying 'Battery low - 10% charge remaining'</dd> - <dd>Battery indicator's icon should show a low charge</dd> - <dd>Battery indicator's "Charge level" menuitem should show a 10% charge</dd> - <dt>Type: "9" (no quotes) and press Enter</dt> - <dd>The 'Battery low' popup should NOT appear, since we've already been notified</dd> - <dd>Battery indicator's "Charge level" menuitem should show a 9% charge</dd> - <dt>Type: "5" (no quotes) and press Enter</dt> - <dd>No 'Battery low' popup SHOULD appear, since 5% is the next warning threshold</dd> - <dd>Battery indicator's "Charge level" menuitem should show a 5% charge</dd> + <dt>On a device, pull down the power indicator's menu</dt> + <dd>The menu should include a brightness slider with icons</dd> + <dt>Slide the brightness slider back and forth</dt> + <dd>The screen should get brighter and darker in sync with the slider's position</dd> + <dt>Launch unity-system-settings' Brightness panel</dt> + <dt>Move both the indicator's and the settings panel's sliders</dt> + <dd>Both sliders' positions should stay in sync with each other</dd> + <dd>Both should have the same effect on the screen's brightness</dd> + <dt>Make a note of the current brightness level and slider position</dt> + <dt>Reboot the device</dt> + <dd>The screen brightness should be the same as it was before rebooting</dd> + <dd>The indicator's brightness slider should be in the same position as it was before rebooting</dd> </dl> |