summaryrefslogtreecommitdiffstats
path: root/plugins/color/gsd-color-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/color/gsd-color-manager.c')
-rw-r--r--plugins/color/gsd-color-manager.c491
1 files changed, 491 insertions, 0 deletions
diff --git a/plugins/color/gsd-color-manager.c b/plugins/color/gsd-color-manager.c
new file mode 100644
index 0000000..a9d8f74
--- /dev/null
+++ b/plugins/color/gsd-color-manager.c
@@ -0,0 +1,491 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ * Copyright (C) 2011-2013 Richard Hughes <richard@hughsie.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <math.h>
+
+#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[] =
+"<node>"
+" <interface name='org.gnome.SettingsDaemon.Color'>"
+" <method name='NightLightPreview'>"
+" <arg type='u' name='duration' direction='in'/>"
+" </method>"
+" <property name='NightLightActive' type='b' access='read'/>"
+" <property name='Temperature' type='u' access='readwrite'/>"
+" <property name='DisabledUntilTomorrow' type='b' access='readwrite'/>"
+" <property name='Sunrise' type='d' access='read'/>"
+" <property name='Sunset' type='d' access='read'/>"
+" </interface>"
+"</node>";
+
+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);
+}