/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2011-2013 Richard Hughes * * 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 #include #include #include "gnome-settings-profile.h" #include "gsd-color-calibrate.h" #include "gsd-color-manager.h" #include "gsd-color-state.h" #include "gsd-night-light.h" #define GSD_DBUS_NAME "org.gnome.SettingsDaemon" #define GSD_DBUS_PATH "/org/gnome/SettingsDaemon" #define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon" #define GSD_COLOR_DBUS_NAME GSD_DBUS_NAME ".Color" #define GSD_COLOR_DBUS_PATH GSD_DBUS_PATH "/Color" #define GSD_COLOR_DBUS_INTERFACE GSD_DBUS_BASE_INTERFACE ".Color" static const gchar introspection_xml[] = "" " " " " " " " " " " " " " " " " " " " " ""; struct _GsdColorManager { GObject parent; /* D-Bus */ guint name_id; GDBusNodeInfo *introspection_data; GDBusConnection *connection; GCancellable *bus_cancellable; GsdColorCalibrate *calibrate; GsdColorState *state; GsdNightLight *nlight; guint nlight_forced_timeout_id; }; enum { PROP_0, }; 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); G_DEFINE_TYPE (GsdColorManager, gsd_color_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; GQuark gsd_color_manager_error_quark (void) { static GQuark quark = 0; if (!quark) quark = g_quark_from_static_string ("gsd_color_manager_error"); return quark; } gboolean gsd_color_manager_start (GsdColorManager *manager, GError **error) { g_debug ("Starting color manager"); gnome_settings_profile_start (NULL); /* start the device probing */ gsd_color_state_start (manager->state); gnome_settings_profile_end (NULL); return TRUE; } void gsd_color_manager_stop (GsdColorManager *manager) { g_debug ("Stopping color manager"); gsd_color_state_stop (manager->state); } static void gsd_color_manager_class_init (GsdColorManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gsd_color_manager_finalize; } static void emit_property_changed (GsdColorManager *manager, const gchar *property_name, GVariant *property_value) { GVariantBuilder builder; GVariantBuilder invalidated_builder; /* not yet connected */ if (manager->connection == NULL) return; /* build the dict */ g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); g_variant_builder_add (&builder, "{sv}", property_name, property_value); g_dbus_connection_emit_signal (manager->connection, NULL, GSD_COLOR_DBUS_PATH, "org.freedesktop.DBus.Properties", "PropertiesChanged", g_variant_new ("(sa{sv}as)", GSD_COLOR_DBUS_INTERFACE, &builder, &invalidated_builder), NULL); g_variant_builder_clear (&builder); g_variant_builder_clear (&invalidated_builder); } static void on_active_notify (GsdNightLight *nlight, GParamSpec *pspec, gpointer user_data) { GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); emit_property_changed (manager, "NightLightActive", g_variant_new_boolean (gsd_night_light_get_active (manager->nlight))); } static void on_sunset_notify (GsdNightLight *nlight, GParamSpec *pspec, gpointer user_data) { GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); emit_property_changed (manager, "Sunset", g_variant_new_double (gsd_night_light_get_sunset (manager->nlight))); } static void on_sunrise_notify (GsdNightLight *nlight, GParamSpec *pspec, gpointer user_data) { GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); emit_property_changed (manager, "Sunrise", g_variant_new_double (gsd_night_light_get_sunrise (manager->nlight))); } static void on_disabled_until_tmw_notify (GsdNightLight *nlight, GParamSpec *pspec, gpointer user_data) { GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); emit_property_changed (manager, "DisabledUntilTomorrow", g_variant_new_boolean (gsd_night_light_get_disabled_until_tmw (manager->nlight))); } static void on_temperature_notify (GsdNightLight *nlight, GParamSpec *pspec, gpointer user_data) { GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); gdouble temperature = gsd_night_light_get_temperature (manager->nlight); gsd_color_state_set_temperature (manager->state, temperature); emit_property_changed (manager, "Temperature", g_variant_new_uint32 (roundf (temperature))); } static void gsd_color_manager_init (GsdColorManager *manager) { /* setup calibration features */ manager->calibrate = gsd_color_calibrate_new (); manager->state = gsd_color_state_new (); /* 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", G_CALLBACK (on_disabled_until_tmw_notify), manager); } static void gsd_color_manager_finalize (GObject *object) { GsdColorManager *manager; g_return_if_fail (object != NULL); g_return_if_fail (GSD_IS_COLOR_MANAGER (object)); manager = GSD_COLOR_MANAGER (object); gsd_color_manager_stop (manager); if (manager->bus_cancellable != NULL) { g_cancellable_cancel (manager->bus_cancellable); g_clear_object (&manager->bus_cancellable); } g_clear_pointer (&manager->introspection_data, g_dbus_node_info_unref); g_clear_object (&manager->connection); if (manager->name_id != 0) { g_bus_unown_name (manager->name_id); manager->name_id = 0; } if (manager->nlight_forced_timeout_id) g_source_remove (manager->nlight_forced_timeout_id); g_clear_object (&manager->calibrate); g_clear_object (&manager->state); g_clear_object (&manager->nlight); G_OBJECT_CLASS (gsd_color_manager_parent_class)->finalize (object); } static gboolean nlight_forced_timeout_cb (gpointer user_data) { GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); manager->nlight_forced_timeout_id = 0; gsd_night_light_set_forced (manager->nlight, FALSE); return G_SOURCE_REMOVE; } static void handle_method_call (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); if (g_strcmp0 (method_name, "NightLightPreview") == 0) { guint32 duration = 0; if (!manager->nlight) { g_dbus_method_invocation_return_error_literal (invocation, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED, "Night-light is currently unavailable"); return; } g_variant_get (parameters, "(u)", &duration); if (duration == 0 || duration > 120) { g_dbus_method_invocation_return_error_literal (invocation, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Duration is out of the range (0-120]."); return; } if (manager->nlight_forced_timeout_id) g_source_remove (manager->nlight_forced_timeout_id); manager->nlight_forced_timeout_id = g_timeout_add_seconds (duration, nlight_forced_timeout_cb, manager); gsd_night_light_set_forced (manager->nlight, TRUE); g_dbus_method_invocation_return_value (invocation, NULL); } else { g_assert_not_reached (); } } static GVariant * handle_get_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data) { GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); if (g_strcmp0 (interface_name, GSD_COLOR_DBUS_INTERFACE) != 0) { g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such interface: %s", interface_name); return NULL; } if (g_strcmp0 (property_name, "NightLightActive") == 0) return g_variant_new_boolean (gsd_night_light_get_active (manager->nlight)); if (g_strcmp0 (property_name, "Temperature") == 0) { guint temperature; temperature = gsd_color_state_get_temperature (manager->state); return g_variant_new_uint32 (temperature); } if (g_strcmp0 (property_name, "DisabledUntilTomorrow") == 0) 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)); if (g_strcmp0 (property_name, "Sunset") == 0) return g_variant_new_double (gsd_night_light_get_sunset (manager->nlight)); g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Failed to get property: %s", property_name); return NULL; } static gboolean handle_set_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GVariant *value, GError **error, gpointer user_data) { GsdColorManager *manager = GSD_COLOR_MANAGER (user_data); if (g_strcmp0 (interface_name, GSD_COLOR_DBUS_INTERFACE) != 0) { g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such interface: %s", interface_name); return FALSE; } if (g_strcmp0 (property_name, "Temperature") == 0) { guint32 temperature; g_variant_get (value, "u", &temperature); if (temperature < GSD_COLOR_TEMPERATURE_MIN) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "%" G_GUINT32_FORMAT "K is < min %" G_GUINT32_FORMAT "K", temperature, GSD_COLOR_TEMPERATURE_MIN); return FALSE; } if (temperature > GSD_COLOR_TEMPERATURE_MAX) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "%" G_GUINT32_FORMAT "K is > max %" G_GUINT32_FORMAT "K", temperature, GSD_COLOR_TEMPERATURE_MAX); return FALSE; } gsd_color_state_set_temperature (manager->state, temperature); return TRUE; } if (g_strcmp0 (property_name, "DisabledUntilTomorrow") == 0) { gsd_night_light_set_disabled_until_tmw (manager->nlight, g_variant_get_boolean (value)); return TRUE; } g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such property: %s", property_name); return FALSE; } static const GDBusInterfaceVTable interface_vtable = { handle_method_call, handle_get_property, handle_set_property }; static void name_lost_handler_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { g_debug ("lost name, so exiting"); gtk_main_quit (); } static void on_bus_gotten (GObject *source_object, GAsyncResult *res, GsdColorManager *manager) { GDBusConnection *connection; GError *error = NULL; connection = g_bus_get_finish (res, &error); if (connection == NULL) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning ("Could not get session bus: %s", error->message); g_error_free (error); return; } manager->connection = connection; g_dbus_connection_register_object (connection, GSD_COLOR_DBUS_PATH, manager->introspection_data->interfaces[0], &interface_vtable, manager, NULL, NULL); manager->name_id = g_bus_own_name_on_connection (connection, GSD_COLOR_DBUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, NULL, name_lost_handler_cb, manager, NULL); /* setup night light module */ if (!gsd_night_light_start (manager->nlight, &error)) { g_warning ("Could not start night light module: %s", error->message); g_error_free (error); } } static void register_manager_dbus (GsdColorManager *manager) { manager->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); g_assert (manager->introspection_data != NULL); manager->bus_cancellable = g_cancellable_new (); g_bus_get (G_BUS_TYPE_SESSION, manager->bus_cancellable, (GAsyncReadyCallback) on_bus_gotten, manager); } GsdColorManager * gsd_color_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (GSD_TYPE_COLOR_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); register_manager_dbus (manager_object); } return GSD_COLOR_MANAGER (manager_object); }