[gnome-settings-daemon] color: Add a D-Bus interface to the color panel



commit 20daa3a21aa3b819a28a7148fa43918eae730c65
Author: Richard Hughes <richard hughsie com>
Date:   Wed Jan 25 14:44:29 2017 +0000

    color: Add a D-Bus interface to the color panel
    
    This allow us to set the display temperature whilst still applying a color
    profile. Future patches will set this automatically much like Red Shift.
    
    Resolves: https://bugzilla.gnome.org/show_bug.cgi?id=742149

 plugins/color/gsd-color-manager.c |  178 +++++++++++++++++++++++++++++++++++++
 plugins/color/gsd-color-state.c   |   81 ++++++++++++++---
 plugins/color/gsd-color-state.h   |    7 ++
 3 files changed, 253 insertions(+), 13 deletions(-)
---
diff --git a/plugins/color/gsd-color-manager.c b/plugins/color/gsd-color-manager.c
index 2cf72d2..6a1c745 100644
--- a/plugins/color/gsd-color-manager.c
+++ b/plugins/color/gsd-color-manager.c
@@ -22,6 +22,7 @@
 
 #include <glib/gi18n.h>
 #include <gdk/gdk.h>
+#include <gtk/gtk.h>
 
 #include "gnome-settings-profile.h"
 #include "gsd-color-calibrate.h"
@@ -29,10 +30,31 @@
 #include "gsd-color-profiles.h"
 #include "gsd-color-state.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'>"
+"    <property name='Temperature' type='u' access='readwrite'/>"
+"  </interface>"
+"</node>";
+
 #define GSD_COLOR_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_COLOR_MANAGER, 
GsdColorManagerPrivate))
 
 struct GsdColorManagerPrivate
 {
+        /* D-Bus */
+        guint              name_id;
+        GDBusNodeInfo     *introspection_data;
+        GDBusConnection   *connection;
+        GCancellable      *bus_cancellable;
+
         GsdColorCalibrate *calibrate;
         GsdColorProfiles  *profiles;
         GsdColorState     *state;
@@ -124,6 +146,19 @@ gsd_color_manager_finalize (GObject *object)
 
         gsd_color_manager_stop (manager);
 
+        if (manager->priv->bus_cancellable != NULL) {
+                g_cancellable_cancel (manager->priv->bus_cancellable);
+                g_clear_object (&manager->priv->bus_cancellable);
+        }
+
+        g_clear_pointer (&manager->priv->introspection_data, g_dbus_node_info_unref);
+        g_clear_object (&manager->priv->connection);
+
+        if (manager->priv->name_id != 0) {
+                g_bus_unown_name (manager->priv->name_id);
+                manager->priv->name_id = 0;
+        }
+
         g_clear_object (&manager->priv->calibrate);
         g_clear_object (&manager->priv->profiles);
         g_clear_object (&manager->priv->state);
@@ -131,6 +166,148 @@ gsd_color_manager_finalize (GObject *object)
         G_OBJECT_CLASS (gsd_color_manager_parent_class)->finalize (object);
 }
 
+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)
+{
+        GVariant *retval = NULL;
+        GsdColorManager *manager = GSD_COLOR_MANAGER (user_data);
+        GsdColorManagerPrivate *priv = manager->priv;
+
+        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, "Temperature") == 0) {
+                guint temperature;
+                temperature = gsd_color_state_get_temperature (priv->state);
+                retval = g_variant_new_uint32 (temperature);
+        }
+
+        if (retval == NULL) {
+                g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+                             "Failed to get property: %s", property_name);
+        }
+
+        return retval;
+}
+
+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);
+        GsdColorManagerPrivate *priv = manager->priv;
+
+        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 (priv->state, temperature);
+                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 =
+{
+        NULL,
+        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)
+{
+        GsdColorManagerPrivate *priv = manager->priv;
+        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;
+        }
+
+        priv->connection = connection;
+
+        g_dbus_connection_register_object (connection,
+                                           GSD_COLOR_DBUS_PATH,
+                                           priv->introspection_data->interfaces[0],
+                                           &interface_vtable,
+                                           manager,
+                                           NULL,
+                                           NULL);
+
+        priv->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);
+}
+
+static void
+register_manager_dbus (GsdColorManager *manager)
+{
+        GsdColorManagerPrivate *priv = manager->priv;
+
+        priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+        g_assert (priv->introspection_data != NULL);
+
+        g_bus_get (G_BUS_TYPE_SESSION,
+                   priv->bus_cancellable,
+                   (GAsyncReadyCallback) on_bus_gotten,
+                   manager);
+}
+
 GsdColorManager *
 gsd_color_manager_new (void)
 {
@@ -140,6 +317,7 @@ gsd_color_manager_new (void)
                 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);
diff --git a/plugins/color/gsd-color-state.c b/plugins/color/gsd-color-state.c
index 8778a44..a580633 100644
--- a/plugins/color/gsd-color-state.c
+++ b/plugins/color/gsd-color-state.c
@@ -46,6 +46,8 @@
 #define GSD_DBUS_PATH "/org/gnome/SettingsDaemon"
 #define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon"
 
+static void gcm_session_set_gamma_for_all_devices (GsdColorState *state);
+
 struct GsdColorStatePrivate
 {
         GCancellable    *cancellable;
@@ -56,6 +58,7 @@ struct GsdColorStatePrivate
         GdkWindow       *gdk_window;
         gboolean         session_is_active;
         GHashTable      *device_assign_hash;
+        guint            color_temperature;
 };
 
 static void     gsd_color_state_class_init  (GsdColorStateClass *klass);
@@ -169,6 +172,23 @@ gcm_session_screen_set_icc_profile (GsdColorState *state,
         return TRUE;
 }
 
+void
+gsd_color_state_set_temperature (GsdColorState *state, guint temperature)
+{
+        GsdColorStatePrivate *priv = state->priv;
+        g_return_if_fail (GSD_IS_COLOR_STATE (state));
+        priv->color_temperature = temperature;
+        gcm_session_set_gamma_for_all_devices (state);
+}
+
+guint
+gsd_color_state_get_temperature (GsdColorState *state)
+{
+        GsdColorStatePrivate *priv = state->priv;
+        g_return_val_if_fail (GSD_IS_COLOR_STATE (state), 0);
+        return priv->color_temperature;
+}
+
 static gchar *
 gcm_session_get_output_id (GsdColorState *state, GnomeRROutput *output)
 {
@@ -360,7 +380,7 @@ out:
 }
 
 static GPtrArray *
-gcm_session_generate_vcgt (CdProfile *profile, guint size)
+gcm_session_generate_vcgt (CdProfile *profile, guint color_temperature, guint size)
 {
         GnomeRROutputClutItem *tmp;
         GPtrArray *array = NULL;
@@ -369,6 +389,7 @@ gcm_session_generate_vcgt (CdProfile *profile, guint size)
         guint i;
         cmsHPROFILE lcms_profile;
         CdIcc *icc = NULL;
+        CdColorRGB temp;
 
         /* invalid size */
         if (size == 0)
@@ -387,14 +408,23 @@ gcm_session_generate_vcgt (CdProfile *profile, guint size)
                 goto out;
         }
 
+        /* get the color temperature */
+        if (!cd_color_get_blackbody_rgb (color_temperature, &temp)) {
+                g_warning ("failed to get blackbody for %uK", color_temperature);
+                cd_color_rgb_set (&temp, 1.0, 1.0, 1.0);
+        } else {
+                g_debug ("using VCGT gamma of %uK = %.1f,%.1f,%.1f",
+                         color_temperature, temp.R, temp.G, temp.B);
+        }
+
         /* create array */
         array = g_ptr_array_new_with_free_func (g_free);
         for (i = 0; i < size; i++) {
                 in = (gdouble) i / (gdouble) (size - 1);
                 tmp = g_new0 (GnomeRROutputClutItem, 1);
-                tmp->red = cmsEvalToneCurveFloat(vcgt[0], in) * (gdouble) 0xffff;
-                tmp->green = cmsEvalToneCurveFloat(vcgt[1], in) * (gdouble) 0xffff;
-                tmp->blue = cmsEvalToneCurveFloat(vcgt[2], in) * (gdouble) 0xffff;
+                tmp->red = cmsEvalToneCurveFloat(vcgt[0], in) * temp.R * (gdouble) 0xffff;
+                tmp->green = cmsEvalToneCurveFloat(vcgt[1], in) * temp.G * (gdouble) 0xffff;
+                tmp->blue = cmsEvalToneCurveFloat(vcgt[2], in) * temp.B * (gdouble) 0xffff;
                 g_ptr_array_add (array, tmp);
         }
 out:
@@ -475,6 +505,7 @@ out:
 static gboolean
 gcm_session_device_set_gamma (GnomeRROutput *output,
                               CdProfile *profile,
+                              guint color_temperature,
                               GError **error)
 {
         gboolean ret = FALSE;
@@ -487,7 +518,7 @@ gcm_session_device_set_gamma (GnomeRROutput *output,
                 ret = TRUE;
                 goto out;
         }
-        clut = gcm_session_generate_vcgt (profile, size);
+        clut = gcm_session_generate_vcgt (profile, color_temperature, size);
         if (clut == NULL) {
                 g_set_error_literal (error,
                                      GSD_COLOR_MANAGER_ERROR,
@@ -508,6 +539,7 @@ out:
 
 static gboolean
 gcm_session_device_reset_gamma (GnomeRROutput *output,
+                                guint color_temperature,
                                 GError **error)
 {
         gboolean ret;
@@ -516,6 +548,7 @@ gcm_session_device_reset_gamma (GnomeRROutput *output,
         guint32 value;
         GPtrArray *clut;
         GnomeRROutputClutItem *data;
+        CdColorRGB temp;
 
         /* create a linear ramp */
         g_debug ("falling back to dummy ramp");
@@ -525,12 +558,22 @@ gcm_session_device_reset_gamma (GnomeRROutput *output,
                 ret = TRUE;
                 goto out;
         }
+
+        /* get the color temperature */
+        if (!cd_color_get_blackbody_rgb (color_temperature, &temp)) {
+                g_warning ("failed to get blackbody for %uK", color_temperature);
+                cd_color_rgb_set (&temp, 1.0, 1.0, 1.0);
+        } else {
+                g_debug ("using reset gamma of %uK = %.1f,%.1f,%.1f",
+                         color_temperature, temp.R, temp.G, temp.B);
+        }
+
         for (i = 0; i < size; i++) {
                 value = (i * 0xffff) / (size - 1);
                 data = g_new0 (GnomeRROutputClutItem, 1);
-                data->red = value;
-                data->green = value;
-                data->blue = value;
+                data->red = value * temp.R;
+                data->green = value * temp.G;
+                data->blue = value * temp.B;
                 g_ptr_array_add (clut, data);
         }
 
@@ -669,6 +712,7 @@ gcm_session_device_assign_profile_connect_cb (GObject *object,
         guint brightness_percentage;
         GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data;
         GsdColorState *state = GSD_COLOR_STATE (helper->state);
+        GsdColorStatePrivate *priv = state->priv;
 
         /* get properties */
         ret = cd_profile_connect_finish (profile, res, &error);
@@ -720,6 +764,7 @@ gcm_session_device_assign_profile_connect_cb (GObject *object,
         if (ret) {
                 ret = gcm_session_device_set_gamma (output,
                                                     profile,
+                                                    priv->color_temperature,
                                                     &error);
                 if (!ret) {
                         g_warning ("failed to set %s gamma tables: %s",
@@ -730,6 +775,7 @@ gcm_session_device_assign_profile_connect_cb (GObject *object,
                 }
         } else {
                 ret = gcm_session_device_reset_gamma (output,
+                                                      priv->color_temperature,
                                                       &error);
                 if (!ret) {
                         g_warning ("failed to reset %s gamma tables: %s",
@@ -874,6 +920,7 @@ gcm_session_device_assign_connect_cb (GObject *object,
 
                 /* reset, as we want linear profiles for profiling */
                 ret = gcm_session_device_reset_gamma (output,
+                                                      priv->color_temperature,
                                                       &error);
                 if (!ret) {
                         g_warning ("failed to reset %s gamma tables: %s",
@@ -1201,12 +1248,8 @@ gcm_session_profile_gamma_find_device_cb (GObject *object,
                 g_object_unref (device);
 }
 
-/* We have to reset the gamma tables each time as if the primary output
- * has changed then different crtcs are going to be used.
- * See https://bugzilla.gnome.org/show_bug.cgi?id=660164 for an example */
 static void
-gnome_rr_screen_output_changed_cb (GnomeRRScreen *screen,
-                                   GsdColorState *state)
+gcm_session_set_gamma_for_all_devices (GsdColorState *state)
 {
         GnomeRROutput **outputs;
         GsdColorStatePrivate *priv = state->priv;
@@ -1227,7 +1270,16 @@ gnome_rr_screen_output_changed_cb (GnomeRRScreen *screen,
                                                    gcm_session_profile_gamma_find_device_cb,
                                                    state);
         }
+}
 
+/* We have to reset the gamma tables each time as if the primary output
+ * has changed then different crtcs are going to be used.
+ * See https://bugzilla.gnome.org/show_bug.cgi?id=660164 for an example */
+static void
+gnome_rr_screen_output_changed_cb (GnomeRRScreen *screen,
+                                   GsdColorState *state)
+{
+        gcm_session_set_gamma_for_all_devices (state);
 }
 
 static gboolean
@@ -1448,6 +1500,9 @@ gsd_color_state_init (GsdColorState *state)
                                                           g_free,
                                                           NULL);
 
+        /* default color temperature */
+        priv->color_temperature = GSD_COLOR_TEMPERATURE_DEFAULT;
+
         priv->client = cd_client_new ();
 }
 
diff --git a/plugins/color/gsd-color-state.h b/plugins/color/gsd-color-state.h
index ebe5850..8adb9c5 100644
--- a/plugins/color/gsd-color-state.h
+++ b/plugins/color/gsd-color-state.h
@@ -29,6 +29,10 @@ G_BEGIN_DECLS
 #define GSD_COLOR_STATE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_COLOR_STATE, GsdColorState))
 #define GSD_IS_COLOR_STATE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_COLOR_STATE))
 
+#define GSD_COLOR_TEMPERATURE_MIN               1000    /* Kelvin */
+#define GSD_COLOR_TEMPERATURE_DEFAULT           6500    /* Kelvin, is RGB [1.0,1.0,1.0] */
+#define GSD_COLOR_TEMPERATURE_MAX               10000   /* Kelvin */
+
 typedef struct GsdColorStatePrivate GsdColorStatePrivate;
 
 typedef struct
@@ -48,6 +52,9 @@ GQuark                  gsd_color_state_error_quark     (void);
 GsdColorState *         gsd_color_state_new             (void);
 void                    gsd_color_state_start           (GsdColorState *state);
 void                    gsd_color_state_stop            (GsdColorState *state);
+void                    gsd_color_state_set_temperature (GsdColorState *state,
+                                                         guint temperature);
+guint                   gsd_color_state_get_temperature (GsdColorState *state);
 
 G_END_DECLS
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]