diff options
Diffstat (limited to 'src/brightness.c')
-rw-r--r-- | src/brightness.c | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/src/brightness.c b/src/brightness.c new file mode 100644 index 0000000..070305e --- /dev/null +++ b/src/brightness.c @@ -0,0 +1,393 @@ +/* + * 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> + +enum +{ + PROP_0, + PROP_PERCENTAGE, + LAST_PROP +}; + +static GParamSpec* properties[LAST_PROP]; + +typedef struct +{ + GDBusConnection * system_bus; + GCancellable * cancellable; + + guint powerd_name_tag; + + double percentage; + + /* powerd brightness params */ + gint powerd_dim; + gint powerd_min; + gint powerd_max; + gint powerd_dflt; + 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); + + switch (property_id) + { + case PROP_PERCENTAGE: + g_value_set_double(value, indicator_power_brightness_get_percentage(self)); + 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); + + switch (property_id) + { + case PROP_PERCENTAGE: + indicator_power_brightness_set_percentage(self, g_value_get_double(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->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 +***/ + +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); + double percentage; + + p->have_powerd_params = TRUE; + g_variant_get(v, "((iiiib))", &p->powerd_dim, + &p->powerd_min, + &p->powerd_max, + &p->powerd_dflt, + &p->powerd_ab_supported); + g_message("powerd brightness settings: dim=%d, min=%d, max=%d, dflt=%d, ab_supported=%d", + p->powerd_dim, + p->powerd_min, + p->powerd_max, + p->powerd_dflt, + (int)p->powerd_ab_supported); + + /* uscreen doesn't have a get_brightness() function, + so the only way to know the value is to initialize it ourselves + (and hope nobody changes it :P */ + percentage = brightness_to_percentage(self, p->powerd_dflt); + indicator_power_brightness_set_percentage(self, percentage); + + /* 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); + + /* get powerd's 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 +***/ + +/* 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); +} + +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_int32(value), + NULL, /* no return args */ + G_DBUS_CALL_FLAGS_NONE, + -1, /* default timeout */ + p->cancellable, + on_set_uscreen_user_brightness_result, + self); +} + + +/*** +**** Instantiation +***/ + +static void +indicator_power_brightness_init (IndicatorPowerBrightness * self) +{ + priv_t * p = get_priv(self); + + p->cancellable = g_cancellable_new(); + + 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.1, /* don't allow completely black */ + 1.0, /* brightest */ + 0.8, + G_PARAM_READWRITE|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) +{ + priv_t * p; + + g_return_if_fail(INDICATOR_IS_POWER_BRIGHTNESS(self)); + + p = get_priv(self); + if ((int)(p->percentage*100) != (int)(percentage*100)) + { + set_uscreen_user_brightness(self, percentage_to_brightness(self, percentage)); + + p->percentage = percentage; + g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_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; +} |