diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 14:51:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 14:51:55 +0000 |
commit | 86b7f1a83d7db9c912f32b29c32e1124c0a6454d (patch) | |
tree | 42a7ff7c6885e99e0669d07b104df11b2bf387b6 /plugins/color/gsd-night-light.c | |
parent | Initial commit. (diff) | |
download | gnome-settings-daemon-86b7f1a83d7db9c912f32b29c32e1124c0a6454d.tar.xz gnome-settings-daemon-86b7f1a83d7db9c912f32b29c32e1124c0a6454d.zip |
Adding upstream version 3.38.2.upstream/3.38.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | plugins/color/gsd-night-light.c | 801 |
1 files changed, 801 insertions, 0 deletions
diff --git a/plugins/color/gsd-night-light.c b/plugins/color/gsd-night-light.c new file mode 100644 index 0000000..635f160 --- /dev/null +++ b/plugins/color/gsd-night-light.c @@ -0,0 +1,801 @@ +/* + * Copyright (C) 2017 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <geoclue.h> + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include "gnome-datetime-source.h" + +#include "gsd-color-state.h" + +#include "gsd-night-light.h" +#include "gsd-night-light-common.h" + +struct _GsdNightLight { + GObject parent; + GSettings *settings; + gboolean forced; + gboolean disabled_until_tmw; + GDateTime *disabled_until_tmw_dt; + gboolean geoclue_enabled; + GSource *source; + guint validate_id; + GClueClient *geoclue_client; + GClueSimple *geoclue_simple; + GSettings *location_settings; + gdouble cached_sunrise; + 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; +}; + +enum { + PROP_0, + PROP_ACTIVE, + PROP_SUNRISE, + PROP_SUNSET, + PROP_TEMPERATURE, + PROP_DISABLED_UNTIL_TMW, + PROP_FORCED, + PROP_LAST +}; + +#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 */ + +#define DESKTOP_ID "gnome-color-panel" + +static void poll_timeout_destroy (GsdNightLight *self); +static void poll_timeout_create (GsdNightLight *self); +static void night_light_recheck (GsdNightLight *self); + +G_DEFINE_TYPE (GsdNightLight, gsd_night_light, G_TYPE_OBJECT); + +static GDateTime * +gsd_night_light_get_date_time_now (GsdNightLight *self) +{ + if (self->datetime_override != NULL) + return g_date_time_ref (self->datetime_override); + return g_date_time_new_now_local (); +} + +void +gsd_night_light_set_date_time_now (GsdNightLight *self, GDateTime *datetime) +{ + if (self->datetime_override != NULL) + g_date_time_unref (self->datetime_override); + self->datetime_override = g_date_time_ref (datetime); + + night_light_recheck (self); +} + +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) +{ + g_return_val_if_fail (factor >= 0.f, -1.f); + g_return_val_if_fail (factor <= 1.f, -1.f); + return ((val1 - val2) * factor) + val2; +} + +static gboolean +update_cached_sunrise_sunset (GsdNightLight *self) +{ + gboolean ret = FALSE; + gdouble latitude; + gdouble longitude; + gdouble sunrise; + gdouble sunset; + g_autoptr(GVariant) tmp = NULL; + g_autoptr(GDateTime) dt_now = gsd_night_light_get_date_time_now (self); + + /* calculate the sunrise/sunset for the location */ + tmp = g_settings_get_value (self->settings, "night-light-last-coordinates"); + g_variant_get (tmp, "(dd)", &latitude, &longitude); + if (latitude > 90.f || latitude < -90.f) + return FALSE; + if (longitude > 180.f || longitude < -180.f) + return FALSE; + if (!gsd_night_light_get_sunrise_sunset (dt_now, latitude, longitude, + &sunrise, &sunset)) { + g_warning ("failed to get sunset/sunrise for %.3f,%.3f", + longitude, longitude); + return FALSE; + } + + /* anything changed */ + if (ABS (self->cached_sunrise - sunrise) > GSD_FRAC_DAY_MAX_DELTA) { + self->cached_sunrise = sunrise; + g_object_notify (G_OBJECT (self), "sunrise"); + ret = TRUE; + } + if (ABS (self->cached_sunset - sunset) > GSD_FRAC_DAY_MAX_DELTA) { + self->cached_sunset = sunset; + g_object_notify (G_OBJECT (self), "sunset"); + ret = TRUE; + } + return ret; +} + +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) +{ + g_assert (self->smooth_id == 0); + 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) +{ + /* immediate */ + if (!self->smooth_enabled) { + gsd_night_light_set_temperature_internal (self, temperature); + return; + } + + /* Destroy any smooth transition, it will be recreated if neccessary */ + poll_smooth_destroy (self); + + /* 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 +gsd_night_light_set_active (GsdNightLight *self, gboolean active) +{ + if (self->cached_active == active) + return; + self->cached_active = active; + + /* ensure set to unity temperature */ + if (!active) + gsd_night_light_set_temperature (self, GSD_COLOR_TEMPERATURE_DEFAULT); + + g_object_notify (G_OBJECT (self), "active"); +} + +static void +night_light_recheck (GsdNightLight *self) +{ + gdouble frac_day; + gdouble schedule_from = -1.f; + gdouble schedule_to = -1.f; + gdouble smear = GSD_NIGHT_LIGHT_POLL_SMEAR; /* hours */ + guint temperature; + guint temp_smeared; + g_autoptr(GDateTime) dt_now = gsd_night_light_get_date_time_now (self); + + /* Forced mode, just set the temperature to night light. + * Proper rechecking will happen once forced mode is disabled again */ + if (self->forced) { + temperature = g_settings_get_uint (self->settings, "night-light-temperature"); + gsd_night_light_set_temperature (self, temperature); + return; + } + + /* enabled */ + if (!g_settings_get_boolean (self->settings, "night-light-enabled")) { + g_debug ("night light disabled, resetting"); + gsd_night_light_set_active (self, FALSE); + return; + } + + /* calculate the position of the sun */ + if (g_settings_get_boolean (self->settings, "night-light-schedule-automatic")) { + update_cached_sunrise_sunset (self); + if (self->cached_sunrise > 0.f && self->cached_sunset > 0.f) { + schedule_to = self->cached_sunrise; + schedule_from = self->cached_sunset; + } + } + + /* fall back to manual settings */ + if (schedule_to <= 0.f || schedule_from <= 0.f) { + schedule_from = g_settings_get_double (self->settings, + "night-light-schedule-from"); + schedule_to = g_settings_get_double (self->settings, + "night-light-schedule-to"); + } + + /* get the current hour of a day as a fraction */ + frac_day = gsd_night_light_frac_day_from_dt (dt_now); + g_debug ("fractional day = %.3f, limits = %.3f->%.3f", + frac_day, schedule_from, schedule_to); + + /* disabled until tomorrow */ + if (self->disabled_until_tmw) { + GTimeSpan time_span; + gboolean reset = FALSE; + + time_span = g_date_time_difference (dt_now, self->disabled_until_tmw_dt); + + /* Reset if disabled until tomorrow is more than 24h ago. */ + if (time_span > (GTimeSpan) 24 * 60 * 60 * 1000000) { + g_debug ("night light disabled until tomorrow is older than 24h, resetting disabled until tomorrow"); + reset = TRUE; + } else if (time_span > 0) { + /* Or if a sunrise lies between the time it was disabled and now. */ + gdouble frac_disabled; + frac_disabled = gsd_night_light_frac_day_from_dt (self->disabled_until_tmw_dt); + if (frac_disabled != frac_day && + gsd_night_light_frac_day_is_between (schedule_to, + frac_disabled, + frac_day)) { + g_debug ("night light sun rise happened, resetting disabled until tomorrow"); + reset = TRUE; + } + } + + if (reset) { + self->disabled_until_tmw = FALSE; + g_clear_pointer(&self->disabled_until_tmw_dt, g_date_time_unref); + g_object_notify (G_OBJECT (self), "disabled-until-tmw"); + } else { + g_debug ("night light still day-disabled, resetting"); + gsd_night_light_set_temperature (self, + GSD_COLOR_TEMPERATURE_DEFAULT); + return; + } + } + + /* lower smearing period to be smaller than the time between start/stop */ + smear = MIN (smear, + MIN ( ABS (schedule_to - schedule_from), + 24 - ABS (schedule_to - schedule_from))); + + if (!gsd_night_light_frac_day_is_between (frac_day, + schedule_from - smear, + schedule_to)) { + g_debug ("not time for night-light"); + gsd_night_light_set_active (self, FALSE); + return; + } + + /* smear the temperature for a short duration before the set limits + * + * |----------------------| = from->to + * |-| = smear down + * |-| = smear up + * + * \ / + * \ / + * \--------------------/ + */ + temperature = g_settings_get_uint (self->settings, "night-light-temperature"); + if (smear < 0.01) { + /* Don't try to smear for extremely short or zero periods */ + temp_smeared = temperature; + } else if (gsd_night_light_frac_day_is_between (frac_day, + schedule_from - smear, + schedule_from)) { + gdouble factor = 1.f - ((frac_day - (schedule_from - smear)) / smear); + temp_smeared = linear_interpolate (GSD_COLOR_TEMPERATURE_DEFAULT, + temperature, factor); + } else if (gsd_night_light_frac_day_is_between (frac_day, + schedule_to - smear, + schedule_to)) { + gdouble factor = (frac_day - (schedule_to - smear)) / smear; + temp_smeared = linear_interpolate (GSD_COLOR_TEMPERATURE_DEFAULT, + temperature, factor); + } else { + temp_smeared = temperature; + } + g_debug ("night light mode on, using temperature of %uK (aiming for %uK)", + temp_smeared, temperature); + gsd_night_light_set_active (self, TRUE); + gsd_night_light_set_temperature (self, temp_smeared); +} + +static gboolean +night_light_recheck_schedule_cb (gpointer user_data) +{ + GsdNightLight *self = GSD_NIGHT_LIGHT (user_data); + night_light_recheck (self); + self->validate_id = 0; + return G_SOURCE_REMOVE; +} + +/* called when something changed */ +static void +night_light_recheck_schedule (GsdNightLight *self) +{ + if (self->validate_id != 0) + g_source_remove (self->validate_id); + self->validate_id = + g_timeout_add_seconds (GSD_NIGHT_LIGHT_SCHEDULE_TIMEOUT, + night_light_recheck_schedule_cb, + self); +} + +/* called when the time may have changed */ +static gboolean +night_light_recheck_cb (gpointer user_data) +{ + GsdNightLight *self = GSD_NIGHT_LIGHT (user_data); + + /* recheck parameters, then reschedule a new timeout */ + night_light_recheck (self); + poll_timeout_destroy (self); + poll_timeout_create (self); + + /* return value ignored for a one-time watch */ + return G_SOURCE_REMOVE; +} + +static void +poll_timeout_create (GsdNightLight *self) +{ + g_autoptr(GDateTime) dt_now = NULL; + g_autoptr(GDateTime) dt_expiry = NULL; + + if (self->source != NULL) + return; + + /* It is not a good idea to make this overridable, it just creates + * an infinite loop as a fixed date for testing just doesn't work. */ + dt_now = g_date_time_new_now_local (); + dt_expiry = g_date_time_add_seconds (dt_now, GSD_NIGHT_LIGHT_POLL_TIMEOUT); + self->source = _gnome_datetime_source_new (dt_now, + dt_expiry, + TRUE); + g_source_set_callback (self->source, + night_light_recheck_cb, + self, NULL); + g_source_attach (self->source, NULL); +} + +static void +poll_timeout_destroy (GsdNightLight *self) +{ + + if (self->source == NULL) + return; + + g_source_destroy (self->source); + g_source_unref (self->source); + self->source = NULL; +} + +static void +settings_changed_cb (GSettings *settings, gchar *key, gpointer user_data) +{ + GsdNightLight *self = GSD_NIGHT_LIGHT (user_data); + g_debug ("settings changed"); + night_light_recheck (self); +} + +static void +on_location_notify (GClueSimple *simple, + GParamSpec *pspec, + gpointer user_data) +{ + GsdNightLight *self = GSD_NIGHT_LIGHT (user_data); + GClueLocation *location; + gdouble latitude, longitude; + + location = gclue_simple_get_location (simple); + latitude = gclue_location_get_latitude (location); + longitude = gclue_location_get_longitude (location); + + g_settings_set_value (self->settings, + "night-light-last-coordinates", + g_variant_new ("(dd)", latitude, longitude)); + + g_debug ("got geoclue latitude %f, longitude %f", latitude, longitude); + + /* recheck the levels if the location changed significantly */ + if (update_cached_sunrise_sunset (self)) + night_light_recheck_schedule (self); +} + +static void +on_geoclue_simple_ready (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GsdNightLight *self = GSD_NIGHT_LIGHT (user_data); + GClueSimple *geoclue_simple; + g_autoptr(GError) error = NULL; + + geoclue_simple = gclue_simple_new_finish (res, &error); + if (geoclue_simple == NULL) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Failed to connect to GeoClue2 service: %s", error->message); + return; + } + + self->geoclue_simple = geoclue_simple; + self->geoclue_client = gclue_simple_get_client (self->geoclue_simple); + g_object_set (G_OBJECT (self->geoclue_client), + "time-threshold", 60*60, NULL); /* 1 hour */ + + g_signal_connect (self->geoclue_simple, "notify::location", + G_CALLBACK (on_location_notify), user_data); + + on_location_notify (self->geoclue_simple, NULL, user_data); +} + +static void +start_geoclue (GsdNightLight *self) +{ + self->cancellable = g_cancellable_new (); + gclue_simple_new (DESKTOP_ID, + GCLUE_ACCURACY_LEVEL_CITY, + self->cancellable, + on_geoclue_simple_ready, + self); + +} + +static void +stop_geoclue (GsdNightLight *self) +{ + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + + if (self->geoclue_client != NULL) { + gclue_client_call_stop (self->geoclue_client, NULL, NULL, NULL); + self->geoclue_client = NULL; + } + g_clear_object (&self->geoclue_simple); +} + +static void +check_location_settings (GsdNightLight *self) +{ + if (g_settings_get_boolean (self->location_settings, "enabled") && self->geoclue_enabled) + start_geoclue (self); + else + stop_geoclue (self); +} + +void +gsd_night_light_set_disabled_until_tmw (GsdNightLight *self, gboolean value) +{ + g_autoptr(GDateTime) dt = gsd_night_light_get_date_time_now (self); + + if (self->disabled_until_tmw == value) + return; + + self->disabled_until_tmw = value; + g_clear_pointer (&self->disabled_until_tmw_dt, g_date_time_unref); + if (self->disabled_until_tmw) + self->disabled_until_tmw_dt = g_steal_pointer (&dt); + night_light_recheck (self); + g_object_notify (G_OBJECT (self), "disabled-until-tmw"); +} + +gboolean +gsd_night_light_get_disabled_until_tmw (GsdNightLight *self) +{ + return self->disabled_until_tmw; +} + +void +gsd_night_light_set_forced (GsdNightLight *self, gboolean value) +{ + if (self->forced == value) + return; + + self->forced = value; + g_object_notify (G_OBJECT (self), "forced"); + + /* A simple recheck might not reset the temperature if + * night light is currently disabled. */ + if (!self->forced && !self->cached_active) + gsd_night_light_set_temperature (self, GSD_COLOR_TEMPERATURE_DEFAULT); + + night_light_recheck (self); +} + +gboolean +gsd_night_light_get_forced (GsdNightLight *self) +{ + return self->forced; +} + +gboolean +gsd_night_light_get_active (GsdNightLight *self) +{ + return self->cached_active; +} + +gdouble +gsd_night_light_get_sunrise (GsdNightLight *self) +{ + return self->cached_sunrise; +} + +gdouble +gsd_night_light_get_sunset (GsdNightLight *self) +{ + return self->cached_sunset; +} + +gdouble +gsd_night_light_get_temperature (GsdNightLight *self) +{ + return self->cached_temperature; +} + +void +gsd_night_light_set_geoclue_enabled (GsdNightLight *self, gboolean enabled) +{ + self->geoclue_enabled = enabled; +} + +gboolean +gsd_night_light_start (GsdNightLight *self, GError **error) +{ + night_light_recheck (self); + poll_timeout_create (self); + + /* care about changes */ + g_signal_connect (self->settings, "changed", + G_CALLBACK (settings_changed_cb), self); + + g_signal_connect_swapped (self->location_settings, "changed::enabled", + G_CALLBACK (check_location_settings), self); + check_location_settings (self); + + return TRUE; +} + +static void +gsd_night_light_finalize (GObject *object) +{ + GsdNightLight *self = GSD_NIGHT_LIGHT (object); + + stop_geoclue (self); + + poll_timeout_destroy (self); + poll_smooth_destroy (self); + + g_clear_object (&self->settings); + g_clear_pointer (&self->datetime_override, g_date_time_unref); + g_clear_pointer (&self->disabled_until_tmw_dt, g_date_time_unref); + + if (self->validate_id > 0) { + g_source_remove (self->validate_id); + self->validate_id = 0; + } + + g_clear_object (&self->location_settings); + G_OBJECT_CLASS (gsd_night_light_parent_class)->finalize (object); +} + +static void +gsd_night_light_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GsdNightLight *self = GSD_NIGHT_LIGHT (object); + + switch (prop_id) { + case PROP_SUNRISE: + self->cached_sunrise = g_value_get_double (value); + break; + case PROP_SUNSET: + self->cached_sunset = g_value_get_double (value); + break; + case PROP_TEMPERATURE: + self->cached_temperature = g_value_get_double (value); + break; + case PROP_DISABLED_UNTIL_TMW: + gsd_night_light_set_disabled_until_tmw (self, g_value_get_boolean (value)); + break; + case PROP_FORCED: + gsd_night_light_set_forced (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gsd_night_light_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GsdNightLight *self = GSD_NIGHT_LIGHT (object); + + switch (prop_id) { + case PROP_ACTIVE: + g_value_set_boolean (value, self->cached_active); + break; + case PROP_SUNRISE: + g_value_set_double (value, self->cached_sunrise); + break; + case PROP_SUNSET: + g_value_set_double (value, self->cached_sunrise); + break; + case PROP_TEMPERATURE: + g_value_set_double (value, self->cached_sunrise); + break; + case PROP_DISABLED_UNTIL_TMW: + g_value_set_boolean (value, gsd_night_light_get_disabled_until_tmw (self)); + break; + case PROP_FORCED: + g_value_set_boolean (value, gsd_night_light_get_forced (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gsd_night_light_class_init (GsdNightLightClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gsd_night_light_finalize; + + object_class->set_property = gsd_night_light_set_property; + object_class->get_property = gsd_night_light_get_property; + + g_object_class_install_property (object_class, + PROP_ACTIVE, + g_param_spec_boolean ("active", + "Active", + "If night light functionality is active right now", + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_SUNRISE, + g_param_spec_double ("sunrise", + "Sunrise", + "Sunrise in fractional hours", + 0, + 24.f, + 12, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_SUNSET, + g_param_spec_double ("sunset", + "Sunset", + "Sunset in fractional hours", + 0, + 24.f, + 12, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_TEMPERATURE, + g_param_spec_double ("temperature", + "Temperature", + "Temperature in Kelvin", + GSD_COLOR_TEMPERATURE_MIN, + GSD_COLOR_TEMPERATURE_MAX, + GSD_COLOR_TEMPERATURE_DEFAULT, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_DISABLED_UNTIL_TMW, + g_param_spec_boolean ("disabled-until-tmw", + "Disabled until tomorrow", + "If the night light is disabled until the next day", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_FORCED, + g_param_spec_boolean ("forced", + "Forced", + "Whether night light should be forced on, useful for previewing", + FALSE, + G_PARAM_READWRITE)); + +} + +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; + self->settings = g_settings_new ("org.gnome.settings-daemon.plugins.color"); + self->location_settings = g_settings_new ("org.gnome.system.location"); +} + +GsdNightLight * +gsd_night_light_new (void) +{ + return g_object_new (GSD_TYPE_NIGHT_LIGHT, NULL); +} |