/*
* 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 "brightness.h"
#include
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;
}