From 66e92a6c6d3b2be2402db7bf69073719eedf9fb7 Mon Sep 17 00:00:00 2001 From: Jamie Murphy Date: Fri, 31 Oct 2025 13:06:24 -0700 Subject: [PATCH 1/2] color: Refactor Geoclue bits into standalone GsdLocationMonitor This handles the Geoclue location services for night light, and colour schemes in later commits. --- plugins/color/gcm-self-test.c | 124 +++++++-- plugins/color/gsd-color-manager.c | 98 ++++++-- plugins/color/gsd-location-monitor.c | 362 +++++++++++++++++++++++++++ plugins/color/gsd-location-monitor.h | 46 ++++ plugins/color/gsd-night-light.c | 304 ++-------------------- plugins/color/gsd-night-light.h | 12 +- plugins/color/meson.build | 2 + 7 files changed, 625 insertions(+), 323 deletions(-) create mode 100644 plugins/color/gsd-location-monitor.c create mode 100644 plugins/color/gsd-location-monitor.h diff --git a/plugins/color/gcm-self-test.c b/plugins/color/gcm-self-test.c index 6ebe2f2ce..249f7a862 100644 --- a/plugins/color/gcm-self-test.c +++ b/plugins/color/gcm-self-test.c @@ -26,15 +26,16 @@ #include #include "gsd-color-state.h" +#include "gsd-location-monitor.h" #include "gsd-night-light.h" #include "gsd-night-light-common.h" GMainLoop *mainloop; static void -on_notify (GsdNightLight *nlight, - GParamSpec *pspec, - gpointer user_data) +on_notify (GsdLocationMonitor *monitor, + GParamSpec *pspec, + gpointer user_data) { guint *cnt = (guint *) user_data; (*cnt)++; @@ -48,6 +49,55 @@ quit_mainloop (gpointer user_data) return FALSE; } +static void +gcm_test_location_monitor (void) +{ + gboolean ret; + guint sunrise_cnt = 0; + guint sunset_cnt = 0; + g_autoptr(GDateTime) datetime_override = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GsdLocationMonitor) monitor = NULL; + g_autoptr(GSettings) settings = NULL; + + monitor = gsd_location_monitor_get (); + g_assert (GSD_IS_LOCATION_MONITOR (monitor)); + g_signal_connect (monitor, "notify::sunset", + G_CALLBACK (on_notify), &sunset_cnt); + g_signal_connect (monitor, "notify::sunrise", + G_CALLBACK (on_notify), &sunrise_cnt); + + /* hardcode a specific date and time */ + datetime_override = g_date_time_new_utc (2017, 2, 8, 20, 0, 0); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + + /* do not start geoclue */ + gsd_location_monitor_set_geoclue_enabled (monitor, FALSE); + + settings = g_settings_new ("org.gnome.settings-daemon.plugins.color"); + + /* check default values */ + g_assert_cmpint ((gint) gsd_location_monitor_get_sunrise (monitor), ==, -1); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunset (monitor), ==, -1); + + /* start module, disabled */ + ret = gsd_location_monitor_start (monitor, &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpint (sunset_cnt, ==, 0); + g_assert_cmpint (sunrise_cnt, ==, 0); + + g_settings_set_value (settings, "night-light-last-coordinates", + g_variant_new ("(dd)", 51.5, -0.1278)); + g_assert_cmpint (sunset_cnt, ==, 1); + g_assert_cmpint (sunrise_cnt, ==, 1); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunrise (monitor), ==, 7); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunset (monitor), ==, 17); + + /* reset coordinates */ + g_settings_reset (settings, "night-light-last-coordinates"); +} + static void gcm_test_night_light (void) { @@ -60,16 +110,20 @@ gcm_test_night_light (void) g_autoptr(GDateTime) datetime_override = NULL; g_autoptr(GError) error = NULL; g_autoptr(GsdNightLight) nlight = NULL; + g_autoptr(GsdLocationMonitor) monitor = NULL; g_autoptr(GSettings) settings = NULL; + monitor = gsd_location_monitor_get (); + g_assert (GSD_IS_LOCATION_MONITOR (monitor)); + g_signal_connect (monitor, "notify::sunset", + G_CALLBACK (on_notify), &sunset_cnt); + g_signal_connect (monitor, "notify::sunrise", + G_CALLBACK (on_notify), &sunrise_cnt); + nlight = gsd_night_light_new (); g_assert (GSD_IS_NIGHT_LIGHT (nlight)); g_signal_connect (nlight, "notify::active", G_CALLBACK (on_notify), &active_cnt); - g_signal_connect (nlight, "notify::sunset", - G_CALLBACK (on_notify), &sunset_cnt); - g_signal_connect (nlight, "notify::sunrise", - G_CALLBACK (on_notify), &sunrise_cnt); g_signal_connect (nlight, "notify::temperature", G_CALLBACK (on_notify), &temperature_cnt); g_signal_connect (nlight, "notify::disabled-until-tmw", @@ -77,10 +131,11 @@ gcm_test_night_light (void) /* hardcode a specific date and time */ datetime_override = g_date_time_new_utc (2017, 2, 8, 20, 0, 0); - gsd_night_light_set_date_time_now (nlight, datetime_override); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_night_light_recheck_immediate (nlight); /* do not start geoclue */ - gsd_night_light_set_geoclue_enabled (nlight, FALSE); + gsd_location_monitor_set_geoclue_enabled (monitor, FALSE); /* do not smooth the transition */ gsd_night_light_set_smooth_enabled (nlight, FALSE); @@ -92,12 +147,16 @@ gcm_test_night_light (void) /* check default values */ g_assert (!gsd_night_light_get_active (nlight)); - g_assert_cmpint ((gint) gsd_night_light_get_sunrise (nlight), ==, -1); - g_assert_cmpint ((gint) gsd_night_light_get_sunset (nlight), ==, -1); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunrise (monitor), ==, -1); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunset (monitor), ==, -1); + g_assert_cmpint (gsd_night_light_get_temperature (nlight), ==, GSD_COLOR_TEMPERATURE_DEFAULT); g_assert (!gsd_night_light_get_disabled_until_tmw (nlight)); /* start module, disabled */ + ret = gsd_location_monitor_start (monitor, &error); + g_assert_no_error (error); + g_assert (ret); ret = gsd_night_light_start (nlight, &error); g_assert_no_error (error); g_assert (ret); @@ -111,6 +170,7 @@ gcm_test_night_light (void) /* enable automatic mode */ g_settings_set_value (settings, "night-light-last-coordinates", g_variant_new ("(dd)", 51.5, -0.1278)); + g_settings_set_boolean (settings, "night-light-schedule-automatic", TRUE); g_settings_set_boolean (settings, "night-light-enabled", TRUE); g_assert (gsd_night_light_get_active (nlight)); @@ -119,8 +179,8 @@ gcm_test_night_light (void) g_assert_cmpint (sunrise_cnt, ==, 1); g_assert_cmpint (temperature_cnt, ==, 1); g_assert_cmpint (disabled_until_tmw_cnt, ==, 0); - g_assert_cmpint ((gint) gsd_night_light_get_sunrise (nlight), ==, 7); - g_assert_cmpint ((gint) gsd_night_light_get_sunset (nlight), ==, 17); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunrise (monitor), ==, 7); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunset (monitor), ==, 17); g_assert_cmpint (gsd_night_light_get_temperature (nlight), ==, 4000); g_assert (!gsd_night_light_get_disabled_until_tmw (nlight)); @@ -152,8 +212,8 @@ gcm_test_night_light (void) g_assert_cmpint (temperature_cnt, ==, 4); g_assert_cmpint (disabled_until_tmw_cnt, ==, 2); g_assert (!gsd_night_light_get_active (nlight)); - g_assert_cmpint ((gint) gsd_night_light_get_sunrise (nlight), ==, 7); - g_assert_cmpint ((gint) gsd_night_light_get_sunset (nlight), ==, 17); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunrise (monitor), ==, 7); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunset (monitor), ==, 17); g_assert_cmpint (gsd_night_light_get_temperature (nlight), ==, GSD_COLOR_TEMPERATURE_DEFAULT); g_assert (!gsd_night_light_get_disabled_until_tmw (nlight)); @@ -199,13 +259,15 @@ gcm_test_night_light (void) /* Move time past midnight */ g_clear_pointer (&datetime_override, g_date_time_unref); datetime_override = g_date_time_new_utc (2017, 2, 9, 1, 0, 0); - gsd_night_light_set_date_time_now (nlight, datetime_override); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_night_light_recheck_immediate (nlight); g_assert_true (gsd_night_light_get_disabled_until_tmw (nlight)); /* Move past sunrise */ g_clear_pointer (&datetime_override, g_date_time_unref); datetime_override = g_date_time_new_utc (2017, 2, 9, 8, 0, 0); - gsd_night_light_set_date_time_now (nlight, datetime_override); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_night_light_recheck_immediate (nlight); g_assert_false (gsd_night_light_get_disabled_until_tmw (nlight)); gsd_night_light_set_disabled_until_tmw (nlight, TRUE); @@ -213,7 +275,8 @@ gcm_test_night_light (void) /* Move into night more than 24h in the future */ g_clear_pointer (&datetime_override, g_date_time_unref); datetime_override = g_date_time_new_utc (2017, 2, 10, 20, 0, 0); - gsd_night_light_set_date_time_now (nlight, datetime_override); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_night_light_recheck_immediate (nlight); g_assert_false (gsd_night_light_get_disabled_until_tmw (nlight)); @@ -224,17 +287,20 @@ gcm_test_night_light (void) g_settings_set_boolean (settings, "night-light-enabled", TRUE); datetime_override = g_date_time_new_utc (2017, 2, 10, 5, 50, 0); - gsd_night_light_set_date_time_now (nlight, datetime_override); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_night_light_recheck_immediate (nlight); g_assert (gsd_night_light_get_active (nlight)); g_assert_cmpint (gsd_night_light_get_temperature (nlight), ==, 4000); datetime_override = g_date_time_new_utc (2017, 2, 10, 6, 0, 0); - gsd_night_light_set_date_time_now (nlight, datetime_override); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_night_light_recheck_immediate (nlight); g_assert (gsd_night_light_get_active (nlight)); g_assert_cmpint (gsd_night_light_get_temperature (nlight), ==, 4000); datetime_override = g_date_time_new_utc (2017, 2, 10, 6, 10, 0); - gsd_night_light_set_date_time_now (nlight, datetime_override); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_night_light_recheck_immediate (nlight); g_assert (gsd_night_light_get_active (nlight)); g_assert_cmpint (gsd_night_light_get_temperature (nlight), ==, 4000); @@ -245,19 +311,22 @@ gcm_test_night_light (void) /* Not enabled 10 minutes before sunset */ datetime_override = g_date_time_new_utc (2017, 2, 10, 5, 50, 0); - gsd_night_light_set_date_time_now (nlight, datetime_override); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_night_light_recheck_immediate (nlight); g_assert_false (gsd_night_light_get_active (nlight)); g_assert_cmpint (gsd_night_light_get_temperature (nlight), ==, GSD_COLOR_TEMPERATURE_DEFAULT); /* Not enabled >10 minutes after sunrise */ datetime_override = g_date_time_new_utc (2017, 2, 10, 6, 20, 0); - gsd_night_light_set_date_time_now (nlight, datetime_override); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_night_light_recheck_immediate (nlight); g_assert_false (gsd_night_light_get_active (nlight)); g_assert_cmpint (gsd_night_light_get_temperature (nlight), ==, GSD_COLOR_TEMPERATURE_DEFAULT); /* ~50% smeared 3 min before sunrise (sunrise at 6 past) */ datetime_override = g_date_time_new_utc (2017, 2, 10, 6, 3, 0); - gsd_night_light_set_date_time_now (nlight, datetime_override); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_night_light_recheck_immediate (nlight); g_assert_true (gsd_night_light_get_active (nlight)); g_assert_cmpint (gsd_night_light_get_temperature (nlight), <=, (GSD_COLOR_TEMPERATURE_DEFAULT + 4000) / 2 + 20); g_assert_cmpint (gsd_night_light_get_temperature (nlight), >=, (GSD_COLOR_TEMPERATURE_DEFAULT + 4000) / 2 - 20); @@ -266,10 +335,14 @@ gcm_test_night_light (void) g_settings_set_double (settings, "night-light-schedule-from", 6.1); g_settings_set_double (settings, "night-light-schedule-to", 6.0); datetime_override = g_date_time_new_utc (2017, 2, 10, 6, 3, 0); - gsd_night_light_set_date_time_now (nlight, datetime_override); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_night_light_recheck_immediate (nlight); g_assert_true (gsd_night_light_get_active (nlight)); g_assert_cmpint (gsd_night_light_get_temperature (nlight), <=, (GSD_COLOR_TEMPERATURE_DEFAULT + 4000) / 2 + 20); g_assert_cmpint (gsd_night_light_get_temperature (nlight), >=, (GSD_COLOR_TEMPERATURE_DEFAULT + 4000) / 2 - 20); + + /* reset coordinates */ + g_settings_reset (settings, "night-light-last-coordinates"); } static void @@ -353,6 +426,7 @@ main (int argc, char **argv) g_test_add_func ("/color/sunset-sunrise", gcm_test_sunset_sunrise); g_test_add_func ("/color/sunset-sunrise/fractional-timezone", gcm_test_sunset_sunrise_fractional_timezone); g_test_add_func ("/color/fractional-day", gcm_test_frac_day); + g_test_add_func ("/color/location-monitor", gcm_test_location_monitor); g_test_add_func ("/color/night-light", gcm_test_night_light); return g_test_run (); diff --git a/plugins/color/gsd-color-manager.c b/plugins/color/gsd-color-manager.c index aae10e425..ab12301eb 100644 --- a/plugins/color/gsd-color-manager.c +++ b/plugins/color/gsd-color-manager.c @@ -20,6 +20,9 @@ #include "config.h" +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include "gnome-datetime-source.h" + #include #include @@ -27,6 +30,8 @@ #include "gsd-color-calibrate.h" #include "gsd-color-manager.h" #include "gsd-color-state.h" +#include "gsd-night-light-common.h" +#include "gsd-location-monitor.h" #include "gsd-night-light.h" #define GSD_DBUS_NAME "org.gnome.SettingsDaemon" @@ -60,15 +65,19 @@ struct _GsdColorManager GsdColorCalibrate *calibrate; GsdColorState *state; + GsdLocationMonitor *monitor; GsdNightLight *nlight; guint nlight_forced_timeout_id; + GSource *source; }; enum { PROP_0, }; +#define GSD_COLOR_POLL_TIMEOUT 60 /* seconds */ + static void gsd_color_manager_class_init (GsdColorManagerClass *klass); static void gsd_color_manager_init (GsdColorManager *color_manager); static void gsd_color_manager_finalize (GObject *object); @@ -80,6 +89,9 @@ static void gsd_color_manager_dbus_unregister (GApplication *app, GDBusConnection *connection, const char *object_path); +static void poll_timeout_destroy (GsdColorManager *manager); +static void poll_timeout_create (GsdColorManager *manager); + G_DEFINE_TYPE (GsdColorManager, gsd_color_manager, GSD_TYPE_APPLICATION) static void @@ -94,6 +106,10 @@ gsd_color_manager_startup (GApplication *app) /* start the device probing */ gsd_color_state_start (manager->state); + /* setup location monitor module */ + if (!gsd_location_monitor_start (manager->monitor, &error)) + g_warning ("Could not start location monitor module: %s", error->message); + /* setup night light module */ if (!gsd_night_light_start (manager->nlight, &error)) g_warning ("Could not start night light module: %s", error->message); @@ -177,23 +193,25 @@ on_active_notify (GsdNightLight *nlight, } static void -on_sunset_notify (GsdNightLight *nlight, - GParamSpec *pspec, - gpointer user_data) +on_sunset_notify (GsdLocationMonitor *monitor, + GParamSpec *pspec, + gpointer user_data) { GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); + gsd_night_light_recheck_schedule (manager->nlight); emit_property_changed (manager, "Sunset", - g_variant_new_double (gsd_night_light_get_sunset (manager->nlight))); + g_variant_new_double (gsd_location_monitor_get_sunset (manager->monitor))); } static void -on_sunrise_notify (GsdNightLight *nlight, - GParamSpec *pspec, - gpointer user_data) +on_sunrise_notify (GsdLocationMonitor *monitor, + GParamSpec *pspec, + gpointer user_data) { GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); + gsd_night_light_recheck_schedule (manager->nlight); emit_property_changed (manager, "Sunrise", - g_variant_new_double (gsd_night_light_get_sunrise (manager->nlight))); + g_variant_new_double (gsd_location_monitor_get_sunrise (manager->monitor))); } static void @@ -218,6 +236,52 @@ on_temperature_notify (GsdNightLight *nlight, g_variant_new_uint32 (roundf (temperature))); } +static gboolean +color_recheck_cb (gpointer user_data) +{ + GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); + + /* recheck individual components */ + gsd_night_light_recheck_immediate (manager->nlight); + + poll_timeout_destroy (manager); + poll_timeout_create (manager); + + /* return value ignored for a one-time watch */ + return G_SOURCE_REMOVE; +} + +static void +poll_timeout_create (GsdColorManager *self) +{ + g_autoptr(GDateTime) dt_now = NULL; + g_autoptr(GDateTime) dt_expiry = NULL; + + if (self->source != NULL) + return; + + dt_now = g_date_time_new_now_local (); + dt_expiry = g_date_time_add_seconds (dt_now, GSD_COLOR_POLL_TIMEOUT); + self->source = _gnome_datetime_source_new (dt_now, + dt_expiry, + TRUE); + g_source_set_callback (self->source, + color_recheck_cb, + self, NULL); + g_source_attach (self->source, NULL); +} + +static void +poll_timeout_destroy (GsdColorManager *manager) +{ + if (manager->source == NULL) + return; + + g_source_destroy (manager->source); + g_source_unref (manager->source); + manager->source = NULL; +} + static void gsd_color_manager_init (GsdColorManager *manager) { @@ -225,14 +289,17 @@ gsd_color_manager_init (GsdColorManager *manager) manager->calibrate = gsd_color_calibrate_new (manager); manager->state = gsd_color_state_new (); + /* location monitor features */ + manager->monitor = gsd_location_monitor_get (); + g_signal_connect (manager->monitor, "notify::sunset", + G_CALLBACK (on_sunset_notify), manager); + g_signal_connect (manager->monitor, "notify::sunrise", + G_CALLBACK (on_sunrise_notify), manager); + /* night light features */ manager->nlight = gsd_night_light_new (); g_signal_connect (manager->nlight, "notify::active", G_CALLBACK (on_active_notify), manager); - g_signal_connect (manager->nlight, "notify::sunset", - G_CALLBACK (on_sunset_notify), manager); - g_signal_connect (manager->nlight, "notify::sunrise", - G_CALLBACK (on_sunrise_notify), manager); g_signal_connect (manager->nlight, "notify::temperature", G_CALLBACK (on_temperature_notify), manager); g_signal_connect (manager->nlight, "notify::disabled-until-tmw", @@ -249,8 +316,11 @@ gsd_color_manager_finalize (GObject *object) manager = GSD_COLOR_MANAGER (object); + poll_timeout_destroy (manager); + g_clear_object (&manager->calibrate); g_clear_object (&manager->state); + g_clear_object (&manager->monitor); g_clear_object (&manager->nlight); G_OBJECT_CLASS (gsd_color_manager_parent_class)->finalize (object); @@ -341,10 +411,10 @@ handle_get_property (GDBusConnection *connection, return g_variant_new_boolean (gsd_night_light_get_disabled_until_tmw (manager->nlight)); if (g_strcmp0 (property_name, "Sunrise") == 0) - return g_variant_new_double (gsd_night_light_get_sunrise (manager->nlight)); + return g_variant_new_double (gsd_location_monitor_get_sunrise (manager->monitor)); if (g_strcmp0 (property_name, "Sunset") == 0) - return g_variant_new_double (gsd_night_light_get_sunset (manager->nlight)); + return g_variant_new_double (gsd_location_monitor_get_sunset (manager->monitor)); g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Failed to get property: %s", property_name); diff --git a/plugins/color/gsd-location-monitor.c b/plugins/color/gsd-location-monitor.c new file mode 100644 index 000000000..6617da911 --- /dev/null +++ b/plugins/color/gsd-location-monitor.c @@ -0,0 +1,362 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2017 Richard Hughes + * Copyright (C) 2025 Jamie Murphy + * + * 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, see . + */ + +#include "config.h" + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include "gnome-datetime-source.h" + +#include "gsd-night-light-common.h" +#include "gsd-location-monitor.h" + +#include + +struct _GsdLocationMonitor { + GObject parent; + + GSettings *settings; + GSettings *location_settings; + + gdouble cached_sunrise; + gdouble cached_sunset; + GDateTime *datetime_override; + + GClueClient *geoclue_client; + GClueSimple *geoclue_simple; + gboolean geoclue_enabled; + GCancellable *cancellable; +}; + +enum { + PROP_0, + PROP_SUNRISE, + PROP_SUNSET, + PROP_LAST +}; + +enum { + CHANGED, + LAST_SIGNAL +}; + +static int signals[LAST_SIGNAL] = { 0 }; + +#define GSD_FRAC_DAY_MAX_DELTA (1.f/60.f) /* 1 minute */ + +#define DESKTOP_ID "gnome-color-panel" + +static void update_cached_sunrise_sunset (GsdLocationMonitor *self); + +G_DEFINE_TYPE (GsdLocationMonitor, gsd_location_monitor, G_TYPE_OBJECT); + +GDateTime * +gsd_location_monitor_get_date_time_now (GsdLocationMonitor *self) +{ + if (self->datetime_override != NULL) + return g_date_time_ref (self->datetime_override); + return g_date_time_new_now_local (); +} + +void +gsd_location_monitor_set_date_time_now (GsdLocationMonitor *self, + GDateTime *datetime) +{ + if (self->datetime_override != NULL) + g_date_time_unref (self->datetime_override); + self->datetime_override = g_date_time_ref (datetime); + + update_cached_sunrise_sunset (self); +} + +static void +update_cached_sunrise_sunset (GsdLocationMonitor *self) +{ + gdouble latitude; + gdouble longitude; + gdouble sunrise; + gdouble sunset; + g_autoptr(GVariant) tmp = NULL; + g_autoptr(GDateTime) dt_now = gsd_location_monitor_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; + if (longitude > 180.f || longitude < -180.f) + return; + 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; + } + + /* anything changed */ + if (ABS (self->cached_sunrise - sunrise) > GSD_FRAC_DAY_MAX_DELTA) { + self->cached_sunrise = sunrise; + g_object_notify (G_OBJECT (self), "sunrise"); + } + if (ABS (self->cached_sunset - sunset) > GSD_FRAC_DAY_MAX_DELTA) { + self->cached_sunset = sunset; + g_object_notify (G_OBJECT (self), "sunset"); + } +} + +static void +settings_changed_cb (GSettings *settings, gchar *key, gpointer user_data) +{ + GsdLocationMonitor *self = GSD_LOCATION_MONITOR (user_data); + g_debug ("settings changed"); + update_cached_sunrise_sunset (self); + g_signal_emit (G_OBJECT (self), + signals[CHANGED], + 0); +} + +static void +on_location_notify (GClueSimple *simple, + GParamSpec *pspec, + gpointer user_data) +{ + GsdLocationMonitor *self = GSD_LOCATION_MONITOR (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 */ + update_cached_sunrise_sunset (self); +} + +static void +on_geoclue_simple_ready (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GsdLocationMonitor *self = GSD_LOCATION_MONITOR (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 (GsdLocationMonitor *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 (GsdLocationMonitor *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 (GsdLocationMonitor *self) +{ + if (g_settings_get_boolean (self->location_settings, "enabled") && self->geoclue_enabled) + start_geoclue (self); + else + stop_geoclue (self); +} + +gdouble +gsd_location_monitor_get_sunrise (GsdLocationMonitor *self) +{ + return self->cached_sunrise; +} + +gdouble +gsd_location_monitor_get_sunset (GsdLocationMonitor *self) +{ + return self->cached_sunset; +} + +void +gsd_location_monitor_set_geoclue_enabled (GsdLocationMonitor *self, + gboolean enabled) +{ + self->geoclue_enabled = enabled; +} + +gboolean +gsd_location_monitor_start (GsdLocationMonitor *self, + GError **error) +{ + 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_location_monitor_finalize (GObject *object) +{ + GsdLocationMonitor *self = GSD_LOCATION_MONITOR (object); + + stop_geoclue (self); + + g_clear_object (&self->settings); + g_clear_object (&self->location_settings); + g_clear_pointer (&self->datetime_override, g_date_time_unref); + + G_OBJECT_CLASS (gsd_location_monitor_parent_class)->finalize (object); +} + +static void +gsd_location_monitor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GsdLocationMonitor *self = GSD_LOCATION_MONITOR (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; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gsd_location_monitor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GsdLocationMonitor *self = GSD_LOCATION_MONITOR (object); + + switch (prop_id) { + case PROP_SUNRISE: + g_value_set_double (value, self->cached_sunrise); + break; + case PROP_SUNSET: + g_value_set_double (value, self->cached_sunset); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gsd_location_monitor_class_init (GsdLocationMonitorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gsd_location_monitor_finalize; + + object_class->set_property = gsd_location_monitor_set_property; + object_class->get_property = gsd_location_monitor_get_property; + + 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)); + + signals[CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + +static void +gsd_location_monitor_init (GsdLocationMonitor *self) +{ + self->geoclue_enabled = TRUE; + self->cached_sunrise = -1.f; + self->cached_sunset = -1.f; + self->settings = g_settings_new ("org.gnome.settings-daemon.plugins.color"); + self->location_settings = g_settings_new ("org.gnome.system.location"); +} + +GsdLocationMonitor * +gsd_location_monitor_get (void) +{ + static GsdLocationMonitor *instance; + + if (g_once_init_enter (&instance)) { + GsdLocationMonitor *monitor = g_object_new (GSD_TYPE_LOCATION_MONITOR, NULL); + g_object_add_weak_pointer (G_OBJECT (monitor), (gpointer *)&instance); + g_once_init_leave (&instance, monitor); + } + + return g_object_ref (instance); +} \ No newline at end of file diff --git a/plugins/color/gsd-location-monitor.h b/plugins/color/gsd-location-monitor.h new file mode 100644 index 000000000..1b3c24c5b --- /dev/null +++ b/plugins/color/gsd-location-monitor.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2025 Jamie Murphy + * + * 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, see . + */ + +#ifndef __GSD_LOCATION_MONITOR_H__ +#define __GSD_LOCATION_MONITOR_H__ + +#include + +G_BEGIN_DECLS + +#define GSD_TYPE_LOCATION_MONITOR (gsd_location_monitor_get_type ()) +G_DECLARE_FINAL_TYPE (GsdLocationMonitor, gsd_location_monitor, GSD, LOCATION_MONITOR, GObject) + +GsdLocationMonitor *gsd_location_monitor_get (void); +gboolean gsd_location_monitor_start (GsdLocationMonitor *self, + GError **error); + +GDateTime *gsd_location_monitor_get_date_time_now (GsdLocationMonitor *self); + +gdouble gsd_location_monitor_get_sunrise (GsdLocationMonitor *self); +gdouble gsd_location_monitor_get_sunset (GsdLocationMonitor *self); + +/* only for the self test program */ +void gsd_location_monitor_set_geoclue_enabled (GsdLocationMonitor *self, + gboolean enabled); +void gsd_location_monitor_set_date_time_now (GsdLocationMonitor *self, + GDateTime *datetime); + +G_END_DECLS + +#endif /* __GSD_LOCATION_MONITOR_H__ */ \ No newline at end of file diff --git a/plugins/color/gsd-night-light.c b/plugins/color/gsd-night-light.c index b11f0755d..fdcbd8a99 100644 --- a/plugins/color/gsd-night-light.c +++ b/plugins/color/gsd-night-light.c @@ -20,11 +20,6 @@ #include "config.h" -#include - -#define GNOME_DESKTOP_USE_UNSTABLE_API -#include "gnome-datetime-source.h" - #include "gsd-color-state.h" #include "gsd-night-light.h" @@ -36,14 +31,7 @@ struct _GsdNightLight { 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; @@ -51,14 +39,12 @@ struct _GsdNightLight { guint smooth_id; gdouble smooth_target_temperature; GCancellable *cancellable; - GDateTime *datetime_override; + GsdLocationMonitor *monitor; }; enum { PROP_0, PROP_ACTIVE, - PROP_SUNRISE, - PROP_SUNSET, PROP_TEMPERATURE, PROP_DISABLED_UNTIL_TMW, PROP_FORCED, @@ -70,32 +56,17 @@ enum { #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) +gsd_night_light_recheck_immediate (GsdNightLight *self) { - if (self->datetime_override != NULL) - g_date_time_unref (self->datetime_override); - self->datetime_override = g_date_time_ref (datetime); - night_light_recheck (self); } @@ -128,45 +99,6 @@ linear_interpolate (gdouble val1, gdouble val2, gdouble factor) 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, gboolean force) { @@ -258,7 +190,7 @@ night_light_recheck (GsdNightLight *self) 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); + g_autoptr(GDateTime) dt_now = gsd_location_monitor_get_date_time_now (self->monitor); /* Forced mode, just set the temperature to night light. * Proper rechecking will happen once forced mode is disabled again */ @@ -277,10 +209,12 @@ night_light_recheck (GsdNightLight *self) /* 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; + gdouble cached_sunrise = gsd_location_monitor_get_sunrise (self->monitor); + gdouble cached_sunset = gsd_location_monitor_get_sunset (self->monitor); + + if (cached_sunrise > 0.f && cached_sunset > 0.f) { + schedule_to = cached_sunrise; + schedule_from = cached_sunset; } } @@ -393,9 +327,9 @@ night_light_recheck_schedule_cb (gpointer user_data) return G_SOURCE_REMOVE; } -/* called when something changed */ -static void -night_light_recheck_schedule (GsdNightLight *self) +/* called when location monitor updates */ +void +gsd_night_light_recheck_schedule (GsdNightLight *self) { if (self->validate_id != 0) g_source_remove (self->validate_id); @@ -405,152 +339,24 @@ night_light_recheck_schedule (GsdNightLight *self) 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); + if (g_settings_get_boolean (self->settings, "night-light-schedule-automatic")) + g_signal_connect (G_OBJECT (self->monitor), "changed", G_CALLBACK (night_light_recheck), self); else - stop_geoclue (self); + g_signal_handlers_disconnect_by_data (self->monitor, self); + + night_light_recheck (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); + g_autoptr(GDateTime) dt = gsd_location_monitor_get_date_time_now (self->monitor); if (self->disabled_until_tmw == value) return; @@ -598,44 +404,21 @@ 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; } @@ -644,13 +427,10 @@ 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_object (&self->monitor); g_clear_pointer (&self->disabled_until_tmw_dt, g_date_time_unref); if (self->validate_id > 0) { @@ -658,7 +438,6 @@ gsd_night_light_finalize (GObject *object) self->validate_id = 0; } - g_clear_object (&self->location_settings); G_OBJECT_CLASS (gsd_night_light_parent_class)->finalize (object); } @@ -671,12 +450,6 @@ gsd_night_light_set_property (GObject *object, 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; @@ -703,12 +476,6 @@ gsd_night_light_get_property (GObject *object, 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_sunset); - break; case PROP_TEMPERATURE: g_value_set_double (value, self->cached_temperature); break; @@ -740,26 +507,6 @@ gsd_night_light_class_init (GsdNightLightClass *klass) 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", @@ -791,17 +538,18 @@ gsd_night_light_class_init (GsdNightLightClass *klass) 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"); + self->monitor = gsd_location_monitor_get (); } GsdNightLight * -gsd_night_light_new (void) +gsd_night_light_new () { - return g_object_new (GSD_TYPE_NIGHT_LIGHT, NULL); + GsdNightLight *self; + + self = g_object_new (GSD_TYPE_NIGHT_LIGHT, NULL); + + return self; } diff --git a/plugins/color/gsd-night-light.h b/plugins/color/gsd-night-light.h index 8803c3385..1b0cece6c 100644 --- a/plugins/color/gsd-night-light.h +++ b/plugins/color/gsd-night-light.h @@ -23,6 +23,8 @@ #include +#include "gsd-location-monitor.h" + G_BEGIN_DECLS #define GSD_TYPE_NIGHT_LIGHT (gsd_night_light_get_type ()) @@ -33,10 +35,9 @@ gboolean gsd_night_light_start (GsdNightLight *self, GError **error); gboolean gsd_night_light_get_active (GsdNightLight *self); -gdouble gsd_night_light_get_sunrise (GsdNightLight *self); -gdouble gsd_night_light_get_sunset (GsdNightLight *self); gdouble gsd_night_light_get_temperature (GsdNightLight *self); + gboolean gsd_night_light_get_disabled_until_tmw (GsdNightLight *self); void gsd_night_light_set_disabled_until_tmw (GsdNightLight *self, gboolean value); @@ -45,11 +46,10 @@ gboolean gsd_night_light_get_forced (GsdNightLight *self); void gsd_night_light_set_forced (GsdNightLight *self, gboolean value); +void gsd_night_light_recheck_schedule (GsdNightLight *self); +void gsd_night_light_recheck_immediate (GsdNightLight *self); + /* only for the self test program */ -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); diff --git a/plugins/color/meson.build b/plugins/color/meson.build index 1c5be07f4..25ed8ce53 100644 --- a/plugins/color/meson.build +++ b/plugins/color/meson.build @@ -3,6 +3,7 @@ sources = files( 'gsd-color-calibrate.c', 'gsd-color-manager.c', 'gsd-color-state.c', + 'gsd-location-monitor.c', 'gsd-night-light.c', 'gsd-night-light-common.c', 'main.c' @@ -33,6 +34,7 @@ executable( sources = files( 'gcm-self-test.c', 'gnome-datetime-source.c', + 'gsd-location-monitor.c', 'gsd-night-light.c', 'gsd-night-light-common.c' ) -- GitLab From 78e9b48f89e208a82c7dbd831c7fe9b040e203f6 Mon Sep 17 00:00:00 2001 From: Jamie Murphy Date: Fri, 31 Oct 2025 13:06:51 -0700 Subject: [PATCH 2/2] color: Add ColorScheme Create a ColorScheme object that work to adjust the system colour scheme on timer. Fixes #788 --- ...ttings-daemon.plugins.color.gschema.xml.in | 20 ++ gnome-settings-daemon/org.gnome.Shell.xml | 1 + plugins/color/gcm-self-test.c | 124 ++++++++++ plugins/color/gsd-color-manager.c | 37 +++ plugins/color/gsd-color-scheme.c | 220 ++++++++++++++++++ plugins/color/gsd-color-scheme.h | 40 ++++ plugins/color/meson.build | 3 + 7 files changed, 445 insertions(+) create mode 100644 plugins/color/gsd-color-scheme.c create mode 100644 plugins/color/gsd-color-scheme.h diff --git a/data/org.gnome.settings-daemon.plugins.color.gschema.xml.in b/data/org.gnome.settings-daemon.plugins.color.gschema.xml.in index 286ea8086..135f6ff72 100644 --- a/data/org.gnome.settings-daemon.plugins.color.gschema.xml.in +++ b/data/org.gnome.settings-daemon.plugins.color.gschema.xml.in @@ -16,6 +16,11 @@ If the night light mode is enabled Night light mode changes the color temperature of your display when the sun has gone down or at preset times. + + false + If the color scheme scheduling is enabled + Color scheme scheduling mode changes the system theme to dark when the sun has gone down or at preset times. + 2700 Temperature of the display when enabled @@ -26,16 +31,31 @@ Use the sunrise and sunset Calculate the sunrise and sunset times automatically, from the current location. + + true + Use the sunrise and sunset + Calculate the sunrise and sunset times automatically, from the current location. + 20.00 The start time When “night-light-schedule-automatic” is disabled, use this start time in hours from midnight. + + 20.00 + The start time + When “color-scheme-schedule-automatic” is disabled, use this start time in hours from midnight. + 6.00 The end time When “night-light-schedule-automatic” is disabled, use this end time in hours from midnight. + + 6.00 + The end time + When “color-scheme-schedule-automatic” is disabled, use this end time in hours from midnight. + (91,181) The last detected position diff --git a/gnome-settings-daemon/org.gnome.Shell.xml b/gnome-settings-daemon/org.gnome.Shell.xml index 1845ddef4..342024bd5 100644 --- a/gnome-settings-daemon/org.gnome.Shell.xml +++ b/gnome-settings-daemon/org.gnome.Shell.xml @@ -30,5 +30,6 @@ + diff --git a/plugins/color/gcm-self-test.c b/plugins/color/gcm-self-test.c index 249f7a862..a4ef0f36f 100644 --- a/plugins/color/gcm-self-test.c +++ b/plugins/color/gcm-self-test.c @@ -21,11 +21,13 @@ #include "config.h" +#include #include #include #include #include "gsd-color-state.h" +#include "gsd-color-scheme.h" #include "gsd-location-monitor.h" #include "gsd-night-light.h" #include "gsd-night-light-common.h" @@ -98,6 +100,127 @@ gcm_test_location_monitor (void) g_settings_reset (settings, "night-light-last-coordinates"); } +static void +gcm_test_color_scheme (void) +{ + gboolean ret; + guint sunrise_cnt = 0; + guint sunset_cnt = 0; + g_autoptr(GDateTime) datetime_override = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GsdColorScheme) color_scheme = NULL; + g_autoptr(GsdLocationMonitor) monitor = NULL; + g_autoptr(GSettings) settings = NULL; + g_autoptr(GSettings) scheme_settings = NULL; + + monitor = gsd_location_monitor_get (); + g_assert (GSD_IS_LOCATION_MONITOR (monitor)); + g_signal_connect (monitor, "notify::sunset", + G_CALLBACK (on_notify), &sunset_cnt); + g_signal_connect (monitor, "notify::sunrise", + G_CALLBACK (on_notify), &sunrise_cnt); + + color_scheme = gsd_color_scheme_new (); + g_assert (GSD_IS_COLOR_SCHEME (color_scheme)); + + /* hardcode a specific date and time */ + datetime_override = g_date_time_new_utc (2017, 2, 8, 20, 0, 0); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_color_scheme_recheck_immediate (color_scheme); + + /* do not start geoclue */ + gsd_location_monitor_set_geoclue_enabled (monitor, FALSE); + + /* switch off */ + settings = g_settings_new ("org.gnome.settings-daemon.plugins.color"); + scheme_settings = g_settings_new ("org.gnome.desktop.interface"); + g_settings_set_boolean (settings, "color-scheme-enabled", FALSE); + g_settings_set_enum (scheme_settings, "color-scheme", G_DESKTOP_COLOR_SCHEME_PREFER_DARK); + + /* start module, disabled */ + ret = gsd_location_monitor_start (monitor, &error); + g_assert_no_error (error); + g_assert (ret); + ret = gsd_color_scheme_start (color_scheme, &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpint (sunset_cnt, ==, 0); + g_assert_cmpint (sunrise_cnt, ==, 0); + + /* enable automatic mode */ + g_settings_set_value (settings, "night-light-last-coordinates", + g_variant_new ("(dd)", 51.5, -0.1278)); + g_settings_set_boolean (settings, "color-scheme-schedule-automatic", TRUE); + g_settings_set_boolean (settings, "color-scheme-enabled", TRUE); + g_assert_cmpint (sunset_cnt, ==, 1); + g_assert_cmpint (sunrise_cnt, ==, 1); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunrise (monitor), ==, 7); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunset (monitor), ==, 17); + g_assert_cmpint ((gint) g_settings_get_enum (scheme_settings, "color-scheme"), ==, 1); // Dark + + /* enabled manual mode */ + g_settings_set_double (settings, "color-scheme-schedule-from", 4.0); + g_settings_set_double (settings, "color-scheme-schedule-to", 16.f); + g_settings_set_boolean (settings, "color-scheme-schedule-automatic", FALSE); + g_assert_cmpint (sunset_cnt, ==, 1); + g_assert_cmpint (sunrise_cnt, ==, 1); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunrise (monitor), ==, 7); + g_assert_cmpint ((gint) gsd_location_monitor_get_sunset (monitor), ==, 17); + g_assert_cmpint ((gint) g_settings_get_enum (scheme_settings, "color-scheme"), ==, 0); // Light + + /* disable, with no changes */ + g_settings_set_boolean (settings, "color-scheme-enabled", FALSE); + g_assert_cmpint (sunset_cnt, ==, 1); + g_assert_cmpint (sunrise_cnt, ==, 1); + g_assert_cmpint ((gint) g_settings_get_enum (scheme_settings, "color-scheme"), ==, 0); // Light + + g_clear_pointer (&datetime_override, g_date_time_unref); + datetime_override = g_date_time_new_utc (2017, 2, 9, 5, 0, 0); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_color_scheme_recheck_immediate (color_scheme); + g_assert_cmpint ((gint) g_settings_get_enum (scheme_settings, "color-scheme"), ==, 0); // Light + + /* enable and adjust schedule */ + g_settings_set_boolean (settings, "color-scheme-enabled", TRUE); + + /* Now, sleep for a bit (we need some time to actually update) */ + g_timeout_add (1000, quit_mainloop, NULL); + g_main_loop_run (mainloop); + + g_assert_cmpint ((gint) g_settings_get_enum (scheme_settings, "color-scheme"), ==, 1); // Dark + + /* adjust schedule again */ + g_clear_pointer (&datetime_override, g_date_time_unref); + datetime_override = g_date_time_new_utc (2017, 2, 8, 10, 00, 00); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_color_scheme_recheck_immediate (color_scheme); + g_timeout_add (1000, quit_mainloop, NULL); + g_main_loop_run (mainloop); + g_assert_cmpint ((gint) g_settings_get_enum (scheme_settings, "color-scheme"), ==, 1); // Dark + + /* Check that we are always dark if from/to are equal */ + g_settings_set_double (settings, "color-scheme-schedule-from", 6.0); + g_settings_set_double (settings, "color-scheme-schedule-to", 6.0); + + datetime_override = g_date_time_new_utc (2017, 2, 8, 5, 50, 0); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_color_scheme_recheck_immediate (color_scheme); + g_assert_cmpint ((gint) g_settings_get_enum (scheme_settings, "color-scheme"), ==, 1); // Dark + + datetime_override = g_date_time_new_utc (2017, 2, 8, 6, 0, 0); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_color_scheme_recheck_immediate (color_scheme); + g_assert_cmpint ((gint) g_settings_get_enum (scheme_settings, "color-scheme"), ==, 1); // Dark + + datetime_override = g_date_time_new_utc (2017, 2, 8, 6, 10, 0); + gsd_location_monitor_set_date_time_now (monitor, datetime_override); + gsd_color_scheme_recheck_immediate (color_scheme); + g_assert_cmpint ((gint) g_settings_get_enum (scheme_settings, "color-scheme"), ==, 1); // Dark + + /* reset coordinates */ + g_settings_reset (settings, "night-light-last-coordinates"); +} + static void gcm_test_night_light (void) { @@ -428,6 +551,7 @@ main (int argc, char **argv) g_test_add_func ("/color/fractional-day", gcm_test_frac_day); g_test_add_func ("/color/location-monitor", gcm_test_location_monitor); g_test_add_func ("/color/night-light", gcm_test_night_light); + g_test_add_func ("/color/color-scheme", gcm_test_color_scheme); return g_test_run (); } diff --git a/plugins/color/gsd-color-manager.c b/plugins/color/gsd-color-manager.c index ab12301eb..ab355de0e 100644 --- a/plugins/color/gsd-color-manager.c +++ b/plugins/color/gsd-color-manager.c @@ -29,10 +29,13 @@ #include "gnome-settings-profile.h" #include "gsd-color-calibrate.h" #include "gsd-color-manager.h" +#include "gsd-color-scheme.h" #include "gsd-color-state.h" #include "gsd-night-light-common.h" #include "gsd-location-monitor.h" #include "gsd-night-light.h" +#include "gsd-shell-helper.h" +#include "gnome-settings-bus.h" #define GSD_DBUS_NAME "org.gnome.SettingsDaemon" #define GSD_DBUS_PATH "/org/gnome/SettingsDaemon" @@ -67,6 +70,8 @@ struct _GsdColorManager GsdColorState *state; GsdLocationMonitor *monitor; GsdNightLight *nlight; + GsdColorScheme *color_scheme; + GsdShell *shell_proxy; guint nlight_forced_timeout_id; GSource *source; @@ -114,6 +119,10 @@ gsd_color_manager_startup (GApplication *app) if (!gsd_night_light_start (manager->nlight, &error)) g_warning ("Could not start night light module: %s", error->message); + /* setup color scheme module */ + if (!gsd_color_scheme_start (manager->color_scheme, &error)) + g_warning ("Could not start color scheme module: %s", error->message); + G_APPLICATION_CLASS (gsd_color_manager_parent_class)->startup (app); gnome_settings_profile_end (NULL); @@ -243,6 +252,7 @@ color_recheck_cb (gpointer user_data) /* recheck individual components */ gsd_night_light_recheck_immediate (manager->nlight); + gsd_color_scheme_recheck_immediate (manager->color_scheme); poll_timeout_destroy (manager); poll_timeout_create (manager); @@ -251,6 +261,22 @@ color_recheck_cb (gpointer user_data) return G_SOURCE_REMOVE; } +static void +on_scheme_switched (GsdColorScheme *color_scheme, + gpointer user_data) +{ + GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); + g_autoptr(GError) error = NULL; + + if (manager->shell_proxy == NULL) + return; + + gsd_shell_call_screen_transition_sync (manager->shell_proxy, NULL, &error); + + if (error) + g_warning ("Couldn't transition screen: %s", error->message); +} + static void poll_timeout_create (GsdColorManager *self) { @@ -285,6 +311,8 @@ poll_timeout_destroy (GsdColorManager *manager) static void gsd_color_manager_init (GsdColorManager *manager) { + manager->shell_proxy = gnome_settings_bus_get_shell_proxy (); + /* setup calibration features */ manager->calibrate = gsd_color_calibrate_new (manager); manager->state = gsd_color_state_new (); @@ -304,6 +332,13 @@ gsd_color_manager_init (GsdColorManager *manager) G_CALLBACK (on_temperature_notify), manager); g_signal_connect (manager->nlight, "notify::disabled-until-tmw", G_CALLBACK (on_disabled_until_tmw_notify), manager); + + /* color scheme features */ + manager->color_scheme = gsd_color_scheme_new (); + g_signal_connect (manager->color_scheme, "scheme-switched", + G_CALLBACK (on_scheme_switched), manager); + + poll_timeout_create (manager); } static void @@ -322,6 +357,8 @@ gsd_color_manager_finalize (GObject *object) g_clear_object (&manager->state); g_clear_object (&manager->monitor); g_clear_object (&manager->nlight); + g_clear_object (&manager->color_scheme); + g_clear_object (&manager->shell_proxy); G_OBJECT_CLASS (gsd_color_manager_parent_class)->finalize (object); } diff --git a/plugins/color/gsd-color-scheme.c b/plugins/color/gsd-color-scheme.c new file mode 100644 index 000000000..291ce7f31 --- /dev/null +++ b/plugins/color/gsd-color-scheme.c @@ -0,0 +1,220 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2024-2025 Jamie Murphy + * + * 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, see . + */ + +#include "config.h" + +#include + +#include "gsd-color-scheme.h" +#include "gsd-night-light-common.h" +#include "gsd-location-monitor.h" + +struct _GsdColorScheme { + GObject parent; + + GSettings *settings; + GSettings *interface_settings; + + guint validate_id; + + GsdLocationMonitor *monitor; +}; + +enum { + SCHEME_SWITCHED, + SIGNAL_LAST +}; + +static guint signals[SIGNAL_LAST] = { 0, }; + +#define GSD_COLOR_SCHEME_SCHEDULE_TIMEOUT 5 /* seconds */ + +G_DEFINE_TYPE (GsdColorScheme, gsd_color_scheme, G_TYPE_OBJECT); + +static void color_scheme_recheck (GsdColorScheme *self); + +void +gsd_color_scheme_recheck_immediate (GsdColorScheme *self) +{ + color_scheme_recheck (self); +} + +static void +set_scheme (GsdColorScheme *self, + gboolean scheme_is_dark) +{ + GDesktopColorScheme system_scheme; + GDesktopColorScheme new_scheme; + + system_scheme = g_settings_get_enum (self->interface_settings, "color-scheme"); + + if (scheme_is_dark) + new_scheme = G_DESKTOP_COLOR_SCHEME_PREFER_DARK; + else + new_scheme = G_DESKTOP_COLOR_SCHEME_DEFAULT; + + /* Don't needlessly transition */ + if (system_scheme == new_scheme) + return; + + g_debug ("Changing scheme from %i to %i (0 = light, 1 = dark)", system_scheme, new_scheme); + + g_signal_emit (G_OBJECT (self), signals[SCHEME_SWITCHED], 0); + + g_settings_set_enum (self->interface_settings, "color-scheme", new_scheme); +} + +static void +color_scheme_recheck (GsdColorScheme *self) +{ + gdouble frac_day; + gdouble schedule_from = -1.f; + gdouble schedule_to = -1.f; + g_autoptr(GDateTime) dt_now = gsd_location_monitor_get_date_time_now (self->monitor); + + /* enabled */ + if (!g_settings_get_boolean (self->settings, "color-scheme-enabled")) { + g_debug ("color scheme disabled"); + return; + } + + /* calculate the position of the sun */ + if (g_settings_get_boolean (self->settings, "color-scheme-schedule-automatic")) { + gdouble cached_sunrise = gsd_location_monitor_get_sunrise (self->monitor); + gdouble cached_sunset = gsd_location_monitor_get_sunset (self->monitor); + + if (cached_sunrise > 0.f && cached_sunset > 0.f) { + schedule_to = cached_sunrise; + schedule_from = cached_sunset; + } + } + + /* fall back to manual settings */ + if (schedule_to <= 0.f || schedule_from <= 0.f) { + schedule_from = g_settings_get_double (self->settings, + "color-scheme-schedule-from"); + schedule_to = g_settings_get_double (self->settings, + "color-scheme-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); + + if (!gsd_night_light_frac_day_is_between (frac_day, + schedule_from, + schedule_to)) { + set_scheme (self, FALSE); + return; + } + + set_scheme (self, TRUE); +} + +static gboolean +color_scheme_recheck_schedule_cb (gpointer user_data) +{ + GsdColorScheme *self = GSD_COLOR_SCHEME (user_data); + color_scheme_recheck (self); + self->validate_id = 0; + return G_SOURCE_REMOVE; +} + +/* called when location monitor updates */ +void +gsd_color_scheme_recheck_schedule (GsdColorScheme *self) +{ + if (self->validate_id != 0) + g_source_remove (self->validate_id); + self->validate_id = + g_timeout_add_seconds (GSD_COLOR_SCHEME_SCHEDULE_TIMEOUT, + color_scheme_recheck_schedule_cb, + self); +} + +static void +settings_changed_cb (GSettings *settings, gchar *key, gpointer user_data) +{ + GsdColorScheme *self = GSD_COLOR_SCHEME (user_data); + g_debug ("settings changed"); + + if (g_settings_get_boolean (self->settings, "color-scheme-schedule-automatic")) + g_signal_connect (G_OBJECT (self->monitor), "changed", G_CALLBACK (color_scheme_recheck), self); + else + g_signal_handlers_disconnect_by_data (self->monitor, self); + + color_scheme_recheck (self); +} + +gboolean +gsd_color_scheme_start (GsdColorScheme *self, GError **error) +{ + color_scheme_recheck (self); + + /* care about changes */ + g_signal_connect (self->settings, "changed", + G_CALLBACK (settings_changed_cb), self); + + return TRUE; +} + +static void +gsd_color_scheme_finalize (GObject *object) +{ + GsdColorScheme *self = GSD_COLOR_SCHEME (object); + + g_clear_object (&self->settings); + g_clear_object (&self->interface_settings); + g_clear_object (&self->monitor); + + G_OBJECT_CLASS (gsd_color_scheme_parent_class)->finalize (object); +} + +static void +gsd_color_scheme_class_init (GsdColorSchemeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gsd_color_scheme_finalize; + + signals[SCHEME_SWITCHED] = + g_signal_new ("scheme-switched", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + +static void +gsd_color_scheme_init (GsdColorScheme *self) +{ + self->settings = g_settings_new ("org.gnome.settings-daemon.plugins.color"); + self->interface_settings = g_settings_new ("org.gnome.desktop.interface"); + self->monitor = gsd_location_monitor_get (); +} + +GsdColorScheme * +gsd_color_scheme_new () +{ + GsdColorScheme *self; + + self = g_object_new (GSD_TYPE_COLOR_SCHEME, NULL); + + return self; +} \ No newline at end of file diff --git a/plugins/color/gsd-color-scheme.h b/plugins/color/gsd-color-scheme.h new file mode 100644 index 000000000..dd8f640d9 --- /dev/null +++ b/plugins/color/gsd-color-scheme.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2024-2025 Jamie Murphy + * + * 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, see . + */ + +#ifndef __GSD_COLOR_SCHEME_H__ +#define __GSD_COLOR_SCHEME_H__ + +#include + +#include "gsd-location-monitor.h" + +G_BEGIN_DECLS + +#define GSD_TYPE_COLOR_SCHEME (gsd_color_scheme_get_type ()) +G_DECLARE_FINAL_TYPE (GsdColorScheme, gsd_color_scheme, GSD, COLOR_SCHEME, GObject) + +GsdColorScheme *gsd_color_scheme_new (void); +gboolean gsd_color_scheme_start (GsdColorScheme *self, + GError **error); + +void gsd_color_scheme_recheck_schedule (GsdColorScheme *self); +void gsd_color_scheme_recheck_immediate (GsdColorScheme *self); + +G_END_DECLS + +#endif /* __GSD_COLOR_SCHEME_H__ */ \ No newline at end of file diff --git a/plugins/color/meson.build b/plugins/color/meson.build index 25ed8ce53..e919c0392 100644 --- a/plugins/color/meson.build +++ b/plugins/color/meson.build @@ -2,6 +2,7 @@ sources = files( 'gnome-datetime-source.c', 'gsd-color-calibrate.c', 'gsd-color-manager.c', + 'gsd-color-scheme.c', 'gsd-color-state.c', 'gsd-location-monitor.c', 'gsd-night-light.c', @@ -12,6 +13,7 @@ sources += main_helper_sources deps = plugins_deps + [ colord_dep, + gsettings_desktop_dep, libgeoclue_dep, libnotify_dep, libcommon_dep, @@ -34,6 +36,7 @@ executable( sources = files( 'gcm-self-test.c', 'gnome-datetime-source.c', + 'gsd-color-scheme.c', 'gsd-location-monitor.c', 'gsd-night-light.c', 'gsd-night-light-common.c' -- GitLab