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 @@ ...@@ -61,5 +61,10 @@
<summary>Power button action</summary> <summary>Power button action</summary>
<description>The action to take when the system power button is pressed.</description> <description>The action to take when the system power button is pressed.</description>
</key> </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> </schema>
</schemalist> </schemalist>
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
* *
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> * 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) 2011 Ritesh Khadgaray <khadgaray@gmail.com>
* Copyright (C) 2012-2013 Red Hat Inc. * Copyright (C) 2012-2013 Red Hat Inc.
* *
...@@ -77,6 +77,11 @@ ...@@ -77,6 +77,11 @@
/* And the time before we stop the warning sound */ /* And the time before we stop the warning sound */
#define GSD_STOP_SOUND_DELAY GSD_ACTION_DELAY - 2 #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[] = static const gchar introspection_xml[] =
"<node>" "<node>"
" <interface name='org.gnome.SettingsDaemon.Power.Screen'>" " <interface name='org.gnome.SettingsDaemon.Power.Screen'>"
...@@ -157,6 +162,15 @@ struct GsdPowerManagerPrivate ...@@ -157,6 +162,15 @@ struct GsdPowerManagerPrivate
gint kbd_brightness_old; gint kbd_brightness_old;
gint kbd_brightness_pre_dim; 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 */ /* Sound */
guint32 critical_alert_timeout_id; guint32 critical_alert_timeout_id;
...@@ -974,12 +988,34 @@ screen_devices_enable (GsdPowerManager *manager) ...@@ -974,12 +988,34 @@ screen_devices_enable (GsdPowerManager *manager)
g_hash_table_remove_all (manager->priv->disabled_devices); 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 static void
backlight_enable (GsdPowerManager *manager) backlight_enable (GsdPowerManager *manager)
{ {
gboolean ret; gboolean ret;
GError *error = NULL; GError *error = NULL;
iio_proxy_claim_light (manager, TRUE);
ret = gnome_rr_screen_set_dpms_mode (manager->priv->rr_screen, ret = gnome_rr_screen_set_dpms_mode (manager->priv->rr_screen,
GNOME_RR_DPMS_ON, GNOME_RR_DPMS_ON,
&error); &error);
...@@ -1000,6 +1036,7 @@ backlight_disable (GsdPowerManager *manager) ...@@ -1000,6 +1036,7 @@ backlight_disable (GsdPowerManager *manager)
gboolean ret; gboolean ret;
GError *error = NULL; GError *error = NULL;
iio_proxy_claim_light (manager, FALSE);
ret = gnome_rr_screen_set_dpms_mode (manager->priv->rr_screen, ret = gnome_rr_screen_set_dpms_mode (manager->priv->rr_screen,
GNOME_RR_DPMS_OFF, GNOME_RR_DPMS_OFF,
&error); &error);
...@@ -1855,6 +1892,10 @@ gsd_power_manager_finalize (GObject *object) ...@@ -1855,6 +1892,10 @@ gsd_power_manager_finalize (GObject *object)
if (manager->priv->name_id != 0) if (manager->priv->name_id != 0)
g_bus_unown_name (manager->priv->name_id); 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); G_OBJECT_CLASS (gsd_power_manager_parent_class)->finalize (object);
} }
...@@ -2078,6 +2119,19 @@ idle_became_active_cb (GnomeIdleMonitor *monitor, ...@@ -2078,6 +2119,19 @@ idle_became_active_cb (GnomeIdleMonitor *monitor,
idle_set_mode (manager, GSD_POWER_IDLE_MODE_NORMAL); 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 static void
engine_settings_key_changed_cb (GSettings *settings, engine_settings_key_changed_cb (GSettings *settings,
const gchar *key, const gchar *key,
...@@ -2420,15 +2474,110 @@ on_rr_screen_acquired (GObject *object, ...@@ -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 /* 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) (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_iface_emit_changed (manager, GSD_POWER_DBUS_INTERFACE_SCREEN,
backlight_get_percentage (manager->priv->rr_screen, NULL)); manager->priv->ambient_percentage_old);
else } else {
backlight_iface_emit_changed (manager, GSD_POWER_DBUS_INTERFACE_SCREEN, -1); backlight_iface_emit_changed (manager, GSD_POWER_DBUS_INTERFACE_SCREEN, -1);
}
gnome_settings_profile_end (NULL); 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 gboolean
gsd_power_manager_start (GsdPowerManager *manager, gsd_power_manager_start (GsdPowerManager *manager,
GError **error) GError **error)
...@@ -2472,6 +2621,20 @@ gsd_power_manager_start (GsdPowerManager *manager, ...@@ -2472,6 +2621,20 @@ gsd_power_manager_start (GsdPowerManager *manager,
manager->priv->settings_bus = g_settings_new ("org.gnome.desktop.session"); manager->priv->settings_bus = g_settings_new ("org.gnome.desktop.session");
manager->priv->settings_xrandr = g_settings_new (GSD_XRANDR_SETTINGS_SCHEMA); 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); gnome_settings_profile_end (NULL);
return TRUE; return TRUE;
} }
...@@ -2508,6 +2671,9 @@ gsd_power_manager_stop (GsdPowerManager *manager) ...@@ -2508,6 +2671,9 @@ gsd_power_manager_stop (GsdPowerManager *manager)
g_clear_object (&manager->priv->settings_bus); g_clear_object (&manager->priv->settings_bus);
g_clear_object (&manager->priv->up_client); 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) { if (manager->priv->inhibit_lid_switch_fd != -1) {
close (manager->priv->inhibit_lid_switch_fd); close (manager->priv->inhibit_lid_switch_fd);
manager->priv->inhibit_lid_switch_fd = -1; manager->priv->inhibit_lid_switch_fd = -1;
...@@ -2629,6 +2795,10 @@ handle_method_call_screen (GsdPowerManager *manager, ...@@ -2629,6 +2795,10 @@ handle_method_call_screen (GsdPowerManager *manager,
g_assert_not_reached (); g_assert_not_reached ();
} }
/* ambient brightness no longer valid */
manager->priv->ambient_percentage_old = value;
manager->priv->ambient_norm_required = TRUE;
out: out:
/* return value */ /* return value */
if (value < 0) { if (value < 0) {
...@@ -2755,6 +2925,10 @@ handle_set_property_other (GsdPowerManager *manager, ...@@ -2755,6 +2925,10 @@ handle_set_property_other (GsdPowerManager *manager,
g_variant_get (value, "i", &brightness_value); g_variant_get (value, "i", &brightness_value);
if (backlight_set_percentage (manager->priv->rr_screen, &brightness_value, error)) { if (backlight_set_percentage (manager->priv->rr_screen, &brightness_value, error)) {
backlight_iface_emit_changed (manager, GSD_POWER_DBUS_INTERFACE_SCREEN, brightness_value); 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; return TRUE;
} else { } else {
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, 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