[gnome-settings-daemon] color: Smooth the transition between different temperature values



commit 591c8860f76cffc21f77a259c4bd8a8129a7f4b8
Author: Richard Hughes <richard hughsie com>
Date:   Wed Feb 15 15:43:35 2017 +0000

    color: Smooth the transition between different temperature values
    
    This makes the effect less jarring when enabling or disabling in the control
    center or shell. This and also means we transition nicely when adjusting the
    times in manual mode.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=778689

 plugins/color/gcm-self-test.c   |    3 +
 plugins/color/gsd-night-light.c |   87 +++++++++++++++++++++++++++++++++++++-
 plugins/color/gsd-night-light.h |    2 +
 3 files changed, 89 insertions(+), 3 deletions(-)
---
diff --git a/plugins/color/gcm-self-test.c b/plugins/color/gcm-self-test.c
index 37ec133..8827ca4 100644
--- a/plugins/color/gcm-self-test.c
+++ b/plugins/color/gcm-self-test.c
@@ -73,6 +73,9 @@ gcm_test_night_light (void)
         /* do not start geoclue */
         gsd_night_light_set_geoclue_enabled (nlight, FALSE);
 
+        /* do not smooth the transition */
+        gsd_night_light_set_smooth_enabled (nlight, FALSE);
+
         /* switch off */
         settings = g_settings_new ("org.gnome.settings-daemon.plugins.color");
         g_settings_set_boolean (settings, "night-light-enabled", FALSE);
diff --git a/plugins/color/gsd-night-light.c b/plugins/color/gsd-night-light.c
index b0bb4f2..67415f1 100644
--- a/plugins/color/gsd-night-light.c
+++ b/plugins/color/gsd-night-light.c
@@ -44,6 +44,10 @@ struct _GsdNightLight {
         gdouble            cached_sunset;
         gdouble            cached_temperature;
         gboolean           cached_active;
+        gboolean           smooth_enabled;
+        GTimer            *smooth_timer;
+        guint              smooth_id;
+        gdouble            smooth_target_temperature;
         GCancellable      *cancellable;
         GDateTime         *datetime_override;
 };
@@ -61,6 +65,7 @@ enum {
 #define GSD_NIGHT_LIGHT_SCHEDULE_TIMEOUT      5       /* seconds */
 #define GSD_NIGHT_LIGHT_POLL_TIMEOUT          60      /* seconds */
 #define GSD_NIGHT_LIGHT_POLL_SMEAR            1       /* hours */
+#define GSD_NIGHT_LIGHT_SMOOTH_SMEAR          5.f     /* seconds */
 
 #define GSD_FRAC_DAY_MAX_DELTA                  (1.f/60.f)     /* 1 minute */
 #define GSD_TEMPERATURE_MAX_DELTA               (10.f)          /* Kelvin */
@@ -88,6 +93,27 @@ gsd_night_light_set_date_time_now (GsdNightLight *self, GDateTime *datetime)
         self->datetime_override = g_date_time_ref (datetime);
 }
 
+static void
+poll_smooth_destroy (GsdNightLight *self)
+{
+        if (self->smooth_id != 0) {
+                g_source_remove (self->smooth_id);
+                self->smooth_id = 0;
+        }
+        if (self->smooth_timer != NULL)
+                g_clear_pointer (&self->smooth_timer, g_timer_destroy);
+}
+
+void
+gsd_night_light_set_smooth_enabled (GsdNightLight *self,
+                                    gboolean smooth_enabled)
+{
+        /* ensure the timeout is stopped if called at runtime */
+        if (!smooth_enabled)
+                poll_smooth_destroy (self);
+        self->smooth_enabled = smooth_enabled;
+}
+
 static gdouble
 linear_interpolate (gdouble val1, gdouble val2, gdouble factor)
 {
@@ -136,12 +162,65 @@ update_cached_sunrise_sunset (GsdNightLight *self)
 }
 
 static void
+gsd_night_light_set_temperature_internal (GsdNightLight *self, gdouble temperature)
+{
+        if (ABS (self->cached_temperature - temperature) <= GSD_TEMPERATURE_MAX_DELTA)
+                return;
+        self->cached_temperature = temperature;
+        g_object_notify (G_OBJECT (self), "temperature");
+}
+
+static gboolean
+gsd_night_light_smooth_cb (gpointer user_data)
+{
+        GsdNightLight *self = GSD_NIGHT_LIGHT (user_data);
+        gdouble tmp;
+        gdouble frac;
+
+        /* find fraction */
+        frac = g_timer_elapsed (self->smooth_timer, NULL) / GSD_NIGHT_LIGHT_SMOOTH_SMEAR;
+        if (frac >= 1.f) {
+                gsd_night_light_set_temperature_internal (self,
+                                                          self->smooth_target_temperature);
+                self->smooth_id = 0;
+                return G_SOURCE_REMOVE;
+        }
+
+        /* set new temperature step using log curve */
+        tmp = self->smooth_target_temperature - self->cached_temperature;
+        tmp *= frac;
+        tmp += self->cached_temperature;
+        gsd_night_light_set_temperature_internal (self, tmp);
+
+        return G_SOURCE_CONTINUE;
+}
+
+static void
+poll_smooth_create (GsdNightLight *self, gdouble temperature)
+{
+        poll_smooth_destroy (self);
+        self->smooth_target_temperature = temperature;
+        self->smooth_timer = g_timer_new ();
+        self->smooth_id = g_timeout_add (50, gsd_night_light_smooth_cb, self);
+}
+
+static void
 gsd_night_light_set_temperature (GsdNightLight *self, gdouble temperature)
 {
-        if (ABS (self->cached_temperature - temperature) > GSD_TEMPERATURE_MAX_DELTA) {
-                self->cached_temperature = temperature;
-                g_object_notify (G_OBJECT (self), "temperature");
+        /* immediate */
+        if (!self->smooth_enabled) {
+                gsd_night_light_set_temperature_internal (self, temperature);
+                return;
         }
+
+        /* small jump */
+        if (ABS (temperature - self->cached_temperature) < GSD_TEMPERATURE_MAX_DELTA) {
+                gsd_night_light_set_temperature_internal (self, temperature);
+                return;
+        }
+
+        /* smooth out the transition */
+        poll_smooth_create (self, temperature);
 }
 
 static void
@@ -460,6 +539,7 @@ gsd_night_light_finalize (GObject *object)
         GsdNightLight *self = GSD_NIGHT_LIGHT (object);
 
         poll_timeout_destroy (self);
+        poll_smooth_destroy (self);
 
         g_clear_object (&self->settings);
         g_clear_pointer (&self->datetime_override, (GDestroyNotify) g_date_time_unref);
@@ -596,6 +676,7 @@ static void
 gsd_night_light_init (GsdNightLight *self)
 {
         self->geoclue_enabled = TRUE;
+        self->smooth_enabled = TRUE;
         self->cached_sunrise = -1.f;
         self->cached_sunset = -1.f;
         self->cached_temperature = GSD_COLOR_TEMPERATURE_DEFAULT;
diff --git a/plugins/color/gsd-night-light.h b/plugins/color/gsd-night-light.h
index 2403307..4f086dc 100644
--- a/plugins/color/gsd-night-light.h
+++ b/plugins/color/gsd-night-light.h
@@ -46,6 +46,8 @@ void             gsd_night_light_set_geoclue_enabled    (GsdNightLight *self,
                                                          gboolean       enabled);
 void             gsd_night_light_set_date_time_now      (GsdNightLight *self,
                                                          GDateTime     *datetime);
+void             gsd_night_light_set_smooth_enabled     (GsdNightLight *self,
+                                                         gboolean       smooth_enabled);
 
 G_END_DECLS
 


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