Commit afd1ec17 authored by Richard Hughes's avatar Richard Hughes

Add support for ambient light devices supported by iio-sensor-proxy

Resolves: https://bugzilla.gnome.org/show_bug.cgi?id=745181
parent 59c6544e
......@@ -61,5 +61,10 @@
<summary>Power button action</summary>
<description>The action to take when the system power button is pressed.</description>
</key>
<key name="ambient-enabled" type="b">
<default>true</default>
<summary>Enable the ALS sensor</summary>
<description>If the ambient light sensor functionality is enabled.</description>
</key>
</schema>
</schemalist>
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
* Copyright (C) 2011-2012 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2011-2012, 2015 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2011 Ritesh Khadgaray <khadgaray@gmail.com>
* Copyright (C) 2012-2013 Red Hat Inc.
*
......@@ -77,6 +77,11 @@
/* And the time before we stop the warning sound */
#define GSD_STOP_SOUND_DELAY GSD_ACTION_DELAY - 2
/* the amount of smoothing done to the the ambient light readings; a lower
* number means the backlight changes slower in response to changing ambient
* conditions, a hugher number may lead to noticable jitteryness */
#define GSD_AMBIENT_SMOOTH 0.3f
static const gchar introspection_xml[] =
"<node>"
" <interface name='org.gnome.SettingsDaemon.Power.Screen'>"
......@@ -157,6 +162,15 @@ struct GsdPowerManagerPrivate
gint kbd_brightness_old;
gint kbd_brightness_pre_dim;
/* Ambient */
GDBusProxy *iio_proxy;
guint iio_proxy_watch_id;
gboolean ambient_norm_required;
gdouble ambient_accumulator;
gdouble ambient_norm_value;
gdouble ambient_percentage_old;
gdouble ambient_last_absolute;
/* Sound */
guint32 critical_alert_timeout_id;
......@@ -974,12 +988,34 @@ screen_devices_enable (GsdPowerManager *manager)
g_hash_table_remove_all (manager->priv->disabled_devices);
}
static void
iio_proxy_claim_light (GsdPowerManager *manager, gboolean active)
{
GError *error = NULL;
if (manager->priv->iio_proxy == NULL)
return;
if (!manager->priv->backlight_available)
return;
if (!g_dbus_proxy_call_sync (manager->priv->iio_proxy,
active ? "ClaimLight" : "ReleaseLight",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error)) {
g_warning ("Call to ii-proxy failed: %s", error->message);
g_error_free (error);
}
}
static void
backlight_enable (GsdPowerManager *manager)
{
gboolean ret;
GError *error = NULL;
iio_proxy_claim_light (manager, TRUE);
ret = gnome_rr_screen_set_dpms_mode (manager->priv->rr_screen,
GNOME_RR_DPMS_ON,
&error);
......@@ -1000,6 +1036,7 @@ backlight_disable (GsdPowerManager *manager)
gboolean ret;
GError *error = NULL;
iio_proxy_claim_light (manager, FALSE);
ret = gnome_rr_screen_set_dpms_mode (manager->priv->rr_screen,
GNOME_RR_DPMS_OFF,
&error);
......@@ -1855,6 +1892,10 @@ gsd_power_manager_finalize (GObject *object)
if (manager->priv->name_id != 0)
g_bus_unown_name (manager->priv->name_id);
if (manager->priv->iio_proxy_watch_id != 0)
g_bus_unwatch_name (manager->priv->iio_proxy_watch_id);
manager->priv->iio_proxy_watch_id = 0;
G_OBJECT_CLASS (gsd_power_manager_parent_class)->finalize (object);
}
......@@ -2078,6 +2119,19 @@ idle_became_active_cb (GnomeIdleMonitor *monitor,
idle_set_mode (manager, GSD_POWER_IDLE_MODE_NORMAL);
}
static void
ch_backlight_renormalize (GsdPowerManager *manager)
{
if (manager->priv->ambient_percentage_old < 0)
return;
if (manager->priv->ambient_last_absolute < 0)
return;
manager->priv->ambient_norm_value = manager->priv->ambient_last_absolute /
(gdouble) manager->priv->ambient_percentage_old;
manager->priv->ambient_norm_value *= 100.f;
manager->priv->ambient_norm_required = FALSE;
}
static void
engine_settings_key_changed_cb (GSettings *settings,
const gchar *key,
......@@ -2420,15 +2474,110 @@ on_rr_screen_acquired (GObject *object,
/* queue a signal in case the proxy from gnome-shell was created before we got here
(likely, considering that to get here we need a reply from gnome-shell)
*/
if (manager->priv->backlight_available)
if (manager->priv->backlight_available) {
manager->priv->ambient_percentage_old = backlight_get_percentage (manager->priv->rr_screen, NULL);
backlight_iface_emit_changed (manager, GSD_POWER_DBUS_INTERFACE_SCREEN,
backlight_get_percentage (manager->priv->rr_screen, NULL));
else
manager->priv->ambient_percentage_old);
} else {
backlight_iface_emit_changed (manager, GSD_POWER_DBUS_INTERFACE_SCREEN, -1);
}
gnome_settings_profile_end (NULL);
}
static void
iio_proxy_changed_cb (GDBusProxy *proxy,
GVariant *changed_properties,
GStrv invalidated_properties,
gpointer user_data)
{
GsdPowerManager *manager = (GsdPowerManager *) user_data;
GError *error = NULL;
GVariant *val_has = NULL;
GVariant *val_als = NULL;
gdouble brightness;
gint pc;
/* no display hardware */
if (!manager->priv->backlight_available)
return;
/* disabled */
if (!g_settings_get_boolean (manager->priv->settings, "ambient-enabled"))
return;
/* get latest results, which do not have to be Lux */
val_has = g_dbus_proxy_get_cached_property (proxy, "HasAmbientLight");
if (val_has == NULL || !g_variant_get_boolean (val_has))
goto out;
val_als = g_dbus_proxy_get_cached_property (proxy, "LightLevel");
if (val_als == NULL)
goto out;
manager->priv->ambient_last_absolute = g_variant_get_double (val_als);
/* the user has asked to renormalize */
if (manager->priv->ambient_norm_required) {
manager->priv->ambient_accumulator = manager->priv->ambient_percentage_old;
ch_backlight_renormalize (manager);
}
/* calculate exponential moving average */
brightness = manager->priv->ambient_last_absolute * 100.f / manager->priv->ambient_norm_value;
brightness = MIN (brightness, 100.f);
brightness = MAX (brightness, 0.f);
manager->priv->ambient_accumulator = (GSD_AMBIENT_SMOOTH * brightness) +
(1.0 - GSD_AMBIENT_SMOOTH) * manager->priv->ambient_accumulator;
/* no valid readings yet */
if (manager->priv->ambient_accumulator < 0.f)
goto out;
/* set new value */
g_debug ("set brightness from ambient %.1f%%",
manager->priv->ambient_accumulator);
pc = manager->priv->ambient_accumulator;
if (!backlight_set_percentage (manager->priv->rr_screen, &pc, &error)) {
g_warning ("failed to set brightness: %s", error->message);
g_error_free (error);
}
manager->priv->ambient_percentage_old = pc;
out:
if (val_has != NULL)
g_variant_unref (val_has);
if (val_als != NULL)
g_variant_unref (val_als);
}
static void
iio_proxy_appeared_cb (GDBusConnection *connection,
const gchar *name,
const gchar *name_owner,
gpointer user_data)
{
GsdPowerManager *manager = GSD_POWER_MANAGER (user_data);
manager->priv->iio_proxy =
g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
0,
NULL,
"net.hadess.SensorProxy",
"/net/hadess/SensorProxy",
"net.hadess.SensorProxy",
NULL,
NULL);
g_signal_connect (manager->priv->iio_proxy, "g-properties-changed",
G_CALLBACK (iio_proxy_changed_cb), manager);
iio_proxy_claim_light (manager, TRUE);
}
static void
iio_proxy_vanished_cb (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
GsdPowerManager *manager = GSD_POWER_MANAGER (user_data);
g_clear_object (&manager->priv->iio_proxy);
}
gboolean
gsd_power_manager_start (GsdPowerManager *manager,
GError **error)
......@@ -2472,6 +2621,20 @@ gsd_power_manager_start (GsdPowerManager *manager,
manager->priv->settings_bus = g_settings_new ("org.gnome.desktop.session");
manager->priv->settings_xrandr = g_settings_new (GSD_XRANDR_SETTINGS_SCHEMA);
/* setup ambient light support */
manager->priv->iio_proxy_watch_id =
g_bus_watch_name (G_BUS_TYPE_SYSTEM,
"net.hadess.SensorProxy",
G_BUS_NAME_WATCHER_FLAGS_NONE,
iio_proxy_appeared_cb,
iio_proxy_vanished_cb,
manager, NULL);
manager->priv->ambient_norm_required = TRUE;
manager->priv->ambient_accumulator = -1.f;
manager->priv->ambient_norm_value = -1.f;
manager->priv->ambient_percentage_old = -1.f;
manager->priv->ambient_last_absolute = -1.f;
gnome_settings_profile_end (NULL);
return TRUE;
}
......@@ -2508,6 +2671,9 @@ gsd_power_manager_stop (GsdPowerManager *manager)
g_clear_object (&manager->priv->settings_bus);
g_clear_object (&manager->priv->up_client);
iio_proxy_claim_light (manager, FALSE);
g_clear_object (&manager->priv->iio_proxy);
if (manager->priv->inhibit_lid_switch_fd != -1) {
close (manager->priv->inhibit_lid_switch_fd);
manager->priv->inhibit_lid_switch_fd = -1;
......@@ -2629,6 +2795,10 @@ handle_method_call_screen (GsdPowerManager *manager,
g_assert_not_reached ();
}
/* ambient brightness no longer valid */
manager->priv->ambient_percentage_old = value;
manager->priv->ambient_norm_required = TRUE;
out:
/* return value */
if (value < 0) {
......@@ -2755,6 +2925,10 @@ handle_set_property_other (GsdPowerManager *manager,
g_variant_get (value, "i", &brightness_value);
if (backlight_set_percentage (manager->priv->rr_screen, &brightness_value, error)) {
backlight_iface_emit_changed (manager, GSD_POWER_DBUS_INTERFACE_SCREEN, brightness_value);
/* ambient brightness no longer valid */
manager->priv->ambient_percentage_old = brightness_value;
manager->priv->ambient_norm_required = TRUE;
return TRUE;
} else {
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment