summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2017-02-15 15:43:35 +0000
committerRichard Hughes <richard@hughsie.com>2017-02-16 15:06:51 +0000
commit591c8860f76cffc21f77a259c4bd8a8129a7f4b8 (patch)
tree50b39ac2661360d483871fb89f3aca80cb7fa69d
parent44da5c107d260e566e00021c01de0a15c23a1620 (diff)
downloadgnome-settings-daemon-591c8860f76cffc21f77a259c4bd8a8129a7f4b8.tar.gz
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
-rw-r--r--plugins/color/gcm-self-test.c3
-rw-r--r--plugins/color/gsd-night-light.c87
-rw-r--r--plugins/color/gsd-night-light.h2
3 files changed, 89 insertions, 3 deletions
diff --git a/plugins/color/gcm-self-test.c b/plugins/color/gcm-self-test.c
index 37ec1338..8827ca46 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 b0bb4f24..67415f1d 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 24033074..4f086dc6 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