[gnome-settings-daemon] Add support for ambient light devices supported by iio-sensor-proxy



commit afd1ec179f8f497a8068fc413102c2ba1b42a26f
Author: Richard Hughes <richard hughsie com>
Date:   Thu May 21 11:19:35 2015 +0100

    Add support for ambient light devices supported by iio-sensor-proxy
    
    Resolves: https://bugzilla.gnome.org/show_bug.cgi?id=745181

 ...settings-daemon.plugins.power.gschema.xml.in.in |    5 +
 plugins/power/gsd-power-manager.c                  |  182 +++++++++++++++++++-
 2 files changed, 183 insertions(+), 4 deletions(-)
---
diff --git a/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in.in 
b/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in.in
index 51d017b..deec1f0 100644
--- a/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in.in
+++ b/data/org.gnome.settings-daemon.plugins.power.gschema.xml.in.in
@@ -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>
diff --git a/plugins/power/gsd-power-manager.c b/plugins/power/gsd-power-manager.c
index afe9405..1215f8b 100644
--- a/plugins/power/gsd-power-manager.c
+++ b/plugins/power/gsd-power-manager.c
@@ -1,7 +1,7 @@
 /* -*- 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;
 
@@ -975,11 +989,33 @@ screen_devices_enable (GsdPowerManager *manager)
 }
 
 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);
 }
 
@@ -2079,6 +2120,19 @@ idle_became_active_cb (GnomeIdleMonitor *monitor,
 }
 
 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,
                                 GsdPowerManager *manager)
@@ -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,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]