[Xfce4-commits] [xfce/xfce4-settings] 08/37: color: Finalize handling of existing profiles

noreply at xfce.org noreply at xfce.org
Fri Feb 15 00:27:37 CET 2019


This is an automated email from the git hooks/post-receive script.

o   c   h   o   s   i       p   u   s   h   e   d       a       c   o   m   m   i   t       t   o       b   r   a   n   c   h       o   c   h   o   s   i   /   c   o   l   o   r   d   
   in repository xfce/xfce4-settings.

commit 7342b7516e7d863d91f0d34add3d9a1764f40689
Author: Simon Steinbeiß <simon.steinbeiss at tttech.com>
Date:   Mon Feb 4 02:48:13 2019 +0100

    color: Finalize handling of existing profiles
---
 .gitignore                                |   3 +
 dialogs/color-settings/Makefile.am        |   2 +
 dialogs/color-settings/color-device.c     | 363 +++++++++++++++++++
 dialogs/color-settings/color-device.h     |  40 +++
 dialogs/color-settings/color-dialog.glade | 312 +++++++++++------
 dialogs/color-settings/color-profile.c    | 407 ++++++++++++++++++++++
 dialogs/color-settings/color-profile.h    |  42 +++
 dialogs/color-settings/main.c             | 558 +++++++++++++++++++++++++++---
 8 files changed, 1585 insertions(+), 142 deletions(-)

diff --git a/.gitignore b/.gitignore
index 69156f8..5ed1da8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,10 +33,12 @@ ChangeLog
 *.lo
 *.o
 *.stamp
+*.patch
 .libs/
 cov-int/
 dialogs/accessibility-settings/accessibility-dialog_ui.h
 dialogs/appearance-settings/appearance-dialog_ui.h
+dialogs/color-settings/color-dialog_ui.h
 dialogs/display-settings/confirmation-dialog_ui.h
 dialogs/display-settings/display-dialog_ui.h
 dialogs/display-settings/identity-popup_ui.h
@@ -53,6 +55,7 @@ xfce4-settings-*.tar.bz2
 dialogs/accessibility-settings/xfce4-accessibility-settings
 dialogs/accessibility-settings/xfce4-find-cursor
 dialogs/appearance-settings/xfce4-appearance-settings
+dialogs/color-settings/xfce4-color-settings
 dialogs/display-settings/xfce4-display-settings
 dialogs/keyboard-settings/xfce4-keyboard-settings
 dialogs/mime-settings/xfce4-mime-settings
diff --git a/dialogs/color-settings/Makefile.am b/dialogs/color-settings/Makefile.am
index b46c201..8e72ff5 100644
--- a/dialogs/color-settings/Makefile.am
+++ b/dialogs/color-settings/Makefile.am
@@ -11,6 +11,8 @@ bin_PROGRAMS = \
 
 xfce4_color_settings_SOURCES = \
 	main.c \
+	color-device.c \
+	color-profile.c \
 	color-dialog_ui.h
 
 xfce4_color_settings_CFLAGS = \
diff --git a/dialogs/color-settings/color-device.c b/dialogs/color-settings/color-device.c
new file mode 100644
index 0000000..877b77b
--- /dev/null
+++ b/dialogs/color-settings/color-device.c
@@ -0,0 +1,363 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <colord.h>
+#include "color-device.h"
+
+struct _ColorDevice
+{
+  GtkListBoxRow parent_instance;
+
+  CdDevice    *device;
+  gboolean     enabled;
+  gchar       *sortable;
+  GtkWidget   *widget_description;
+  GtkWidget   *widget_switch;
+  guint        device_changed_id;
+};
+
+G_DEFINE_TYPE (ColorDevice, color_device, GTK_TYPE_LIST_BOX_ROW)
+
+enum
+{
+  SIGNAL_ENABLED_CHANGED,
+  SIGNAL_LAST
+};
+
+enum
+{
+  PROP_0,
+  PROP_DEVICE,
+  PROP_LAST
+};
+
+static guint signals [SIGNAL_LAST] = { 0 };
+
+gchar *
+color_device_get_title (CdDevice *device)
+{
+  const gchar *tmp;
+  GString *string;
+
+  string = g_string_new ("");
+
+  /* is laptop panel */
+  if (cd_device_get_kind (device) == CD_DEVICE_KIND_DISPLAY &&
+      cd_device_get_embedded (device))
+    {
+      /* TRANSLATORS: This refers to the TFT display on a laptop */
+      g_string_append (string, _("Laptop Screen"));
+      goto out;
+    }
+
+  /* is internal webcam */
+  if (cd_device_get_kind (device) == CD_DEVICE_KIND_WEBCAM &&
+      cd_device_get_embedded (device))
+    {
+      /* TRANSLATORS: This refers to the embedded webcam on a laptop */
+      g_string_append (string, _("Built-in Webcam"));
+      goto out;
+    }
+
+  /* get the display model, falling back to something sane */
+  tmp = cd_device_get_model (device);
+  if (tmp == NULL)
+    tmp = cd_device_get_vendor (device);
+  if (tmp == NULL)
+    tmp = cd_device_get_id (device);
+
+  switch (cd_device_get_kind (device)) {
+    case CD_DEVICE_KIND_DISPLAY:
+      /* TRANSLATORS: an externally connected display, where %s is either the
+       * model, vendor or ID, e.g. 'LP2480zx Monitor' */
+      g_string_append_printf (string, _("%s Monitor"), tmp);
+      break;
+    case CD_DEVICE_KIND_SCANNER:
+      /* TRANSLATORS: a flatbed scanner device, e.g. 'Epson Scanner' */
+      g_string_append_printf (string, _("%s Scanner"), tmp);
+      break;
+    case CD_DEVICE_KIND_CAMERA:
+      /* TRANSLATORS: a camera device, e.g. 'Nikon D60 Camera' */
+      g_string_append_printf (string, _("%s Camera"), tmp);
+      break;
+    case CD_DEVICE_KIND_PRINTER:
+      /* TRANSLATORS: a printer device, e.g. 'Epson Photosmart Printer' */
+      g_string_append_printf (string, _("%s Printer"), tmp);
+      break;
+    case CD_DEVICE_KIND_WEBCAM:
+      /* TRANSLATORS: a webcam device, e.g. 'Philips HiDef Camera' */
+      g_string_append_printf (string, _("%s Webcam"), tmp);
+      break;
+    default:
+      g_string_append (string, tmp);
+      break;
+  }
+out:
+  return g_string_free (string, FALSE);
+}
+
+static const gchar *
+color_device_kind_to_sort (CdDevice *device)
+{
+  CdDeviceKind kind = cd_device_get_kind (device);
+  if (kind == CD_DEVICE_KIND_DISPLAY)
+    return "4";
+  if (kind == CD_DEVICE_KIND_SCANNER)
+    return "3";
+  if (kind == CD_DEVICE_KIND_CAMERA)
+    return "2";
+  if (kind == CD_DEVICE_KIND_WEBCAM)
+    return "1";
+  if (kind == CD_DEVICE_KIND_PRINTER)
+    return "0";
+  return "9";
+}
+
+gchar *
+color_device_get_sortable_base (CdDevice *device)
+{
+  g_autofree gchar *title = color_device_get_title (device);
+  return g_strdup_printf ("%s-%s-%s",
+                          color_device_kind_to_sort (device),
+                          cd_device_get_id (device),
+                          title);
+}
+
+static void
+color_device_refresh (ColorDevice *color_device)
+{
+  g_autofree gchar *title = NULL;
+  g_autoptr(GPtrArray) profiles = NULL;
+  AtkObject *accessible;
+  g_autofree gchar *name1 = NULL;
+
+  /* add switch and expander if there are profiles, otherwise use a label */
+  profiles = cd_device_get_profiles (color_device->device);
+  if (profiles == NULL)
+    return;
+
+  title = color_device_get_title (color_device->device);
+  gtk_label_set_label (GTK_LABEL (color_device->widget_description), title);
+  gtk_widget_set_visible (color_device->widget_description, TRUE);
+
+  gtk_widget_set_visible (color_device->widget_switch, profiles->len > 0);
+
+  gtk_switch_set_active (GTK_SWITCH (color_device->widget_switch),
+                         cd_device_get_enabled (color_device->device));
+
+  accessible = gtk_widget_get_accessible (color_device->widget_switch);
+  name1 = g_strdup_printf (_("Enable color management for %s"), title);
+  atk_object_set_name (accessible, name1);
+}
+
+CdDevice *
+color_device_get_device (ColorDevice *color_device)
+{
+  g_return_val_if_fail (CC_IS_COLOR_DEVICE (color_device), NULL);
+  return color_device->device;
+}
+
+const gchar *
+color_device_get_sortable (ColorDevice *color_device)
+{
+  g_return_val_if_fail (CC_IS_COLOR_DEVICE (color_device), NULL);
+  return color_device->sortable;
+}
+
+static void
+color_device_get_property (GObject *object, guint param_id,
+                              GValue *value, GParamSpec *pspec)
+{
+  ColorDevice *color_device = CC_COLOR_DEVICE (object);
+  switch (param_id)
+    {
+      case PROP_DEVICE:
+        g_value_set_object (value, color_device->device);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    }
+}
+
+static void
+color_device_set_property (GObject *object, guint param_id,
+                              const GValue *value, GParamSpec *pspec)
+{
+  ColorDevice *color_device = CC_COLOR_DEVICE (object);
+
+  switch (param_id)
+    {
+      case PROP_DEVICE:
+        color_device->device = g_value_dup_object (value);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    }
+}
+
+static void
+color_device_finalize (GObject *object)
+{
+  ColorDevice *color_device = CC_COLOR_DEVICE (object);
+
+  if (color_device->device_changed_id > 0)
+    g_signal_handler_disconnect (color_device->device, color_device->device_changed_id);
+
+  g_free (color_device->sortable);
+  g_object_unref (color_device->device);
+
+  G_OBJECT_CLASS (color_device_parent_class)->finalize (object);
+}
+
+void
+color_device_set_enabled (ColorDevice *color_device,
+                              gboolean enabled)
+{
+  /* same as before */
+  if (color_device->enabled == enabled)
+    return;
+
+  /* refresh */
+  color_device->enabled = enabled;
+
+  g_signal_emit (color_device,
+                 signals[SIGNAL_ENABLED_CHANGED], 0,
+                 color_device->enabled);
+  color_device_refresh (color_device);
+}
+
+static void
+color_device_notify_enable_device_cb (GtkSwitch *sw,
+                                         GParamSpec *pspec,
+                                         gpointer user_data)
+{
+  ColorDevice *color_device = CC_COLOR_DEVICE (user_data);
+  gboolean enable;
+  gboolean ret;
+  g_autoptr(GError) error = NULL;
+
+  enable = gtk_switch_get_active (sw);
+  g_debug ("Set %s to %i", cd_device_get_id (color_device->device), enable);
+  ret = cd_device_set_enabled_sync (color_device->device,
+                                    enable, NULL, &error);
+  if (!ret)
+    g_warning ("failed to %s to the device: %s",
+               enable ? "enable" : "disable", error->message);
+
+  /* if enabled, close */
+  color_device_set_enabled (color_device, enable);
+}
+
+static void
+color_device_changed_cb (CdDevice *device,
+                                   ColorDevice *color_device)
+{
+  color_device_refresh (color_device);
+}
+
+static void
+color_device_constructed (GObject *object)
+{
+  ColorDevice *color_device = CC_COLOR_DEVICE (object);
+  g_autofree gchar *sortable_tmp = NULL;
+
+  /* watch the device for changes */
+  color_device->device_changed_id =
+    g_signal_connect (color_device->device, "changed",
+                      G_CALLBACK (color_device_changed_cb), color_device);
+
+  /* calculate sortable -- FIXME: we have to hack this as EggListBox
+   * does not let us specify a GtkSortType:
+   * https://bugzilla.gnome.org/show_bug.cgi?id=691341 */
+  sortable_tmp = color_device_get_sortable_base (color_device->device);
+  color_device->sortable = g_strdup_printf ("%sXX", sortable_tmp);
+
+  color_device_refresh (color_device);
+
+  /* watch to see if the user flicked the switch */
+  g_signal_connect (G_OBJECT (color_device->widget_switch), "notify::active",
+                    G_CALLBACK (color_device_notify_enable_device_cb),
+                    color_device);
+}
+
+static void
+color_device_class_init (ColorDeviceClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  object_class->get_property = color_device_get_property;
+  object_class->set_property = color_device_set_property;
+  object_class->constructed = color_device_constructed;
+  object_class->finalize = color_device_finalize;
+
+  g_object_class_install_property (object_class, PROP_DEVICE,
+                                   g_param_spec_object ("device", NULL,
+                                                        NULL,
+                                                        CD_TYPE_DEVICE,
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+  signals [SIGNAL_ENABLED_CHANGED] =
+    g_signal_new ("enabled-changed",
+            G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+            0,
+            NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN,
+            G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+}
+
+static void
+color_device_init (ColorDevice *color_device)
+{
+  GtkWidget *box;
+
+  /* description */
+  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 9);
+  color_device->widget_description = gtk_label_new ("");
+  gtk_widget_set_margin_start (color_device->widget_description, 20);
+  gtk_widget_set_margin_top (color_device->widget_description, 12);
+  gtk_widget_set_margin_bottom (color_device->widget_description, 12);
+  gtk_widget_set_halign (color_device->widget_description, GTK_ALIGN_START);
+  gtk_label_set_ellipsize (GTK_LABEL (color_device->widget_description), PANGO_ELLIPSIZE_END);
+  gtk_label_set_xalign (GTK_LABEL (color_device->widget_description), 0);
+  gtk_box_pack_start (GTK_BOX (box), color_device->widget_description, TRUE, TRUE, 0);
+
+  /* switch */
+  color_device->widget_switch = gtk_switch_new ();
+  gtk_widget_set_valign (color_device->widget_switch, GTK_ALIGN_CENTER);
+  gtk_widget_set_margin_end (color_device->widget_switch, 12);
+  gtk_box_pack_start (GTK_BOX (box), color_device->widget_switch, FALSE, FALSE, 0);
+
+  /* refresh */
+  gtk_container_add (GTK_CONTAINER (color_device), box);
+  gtk_widget_set_visible (box, TRUE);
+}
+
+GtkWidget *
+color_device_new (CdDevice *device)
+{
+  return g_object_new (TYPE_COLOR_DEVICE,
+                       "device", device,
+                       NULL);
+}
diff --git a/dialogs/color-settings/color-device.h b/dialogs/color-settings/color-device.h
new file mode 100644
index 0000000..5fc835c
--- /dev/null
+++ b/dialogs/color-settings/color-device.h
@@ -0,0 +1,40 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+#include <colord.h>
+
+G_BEGIN_DECLS
+
+#define TYPE_COLOR_DEVICE (color_device_get_type ())
+G_DECLARE_FINAL_TYPE (ColorDevice, color_device, CC, COLOR_DEVICE, GtkListBoxRow)
+
+gchar   *color_device_get_sortable_base (CdDevice *device);
+gchar   *color_device_get_title         (CdDevice *device);
+GtkWidget   *color_device_new           (CdDevice       *device);
+CdDevice    *color_device_get_device    (ColorDevice  *color_device);
+const gchar *color_device_get_sortable  (ColorDevice  *color_device);
+void         color_device_set_enabled  (ColorDevice  *color_device,
+                                          gboolean        enabled);
+
+G_END_DECLS
diff --git a/dialogs/color-settings/color-dialog.glade b/dialogs/color-settings/color-dialog.glade
index 2dd462e..be203c6 100644
--- a/dialogs/color-settings/color-dialog.glade
+++ b/dialogs/color-settings/color-dialog.glade
@@ -23,41 +23,6 @@
     <property name="icon_name">list-remove-symbolic</property>
     <property name="use_fallback">True</property>
   </object>
-  <object class="GtkAdjustment" id="mouse-emulation-curve">
-    <property name="lower">-1000</property>
-    <property name="upper">1000</property>
-    <property name="step_increment">10</property>
-    <property name="page_increment">100</property>
-  </object>
-  <object class="GtkAdjustment" id="mouse-emulation-delay">
-    <property name="lower">1</property>
-    <property name="upper">1000</property>
-    <property name="value">150</property>
-    <property name="step_increment">10</property>
-    <property name="page_increment">100</property>
-  </object>
-  <object class="GtkAdjustment" id="mouse-emulation-interval">
-    <property name="lower">10</property>
-    <property name="upper">1000</property>
-    <property name="value">20</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">10</property>
-  </object>
-  <object class="GtkAdjustment" id="mouse-emulation-max-speed">
-    <property name="lower">1</property>
-    <property name="upper">2000</property>
-    <property name="value">1000</property>
-    <property name="step_increment">10</property>
-    <property name="page_increment">100</property>
-  </object>
-  <object class="GtkAdjustment" id="mouse-emulation-time-to-max">
-    <property name="lower">100</property>
-    <property name="upper">10000</property>
-    <property name="value">3000</property>
-    <property name="step_increment">10</property>
-    <property name="page_increment">100</property>
-  </object>
-  <object class="GtkListStore" id="profiles"/>
   <object class="XfceTitledDialog" id="dialog">
     <property name="can_focus">False</property>
     <property name="title" translatable="yes">Color Profiles</property>
@@ -79,8 +44,8 @@
             <property name="can_focus">False</property>
             <property name="layout_style">end</property>
             <child>
-              <object class="GtkButton" id="button2">
-                <property name="label">gtk-close</property>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-help</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="receives_default">True</property>
@@ -90,11 +55,12 @@
                 <property name="expand">False</property>
                 <property name="fill">False</property>
                 <property name="position">0</property>
+                <property name="secondary">True</property>
               </packing>
             </child>
             <child>
-              <object class="GtkButton" id="button1">
-                <property name="label">gtk-help</property>
+              <object class="GtkButton" id="button2">
+                <property name="label">gtk-close</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="receives_default">True</property>
@@ -104,7 +70,6 @@
                 <property name="expand">False</property>
                 <property name="fill">False</property>
                 <property name="position">0</property>
-                <property name="secondary">True</property>
               </packing>
             </child>
           </object>
@@ -121,32 +86,18 @@
             <property name="can_focus">False</property>
             <property name="orientation">vertical</property>
             <child>
-              <object class="GtkGrid">
+              <object class="GtkGrid" id="grid">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
+                <property name="hexpand">True</property>
+                <property name="vexpand">True</property>
                 <property name="border_width">6</property>
-                <property name="row_spacing">6</property>
-                <property name="column_spacing">12</property>
-                <child>
-                  <object class="GtkTreeView" id="colord-devices">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="margin_left">12</property>
-                    <property name="model">devices</property>
-                    <child internal-child="selection">
-                      <object class="GtkTreeSelection"/>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">1</property>
-                  </packing>
-                </child>
                 <child>
                   <object class="GtkLabel">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="label" translatable="yes">Devices</property>
+                    <property name="label" translatable="yes"><b>Devices</b></property>
+                    <property name="use_markup">True</property>
                     <property name="xalign">0</property>
                   </object>
                   <packing>
@@ -155,43 +106,49 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkTreeView" id="colord-profiles">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="margin_left">12</property>
-                    <property name="model">profiles</property>
-                    <child internal-child="selection">
-                      <object class="GtkTreeSelection"/>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">4</property>
-                  </packing>
-                </child>
-                <child>
                   <object class="GtkLabel">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="label" translatable="yes">Profiles
-</property>
+                    <property name="margin_top">12</property>
+                    <property name="label" translatable="yes"><b>Profiles</b></property>
+                    <property name="use_markup">True</property>
                     <property name="xalign">0</property>
                   </object>
                   <packing>
                     <property name="left_attach">0</property>
-                    <property name="top_attach">3</property>
+                    <property name="top_attach">2</property>
                   </packing>
                 </child>
                 <child>
                   <object class="GtkBox">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
                     <child>
-                      <object class="GtkButton" id="profile-add">
+                      <object class="GtkBox" id="box-devices">
                         <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">True</property>
-                        <property name="image">image1</property>
+                        <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkFrame" id="frame-devices">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="hexpand">True</property>
+                            <property name="label_xalign">0.5</property>
+                            <property name="shadow_type">in</property>
+                            <child>
+                              <placeholder/>
+                            </child>
+                            <child type="label_item">
+                              <placeholder/>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
                       </object>
                       <packing>
                         <property name="expand">False</property>
@@ -200,11 +157,32 @@
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkButton" id="profile-remove">
+                      <object class="GtkBox" id="label-no-devices">
                         <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">True</property>
-                        <property name="image">image2</property>
+                        <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkLabel" id="label-no-devices-label">
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">False</property>
+                            <property name="margin_left">12</property>
+                            <property name="margin_right">12</property>
+                            <property name="margin_top">12</property>
+                            <property name="margin_bottom">12</property>
+                            <property name="label" translatable="yes"><b>No devices found.</b></property>
+                            <property name="use_markup">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <style>
+                          <class name="view"/>
+                          <class name="frame"/>
+                        </style>
                       </object>
                       <packing>
                         <property name="expand">False</property>
@@ -212,35 +190,134 @@
                         <property name="position">1</property>
                       </packing>
                     </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
                     <child>
-                      <object class="GtkButton" id="make-profile-default">
-                        <property name="label" translatable="yes">Set as default</property>
+                      <object class="GtkBox" id="box-profiles">
                         <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkFrame" id="frame-profiles">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="hexpand">True</property>
+                            <property name="label_xalign">0.5</property>
+                            <property name="shadow_type">in</property>
+                            <child>
+                              <placeholder/>
+                            </child>
+                            <child type="label_item">
+                              <placeholder/>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkBox" id="profiles-toolbar">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkButton" id="profile-add">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="image">image1</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="profile-remove">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="image">image2</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <style>
+                              <class name="inline-toolbar"/>
+                            </style>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
                       </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">True</property>
-                        <property name="pack_type">end</property>
-                        <property name="position">2</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkBox" id="label-no-profiles">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkLabel" id="label-no-profiles-label">
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">False</property>
+                            <property name="margin_left">12</property>
+                            <property name="margin_right">12</property>
+                            <property name="margin_top">12</property>
+                            <property name="margin_bottom">12</property>
+                            <property name="hexpand">True</property>
+                            <property name="label" translatable="yes"><b>No profiles for the selected device.</b></property>
+                            <property name="use_markup">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <style>
+                          <class name="view"/>
+                          <class name="frame"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
                       </packing>
                     </child>
-                    <style>
-                      <class name="inline-toolbar"/>
-                    </style>
                   </object>
                   <packing>
                     <property name="left_attach">0</property>
-                    <property name="top_attach">5</property>
+                    <property name="top_attach">3</property>
                   </packing>
                 </child>
-                <child>
-                  <placeholder/>
-                </child>
               </object>
               <packing>
-                <property name="expand">False</property>
+                <property name="expand">True</property>
                 <property name="fill">True</property>
                 <property name="position">0</property>
               </packing>
@@ -255,10 +332,45 @@
       </object>
     </child>
     <action-widgets>
-      <action-widget response="0">button2</action-widget>
       <action-widget response="-11">button1</action-widget>
+      <action-widget response="0">button2</action-widget>
     </action-widgets>
   </object>
+  <object class="GtkAdjustment" id="mouse-emulation-curve">
+    <property name="lower">-1000</property>
+    <property name="upper">1000</property>
+    <property name="step_increment">10</property>
+    <property name="page_increment">100</property>
+  </object>
+  <object class="GtkAdjustment" id="mouse-emulation-delay">
+    <property name="lower">1</property>
+    <property name="upper">1000</property>
+    <property name="value">150</property>
+    <property name="step_increment">10</property>
+    <property name="page_increment">100</property>
+  </object>
+  <object class="GtkAdjustment" id="mouse-emulation-interval">
+    <property name="lower">10</property>
+    <property name="upper">1000</property>
+    <property name="value">20</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="mouse-emulation-max-speed">
+    <property name="lower">1</property>
+    <property name="upper">2000</property>
+    <property name="value">1000</property>
+    <property name="step_increment">10</property>
+    <property name="page_increment">100</property>
+  </object>
+  <object class="GtkAdjustment" id="mouse-emulation-time-to-max">
+    <property name="lower">100</property>
+    <property name="upper">10000</property>
+    <property name="value">3000</property>
+    <property name="step_increment">10</property>
+    <property name="page_increment">100</property>
+  </object>
+  <object class="GtkListStore" id="profiles"/>
   <object class="GtkAdjustment" id="slow-keys-delay">
     <property name="lower">50</property>
     <property name="upper">1000</property>
diff --git a/dialogs/color-settings/color-profile.c b/dialogs/color-settings/color-profile.c
new file mode 100644
index 0000000..fb87e37
--- /dev/null
+++ b/dialogs/color-settings/color-profile.c
@@ -0,0 +1,407 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "color-profile.h"
+
+struct _ColorProfile
+{
+  GtkListBoxRow parent_instance;
+
+  GtkWidget   *box;
+  CdDevice    *device;
+  CdProfile   *profile;
+  gboolean     is_default;
+  gchar       *sortable;
+  GtkWidget   *widget_description;
+  GtkWidget   *widget_image;
+  GtkWidget   *widget_info;
+  guint        device_changed_id;
+  guint        profile_changed_id;
+};
+
+#define GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD      "recalibrate-printer-threshold"
+#define GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD      "recalibrate-display-threshold"
+
+
+#define IMAGE_WIDGET_PADDING 12
+
+G_DEFINE_TYPE (ColorProfile, color_profile, GTK_TYPE_LIST_BOX_ROW)
+
+enum
+{
+  PROP_0,
+  PROP_DEVICE,
+  PROP_PROFILE,
+  PROP_IS_DEFAULT,
+  PROP_LAST
+};
+
+static gchar *
+color_profile_get_profile_date (CdProfile *profile)
+{
+  gint64 created;
+  g_autoptr(GDateTime) dt = NULL;
+
+  /* get profile age */
+  created = cd_profile_get_created (profile);
+  if (created == 0)
+    return NULL;
+  dt = g_date_time_new_from_unix_utc (created);
+  return g_date_time_format (dt, "%x");
+}
+
+static gchar *
+gcm_prefs_get_profile_title (CdProfile *profile)
+{
+  CdColorspace colorspace;
+  const gchar *tmp;
+  GString *str;
+
+  str = g_string_new ("");
+
+  /* add date only if it's a calibration profile or the profile has
+   * not been tagged with this data */
+  tmp = cd_profile_get_metadata_item (profile, CD_PROFILE_METADATA_DATA_SOURCE);
+  if (tmp == NULL || g_strcmp0 (tmp, CD_PROFILE_METADATA_DATA_SOURCE_CALIB) == 0)
+    {
+      tmp = color_profile_get_profile_date (profile);
+      if (tmp != NULL)
+        g_string_append_printf (str, "%s - ", tmp);
+    }
+  else if (g_strcmp0 (tmp, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0)
+    {
+      /* TRANSLATORS: standard spaces are well known colorspaces like
+       * sRGB, AdobeRGB and ProPhotoRGB */
+      g_string_append_printf (str, "%s - ", _("Standard Space"));
+    }
+  else if (g_strcmp0 (tmp, CD_PROFILE_METADATA_DATA_SOURCE_TEST) == 0)
+    {
+      /* TRANSLATORS: test profiles do things like changing the screen
+       * a different color, or swap the red and green channels */
+      g_string_append_printf (str, "%s - ", _("Test Profile"));
+    }
+  else if (g_strcmp0 (tmp, CD_PROFILE_METADATA_DATA_SOURCE_EDID) == 0)
+    {
+      /* TRANSLATORS: automatic profiles are generated automatically
+       * by the color management system based on manufacturing data,
+       * for instance the default monitor profile is created from the
+       * primaries specified in the monitor EDID */
+      g_string_append_printf (str, "%s - ", C_("Automatically generated profile", "Automatic"));
+    }
+
+  /* add quality if it exists */
+  tmp = cd_profile_get_metadata_item (profile, CD_PROFILE_METADATA_QUALITY);
+  if (g_strcmp0 (tmp, CD_PROFILE_METADATA_QUALITY_LOW) == 0)
+    {
+      /* TRANSLATORS: the profile quality - low quality profiles take
+       * much less time to generate but may be a poor reflection of the
+       * device capability */
+      g_string_append_printf (str, "%s - ", C_("Profile quality", "Low Quality"));
+    }
+  else if (g_strcmp0 (tmp, CD_PROFILE_METADATA_QUALITY_MEDIUM) == 0)
+    {
+      /* TRANSLATORS: the profile quality */
+      g_string_append_printf (str, "%s - ", C_("Profile quality", "Medium Quality"));
+    }
+  else if (g_strcmp0 (tmp, CD_PROFILE_METADATA_QUALITY_HIGH) == 0)
+    {
+      /* TRANSLATORS: the profile quality - high quality profiles take
+       * a *long* time, and have the best calibration and
+       * characterisation data. */
+      g_string_append_printf (str, "%s - ", C_("Profile quality", "High Quality"));
+    }
+
+  /* add profile description */
+  tmp = cd_profile_get_title (profile);
+  if (tmp != NULL)
+    {
+      g_string_append (str, tmp);
+      goto out;
+    }
+
+  /* some meta profiles do not have ICC profiles */
+  colorspace = cd_profile_get_colorspace (profile);
+  if (colorspace == CD_COLORSPACE_RGB)
+    {
+      /* TRANSLATORS: this default RGB space is used for printers that
+       * do not have additional printer profiles specified in the PPD */
+      g_string_append (str, C_("Colorspace fallback", "Default RGB"));
+      goto out;
+    }
+  if (colorspace == CD_COLORSPACE_CMYK)
+    {
+      /* TRANSLATORS: this default CMYK space is used for printers that
+       * do not have additional printer profiles specified in the PPD */
+      g_string_append (str, C_("Colorspace fallback", "Default CMYK"));
+      goto out;
+    }
+  if (colorspace == CD_COLORSPACE_GRAY)
+    {
+      /* TRANSLATORS: this default gray space is used for printers that
+       * do not have additional printer profiles specified in the PPD */
+      g_string_append (str, C_("Colorspace fallback", "Default Gray"));
+      goto out;
+    }
+
+  /* fall back to ID, ick */
+  tmp = g_strdup (cd_profile_get_id (profile));
+  g_string_append (str, tmp);
+out:
+  return g_string_free (str, FALSE);
+}
+
+static void
+color_profile_refresh (ColorProfile *color_profile)
+{
+  g_autofree gchar *title = NULL;
+
+  /* show the image if the profile is default */
+  gtk_widget_set_visible (color_profile->widget_image, color_profile->is_default);
+  gtk_widget_set_margin_start (color_profile->widget_description,
+                              color_profile->is_default ? 0 : IMAGE_WIDGET_PADDING * 4);
+
+  /* set the title */
+  title = gcm_prefs_get_profile_title (color_profile->profile);
+  gtk_label_set_markup (GTK_LABEL (color_profile->widget_description), title);
+}
+
+CdDevice *
+color_profile_get_device (ColorProfile *color_profile)
+{
+  g_return_val_if_fail (SETTINGS_IS_COLOR_PROFILE (color_profile), NULL);
+  return color_profile->device;
+}
+
+CdProfile *
+color_profile_get_profile (ColorProfile *color_profile)
+{
+  g_return_val_if_fail (SETTINGS_IS_COLOR_PROFILE (color_profile), NULL);
+  return color_profile->profile;
+}
+
+const gchar *
+color_profile_get_sortable (ColorProfile *color_profile)
+{
+  g_return_val_if_fail (SETTINGS_IS_COLOR_PROFILE (color_profile), NULL);
+  return color_profile->sortable;
+}
+
+gboolean
+color_profile_get_is_default (ColorProfile *color_profile)
+{
+  g_return_val_if_fail (SETTINGS_IS_COLOR_PROFILE (color_profile), 0);
+  return color_profile->is_default;
+}
+
+void
+color_profile_set_is_default (ColorProfile *color_profile, gboolean is_default)
+{
+  g_return_if_fail (SETTINGS_IS_COLOR_PROFILE (color_profile));
+  color_profile->is_default = is_default;
+  color_profile_refresh (color_profile);
+}
+
+static void
+color_profile_get_property (GObject *object, guint param_id,
+                               GValue *value, GParamSpec *pspec)
+{
+  ColorProfile *color_profile = SETTINGS_COLOR_PROFILE (object);
+  switch (param_id)
+    {
+      case PROP_DEVICE:
+        g_value_set_object (value, color_profile->device);
+        break;
+      case PROP_PROFILE:
+        g_value_set_object (value, color_profile->profile);
+        break;
+      case PROP_IS_DEFAULT:
+        g_value_set_boolean (value, color_profile->is_default);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    }
+}
+
+static void
+color_profile_set_property (GObject *object, guint param_id,
+                               const GValue *value, GParamSpec *pspec)
+{
+  ColorProfile *color_profile = SETTINGS_COLOR_PROFILE (object);
+
+  switch (param_id)
+    {
+      case PROP_DEVICE:
+        color_profile->device = g_value_dup_object (value);
+        break;
+      case PROP_PROFILE:
+        color_profile->profile = g_value_dup_object (value);
+        break;
+      case PROP_IS_DEFAULT:
+        color_profile->is_default = g_value_get_boolean (value);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    }
+}
+
+static void
+color_profile_finalize (GObject *object)
+{
+  ColorProfile *color_profile = SETTINGS_COLOR_PROFILE (object);
+
+  if (color_profile->device_changed_id > 0)
+    g_signal_handler_disconnect (color_profile->device, color_profile->device_changed_id);
+  if (color_profile->profile_changed_id > 0)
+    g_signal_handler_disconnect (color_profile->profile, color_profile->profile_changed_id);
+
+  g_free (color_profile->sortable);
+  g_object_unref (color_profile->device);
+  g_object_unref (color_profile->profile);
+
+  G_OBJECT_CLASS (color_profile_parent_class)->finalize (object);
+}
+
+static void
+color_profile_changed_cb (CdDevice *device,
+                          ColorProfile *color_profile)
+{
+  g_autoptr(CdProfile) profile = NULL;
+
+  /* check to see if the default has changed */
+  profile = cd_device_get_default_profile (device);
+  if (profile != NULL)
+    color_profile->is_default = g_strcmp0 (cd_profile_get_object_path (profile),
+                                           cd_profile_get_object_path (color_profile->profile)) == 0;
+
+  color_profile_refresh (color_profile);
+}
+
+static void
+color_profile_constructed (GObject *object)
+{
+  ColorProfile *color_profile = SETTINGS_COLOR_PROFILE (object);
+  g_autofree gchar *title = NULL;
+
+  /* watch to see if the default changes */
+  color_profile->device_changed_id =
+    g_signal_connect (color_profile->device, "changed",
+                      G_CALLBACK (color_profile_changed_cb), color_profile);
+  color_profile->profile_changed_id =
+    g_signal_connect (color_profile->profile, "changed",
+                      G_CALLBACK (color_profile_changed_cb), color_profile);
+
+  /* sort the profiles in the list by:
+   * 1. thier device (required)
+   * 2. the data source (so calibration profiles are listed before autogenerated ones)
+   * 3. the date the profiles were created (newest first)
+   * 4. the alpha sorting of the filename
+   */
+  /*
+  title = gcm_prefs_get_profile_title (color_profile->profile);
+  sortable_device = color_device_get_sortable_base (color_profile->device);
+  sortable_data_source = color_profile_get_profile_sort_data_source (color_profile->profile);
+  color_profile->sortable = g_strdup_printf ("%s-%s-%012" G_GINT64_FORMAT "-%s",
+                                    sortable_device,
+                                    sortable_data_source,
+                                    cd_profile_get_created (color_profile->profile),
+                                    title);
+*/
+  color_profile_refresh (color_profile);
+}
+
+static void
+color_profile_class_init (ColorProfileClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  object_class->get_property = color_profile_get_property;
+  object_class->set_property = color_profile_set_property;
+  object_class->constructed = color_profile_constructed;
+  object_class->finalize = color_profile_finalize;
+
+  g_object_class_install_property (object_class, PROP_DEVICE,
+                                   g_param_spec_object ("device", NULL,
+                                                        NULL,
+                                                        CD_TYPE_DEVICE,
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property (object_class, PROP_PROFILE,
+                                   g_param_spec_object ("profile", NULL,
+                                                        NULL,
+                                                        CD_TYPE_PROFILE,
+                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property (object_class, PROP_IS_DEFAULT,
+                                   g_param_spec_boolean ("is-default", NULL,
+                                                         NULL,
+                                                         FALSE,
+                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+color_profile_init (ColorProfile *color_profile)
+{
+  GtkWidget *box;
+
+  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 9);
+
+  /* default tick */
+  color_profile->widget_image = gtk_image_new_from_icon_name ("object-select-symbolic", GTK_ICON_SIZE_MENU);
+  gtk_widget_set_margin_start (color_profile->widget_image, IMAGE_WIDGET_PADDING);
+  gtk_widget_set_margin_end (color_profile->widget_image, IMAGE_WIDGET_PADDING);
+  gtk_box_pack_start (GTK_BOX (box), color_profile->widget_image, FALSE, FALSE, 0);
+
+  /* description */
+  color_profile->widget_description = gtk_label_new ("");
+  gtk_widget_set_margin_top (color_profile->widget_description, 9);
+  gtk_widget_set_margin_bottom (color_profile->widget_description, 9);
+  gtk_widget_set_halign (color_profile->widget_description, GTK_ALIGN_START);
+  gtk_label_set_ellipsize (GTK_LABEL (color_profile->widget_description), PANGO_ELLIPSIZE_END);
+  gtk_label_set_xalign (GTK_LABEL (color_profile->widget_description), 0);
+  gtk_box_pack_start (GTK_BOX (box), color_profile->widget_description, TRUE, TRUE, 0);
+  gtk_widget_show (color_profile->widget_description);
+
+  /* profile warnings/info */
+  color_profile->widget_info = gtk_image_new_from_icon_name ("dialog-information-symbolic", GTK_ICON_SIZE_MENU);
+  gtk_widget_set_margin_start (color_profile->widget_info, IMAGE_WIDGET_PADDING);
+  gtk_widget_set_margin_end (color_profile->widget_info, IMAGE_WIDGET_PADDING);
+  gtk_box_pack_start (GTK_BOX (box), color_profile->widget_info, FALSE, FALSE, 0);
+
+  /* refresh */
+  gtk_container_add (GTK_CONTAINER (color_profile), box);
+  gtk_widget_set_visible (box, TRUE);
+}
+
+GtkWidget *
+color_profile_new (CdDevice *device,
+                   CdProfile *profile,
+                   gboolean is_default)
+{
+  return g_object_new (TYPE_COLOR_PROFILE,
+                       "device", device,
+                       "profile", profile,
+                       "is-default", is_default,
+                       NULL);
+}
diff --git a/dialogs/color-settings/color-profile.h b/dialogs/color-settings/color-profile.h
new file mode 100644
index 0000000..055d717
--- /dev/null
+++ b/dialogs/color-settings/color-profile.h
@@ -0,0 +1,42 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+#include <colord.h>
+
+G_BEGIN_DECLS
+
+#define TYPE_COLOR_PROFILE (color_profile_get_type ())
+G_DECLARE_FINAL_TYPE (ColorProfile, color_profile, SETTINGS, COLOR_PROFILE, GtkListBoxRow)
+
+GtkWidget   *color_profile_new              (CdDevice        *device,
+                                                CdProfile       *profile,
+                                                gboolean         is_default);
+gboolean     color_profile_get_is_default   (ColorProfile  *color_profile);
+void         color_profile_set_is_default   (ColorProfile  *color_profile,
+                                                gboolean         profile_is_default);
+CdDevice    *color_profile_get_device       (ColorProfile  *color_profile);
+CdProfile   *color_profile_get_profile      (ColorProfile  *color_profile);
+const gchar *color_profile_get_sortable     (ColorProfile  *color_profile);
+
+G_END_DECLS
diff --git a/dialogs/color-settings/main.c b/dialogs/color-settings/main.c
index 9f91246..d57fc23 100644
--- a/dialogs/color-settings/main.c
+++ b/dialogs/color-settings/main.c
@@ -36,6 +36,8 @@
 #include <libxfce4util/libxfce4util.h>
 #include <xfconf/xfconf.h>
 
+#include "color-device.h"
+#include "color-profile.h"
 #include "color-dialog_ui.h"
 
 
@@ -62,41 +64,290 @@ struct _ColorSettings
     GPtrArray     *devices;
     GCancellable  *cancellable;
     GDBusProxy    *proxy;
+    GObject       *grid;
+    GObject       *label_no_devices;
+    GObject       *box_devices;
+    GObject       *frame_devices;
+    GtkListBox    *list_box;
+    gchar         *list_box_filter;
+    guint          list_box_selected_id;
+    guint          list_box_activated_id;
+    GtkSizeGroup  *list_box_size;
+    GObject       *label_no_profiles;
+    GObject       *box_profiles;
+    GObject       *frame_profiles;
+    GtkListBox    *profiles_list_box;
+    gchar         *profiles_list_box_filter;
+    guint          profiles_list_box_selected_id;
+    guint          profiles_list_box_activated_id;
+    GtkSizeGroup  *profiles_list_box_size;
 } ColorSettings;
 
-static ColorSettings *color_settings;
+
 
 static void
-color_settings_device_selected_cb (GtkTreeView       *tree_view,
-                                   GtkTreePath       *path,
-                                   GtkTreeViewColumn *column,
-                                   gpointer           user_data)
+color_settings_make_profile_default_cb (GObject *object,
+                                        GAsyncResult *res,
+                                        ColorSettings *settings)
 {
+  CdDevice *device = CD_DEVICE (object);
+  gboolean ret = FALSE;
+  g_autoptr(GError) error = NULL;
 
+  ret = cd_device_make_profile_default_finish (device,
+                                               res,
+                                               &error);
+  if (!ret)
+    {
+      g_warning ("failed to set default profile on %s: %s",
+                 cd_device_get_id (device),
+                 error->message);
+    }
 }
 
 
 
 static void
-color_settings_profile_add_cb (GtkButton *button, gpointer user_data)
+color_settings_device_profile_enable_cb (GtkWidget *widget, ColorSettings *settings)
 {
+  CdProfile *profile;
+  GtkListBoxRow *row;
+
+  /* get the selected profile */
+  row = gtk_list_box_get_selected_row (settings->profiles_list_box);
+  if (row == NULL)
+    return;
+  profile = color_profile_get_profile (SETTINGS_COLOR_PROFILE (row));
+  if (profile == NULL)
+    {
+        g_warning ("failed to get the active profile");
+        return;
+    }
 
+  /* just set it default */
+  g_debug ("setting %s default on %s",
+           cd_profile_get_id (profile),
+           cd_device_get_id (settings->current_device));
+  cd_device_make_profile_default (settings->current_device,
+                                  profile,
+                                  settings->cancellable,
+                                  (GAsyncReadyCallback) color_settings_make_profile_default_cb,
+                                  settings);
+}
+
+static void
+color_settings_add_device_profile (ColorSettings *settings,
+                              CdDevice *device,
+                              CdProfile *profile,
+                              gboolean is_default)
+{
+  gboolean ret;
+  g_autoptr(GError) error = NULL;
+  GtkWidget *widget;
+
+  /* get properties */
+  ret = cd_profile_connect_sync (profile,
+                                 settings->cancellable,
+                                 &error);
+  if (!ret)
+    {
+      g_warning ("failed to get profile: %s", error->message);
+      return;
+    }
+
+  /* ignore profiles from other user accounts */
+  if (!cd_profile_has_access (profile))
+    {
+      /* only print the filename if it exists */
+      if (cd_profile_get_filename (profile) != NULL)
+        {
+          g_warning ("%s is not usable by this user",
+                     cd_profile_get_filename (profile));
+        }
+      else
+        {
+          g_warning ("%s is not usable by this user",
+                     cd_profile_get_id (profile));
+        }
+      return;
+    }
+
+  /* add to listbox */
+  widget = color_profile_new (device, profile, is_default);
+  gtk_widget_show (widget);
+  gtk_container_add (GTK_CONTAINER (settings->profiles_list_box), widget);
+  gtk_size_group_add_widget (settings->profiles_list_box_size, widget);
 }
 
 
 
 static void
-color_settings_dialog_configure_widgets (GtkBuilder *builder)
+color_settings_add_device_profiles (ColorSettings *settings, CdDevice *device)
 {
-    GObject *devices, *profiles, *profile_add;
+  CdProfile *profile_tmp;
+  g_autoptr(GPtrArray) profiles = NULL;
+  guint i;
 
-    /* Sticky keys */
-    devices = gtk_builder_get_object (builder, "colord-devices");
-    profiles = gtk_builder_get_object (builder, "colord-profiles");
-    g_signal_connect (devices, "row-activated", G_CALLBACK (color_settings_device_selected_cb), profiles);
+  /* add profiles */
+  profiles = cd_device_get_profiles (device);
+  if (profiles == NULL)
+    return;
+  for (i = 0; i < profiles->len; i++)
+    {
+      profile_tmp = g_ptr_array_index (profiles, i);
+      color_settings_add_device_profile (settings, device, profile_tmp, i == 0);
+    }
+
+  gtk_widget_show (GTK_WIDGET (settings->profiles_list_box));
+}
+
+
+
+/* find the profile in the array -- for flicker-free changes */
+static gboolean
+color_settings_find_profile_by_object_path (GPtrArray *profiles,
+                                       const gchar *object_path)
+{
+  CdProfile *profile_tmp;
+  guint i;
+
+  for (i = 0; i < profiles->len; i++)
+    {
+      profile_tmp = g_ptr_array_index (profiles, i);
+      if (g_strcmp0 (cd_profile_get_object_path (profile_tmp), object_path) == 0)
+        return TRUE;
+    }
+  return FALSE;
+}
+
+
+
+/* find the profile in the list view -- for flicker-free changes */
+static gboolean
+color_settings_find_widget_by_object_path (GList *list,
+                                      const gchar *object_path_device,
+                                      const gchar *object_path_profile)
+{
+  GList *l;
+  CdDevice *device_tmp;
+  CdProfile *profile_tmp;
+
+  for (l = list; l != NULL; l = l->next)
+    {
+      if (!SETTINGS_IS_COLOR_PROFILE (l->data))
+        continue;
+
+      /* correct device ? */
+      device_tmp = color_profile_get_device (SETTINGS_COLOR_PROFILE (l->data));
+      if (g_strcmp0 (object_path_device,
+                     cd_device_get_object_path (device_tmp)) != 0)
+        {
+          continue;
+        }
+
+      /* this profile */
+      profile_tmp = color_profile_get_profile (SETTINGS_COLOR_PROFILE (l->data));
+      if (g_strcmp0 (object_path_profile,
+                     cd_profile_get_object_path (profile_tmp)) == 0)
+        {
+          return TRUE;
+        }
+    }
+  return FALSE;
+}
+
+
+
+static void
+color_settings_update_device_list_extra_entry (ColorSettings *settings)
+{
+  g_autoptr(GList) device_widgets = NULL;
+  guint number_of_devices;
+
+  /* any devices to show? */
+  device_widgets = gtk_container_get_children (GTK_CONTAINER (settings->list_box));
+  number_of_devices = g_list_length (device_widgets);
+  gtk_widget_set_visible (GTK_WIDGET (settings->label_no_devices), number_of_devices == 0);
+  gtk_widget_set_visible (GTK_WIDGET (settings->box_devices), number_of_devices > 0);
+}
+
+
+
+static void
+color_settings_update_profile_list_extra_entry (ColorSettings *settings)
+{
+  g_autoptr(GList) profile_widgets = NULL;
+  guint number_of_profiles;
+
+  /* any profiles to show? */
+  profile_widgets = gtk_container_get_children (GTK_CONTAINER (settings->profiles_list_box));
+  number_of_profiles = g_list_length (profile_widgets);
+  gtk_widget_set_visible (GTK_WIDGET (settings->label_no_profiles), number_of_profiles == 0);
+  gtk_widget_set_visible (GTK_WIDGET (settings->box_profiles), number_of_profiles > 0);
+}
+
+
+
+static void
+listbox_remove_all (GtkWidget *widget, gpointer user_data)
+{
+    GtkWidget *container = user_data;
+    gtk_container_remove (GTK_CONTAINER (container), widget);
+}
+
+
+
+static void
+color_settings_list_box_row_activated_cb (GtkListBox *list_box,
+                                          GtkListBoxRow *row,
+                                          ColorSettings *settings)
+{
+    GtkCallback func = listbox_remove_all;
+
+    gtk_container_foreach (GTK_CONTAINER (settings->profiles_list_box), func, settings->profiles_list_box);
+    g_object_get (row, "device", &settings->current_device, NULL);
+    if (cd_device_get_enabled (settings->current_device))
+    {
+        color_settings_add_device_profiles (settings, settings->current_device);
+        color_settings_update_profile_list_extra_entry (settings);
+        gtk_widget_queue_draw (GTK_WIDGET (settings->grid));
+    }
+    else
+        color_settings_update_profile_list_extra_entry (settings);
+}
+
+
+
+
+static void
+color_settings_device_enabled_changed_cb (ColorDevice *widget,
+                                          gboolean is_enabled,
+                                          ColorSettings *settings)
+{
+    gtk_list_box_select_row (settings->list_box, GTK_LIST_BOX_ROW (widget));
+    gtk_widget_set_visible (GTK_WIDGET (settings->label_no_profiles), !is_enabled);
+    gtk_widget_set_visible (GTK_WIDGET (settings->box_profiles), is_enabled);
+}
+
+
+
+static void
+color_settings_profiles_list_box_row_activated_cb (GtkListBox *list_box,
+                                                   GtkListBoxRow *row,
+                                                   ColorSettings *settings)
+{
+    if (SETTINGS_IS_COLOR_PROFILE (row))
+    {
+      color_settings_device_profile_enable_cb (NULL, settings);
+    }
+}
+
+
+
+static void
+color_settings_profile_add_cb (GtkButton *button, gpointer user_data)
+{
 
-    profile_add = gtk_builder_get_object (builder, "profile-add");
-    g_signal_connect (profile_add, "clicked", G_CALLBACK (color_settings_profile_add_cb), NULL);
 }
 
 
@@ -115,13 +366,181 @@ color_settings_dialog_response (GtkWidget *dialog,
 
 
 static void
+color_settings_device_changed_cb (CdDevice *device, ColorSettings *settings)
+{
+  CdDevice *device_tmp;
+  CdProfile *profile_tmp;
+  gboolean ret;
+  GList *l;
+  g_autoptr(GList) list = NULL;
+  GPtrArray *profiles;
+  guint i;
+
+  /* remove anything in the list view that's not in Device.Profiles */
+  profiles = cd_device_get_profiles (device);
+  list = gtk_container_get_children (GTK_CONTAINER (settings->profiles_list_box));
+  for (l = list; l != NULL; l = l->next)
+    {
+      if (!SETTINGS_IS_COLOR_PROFILE (l->data))
+        continue;
+
+      /* correct device ? */
+      device_tmp = color_profile_get_device (SETTINGS_COLOR_PROFILE (l->data));
+      if (g_strcmp0 (cd_device_get_id (device),
+                     cd_device_get_id (device_tmp)) != 0)
+        continue;
+
+      /* if profile is not in Device.Profiles then remove */
+      profile_tmp = color_profile_get_profile (SETTINGS_COLOR_PROFILE (l->data));
+      ret = color_settings_find_profile_by_object_path (profiles,
+                                                   cd_profile_get_object_path (profile_tmp));
+      if (!ret) {
+        gtk_widget_destroy (GTK_WIDGET (l->data));
+        /* Don't look at the destroyed widget below */
+        l->data = NULL;
+      }
+    }
+
+  /* add anything in Device.Profiles that's not in the list view */
+  for (i = 0; i < profiles->len; i++)
+    {
+      profile_tmp = g_ptr_array_index (profiles, i);
+      ret = color_settings_find_widget_by_object_path (list,
+                                                  cd_device_get_object_path (device),
+                                                  cd_profile_get_object_path (profile_tmp));
+      if (!ret)
+        color_settings_add_device_profile (settings, device, profile_tmp, i == 0);
+    }
+
+  color_settings_update_profile_list_extra_entry (settings);
+  /* resort */
+  //gtk_list_box_invalidate_sort (prefs->list_box);
+}
+
+
+
+static void
+color_settings_add_device (ColorSettings *settings, CdDevice *device)
+{
+  gboolean ret;
+  g_autoptr(GError) error = NULL;
+  GtkWidget *widget;
+
+  /* get device properties */
+  ret = cd_device_connect_sync (device, settings->cancellable, &error);
+  if (!ret)
+    {
+      g_warning ("failed to connect to the device: %s", error->message);
+      return;
+    }
+
+  /* add device */
+  widget = color_device_new (device);
+  g_signal_connect (G_OBJECT (widget), "enabled-changed",
+                    G_CALLBACK (color_settings_device_enabled_changed_cb), settings);
+  gtk_widget_show (widget);
+  gtk_container_add (GTK_CONTAINER (settings->list_box), widget);
+  gtk_size_group_add_widget (settings->list_box_size, widget);
+
+  /* add profiles */
+  //color_settings_add_device_profiles (settings, device);
+
+  /* watch for changes */
+  g_ptr_array_add (settings->devices, g_object_ref (device));
+  g_signal_connect (device, "changed",
+                    G_CALLBACK (color_settings_device_changed_cb), settings);
+  gtk_list_box_invalidate_sort (settings->list_box);
+}
+
+
+
+static void
+color_settings_remove_device (ColorSettings *settings, CdDevice *device)
+{
+  CdDevice *device_tmp;
+  GList *l;
+  g_autoptr(GList) list = NULL;
+
+  list = gtk_container_get_children (GTK_CONTAINER (settings->list_box));
+  for (l = list; l != NULL; l = l->next)
+    {
+      device_tmp = color_device_get_device (CC_COLOR_DEVICE (l->data));
+
+      if (g_strcmp0 (cd_device_get_object_path (device),
+                     cd_device_get_object_path (device_tmp)) == 0)
+        {
+          gtk_widget_destroy (GTK_WIDGET (l->data));
+        }
+    }
+  g_signal_handlers_disconnect_by_func (device,
+                                        G_CALLBACK (color_settings_device_changed_cb),
+                                        settings);
+  g_ptr_array_remove (settings->devices, device);
+  color_settings_update_profile_list_extra_entry (settings);
+}
+
+
+
+static void
+list_box_update_header_func (GtkListBoxRow *row,
+                                GtkListBoxRow *before,
+                                gpointer user_data)
+{
+  GtkWidget *current;
+
+  if (before == NULL)
+    {
+      gtk_list_box_row_set_header (row, NULL);
+      return;
+    }
+
+  current = gtk_list_box_row_get_header (row);
+  if (current == NULL)
+    {
+      current = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+      gtk_widget_show (current);
+      gtk_list_box_row_set_header (row, current);
+    }
+}
+
+
+
+static void
+color_settings_device_added_cb (CdClient *client,
+                                CdDevice *device,
+                                ColorSettings *settings)
+{
+  /* add the device */
+  color_settings_add_device (settings, device);
+
+  /* ensure we're not showing the 'No devices detected' entry */
+  color_settings_update_device_list_extra_entry (settings);
+}
+
+
+
+static void
+color_settings_device_removed_cb (CdClient *client,
+                                  CdDevice *device,
+                                  ColorSettings *settings)
+{
+  /* remove from the UI */
+  color_settings_remove_device (settings, device);
+
+  /* ensure we showing the 'No devices detected' entry if required */
+  color_settings_update_device_list_extra_entry (settings);
+}
+
+
+
+static void
 color_settings_get_devices_cb (GObject *object,
                                GAsyncResult *res,
                                gpointer user_data)
 {
-  //ColorSettings *settings = (ColorSettings *) user_data;
+  ColorSettings *settings = (ColorSettings *) user_data;
   CdClient *client = CD_CLIENT (object);
-  //CdDevice *device;
+  CdDevice *device;
   g_autoptr(GError) error = NULL;
   g_autoptr(GPtrArray) devices = NULL;
   guint i;
@@ -136,13 +555,12 @@ color_settings_get_devices_cb (GObject *object,
     }
   for (i = 0; i < devices->len; i++)
     {
-      //device = g_ptr_array_index (devices, i);
-      g_warning ("device: %d", i);
-      //gcm_prefs_add_device (prefs, device);
+      device = g_ptr_array_index (devices, i);
+      color_settings_add_device (settings, device);
     }
-
-  /* ensure we show the 'No devices detected' entry if empty */
-  //gcm_prefs_update_device_list_extra_entry (prefs);
+  /* ensure we showing the 'No devices detected' entry if required */
+  color_settings_update_device_list_extra_entry (settings);
+  color_settings_update_profile_list_extra_entry (settings);
 }
 
 
@@ -152,6 +570,7 @@ color_settings_connect_cb (GObject *object,
                            GAsyncResult *res,
                            gpointer user_data)
 {
+    ColorSettings *settings = (ColorSettings *) user_data;
     gboolean ret;
     g_autoptr(GError) error = NULL;
 
@@ -168,35 +587,91 @@ color_settings_connect_cb (GObject *object,
     /* Only cast the parameters after making sure it didn't fail. At this point,
      * the user can potentially already have changed to another panel, effectively
      * making user_data invalid. */
-    //settings = CC_COLOR_PANEL (user_data);
+    //settings = SETTINGS_COLOR_PANEL (user_data);
 
     /* get devices */
-    cd_client_get_devices (color_settings->client,
-                           color_settings->cancellable,
+    cd_client_get_devices (settings->client,
+                           settings->cancellable,
                            color_settings_get_devices_cb,
-                           color_settings);
+                           settings);
 }
 
 
 
 static void
-color_settings_dialog_init (void)
+color_settings_dialog_init (GtkBuilder *builder)
 {
-    color_settings = g_new0 (ColorSettings, 1);
-    color_settings->cancellable = g_cancellable_new ();
-    color_settings->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+    GObject *profile_add;
+
+    ColorSettings *settings;
+    settings = g_new0 (ColorSettings, 1);
+    settings->cancellable = g_cancellable_new ();
+    settings->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
 
     /* use a device client array */
-    color_settings->client = cd_client_new ();
-/*    g_signal_connect_object (settings->client, "device-added",
-                             G_CALLBACK (color_settings_device_added_cb), settings, 0);
-    g_signal_connect_object (settings->client, "device-removed",
-                             G_CALLBACK (color_settings_device_removed_cb), settings, 0);
-*/
-    cd_client_connect (color_settings->client,
-                       color_settings->cancellable,
+    settings->client = cd_client_new ();
+    g_signal_connect_data (settings->client, "device-added",
+                           G_CALLBACK (color_settings_device_added_cb), settings, 0, 0);
+    g_signal_connect_data (settings->client, "device-removed",
+                           G_CALLBACK (color_settings_device_removed_cb), settings, 0, 0);
+
+    profile_add = gtk_builder_get_object (builder, "profile-add");
+    g_signal_connect (profile_add, "clicked", G_CALLBACK (color_settings_profile_add_cb), NULL);
+
+    settings->label_no_devices = gtk_builder_get_object (builder, "label-no-devices");
+    settings->box_devices = gtk_builder_get_object (builder, "box-devices");
+    settings->grid = gtk_builder_get_object (builder, "grid");
+
+    /* Devices ListBox */
+    settings->frame_devices = gtk_builder_get_object (builder, "frame-devices");
+    settings->list_box = GTK_LIST_BOX (gtk_list_box_new ());
+    gtk_list_box_set_header_func (settings->list_box,
+                              list_box_update_header_func,
+                              settings, NULL);
+    gtk_list_box_set_selection_mode (settings->list_box,
+                                 GTK_SELECTION_SINGLE);
+    gtk_list_box_set_activate_on_single_click (settings->list_box, TRUE);
+    settings->list_box_selected_id =
+        g_signal_connect (settings->list_box, "row-selected",
+                          G_CALLBACK (color_settings_list_box_row_activated_cb),
+                          settings);
+    settings->list_box_activated_id =
+    g_signal_connect (settings->list_box, "row-activated",
+                      G_CALLBACK (color_settings_list_box_row_activated_cb),
+                      settings);
+    settings->list_box_size = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
+
+    gtk_container_add (GTK_CONTAINER (settings->frame_devices), GTK_WIDGET (settings->list_box));
+    gtk_widget_show_all (GTK_WIDGET (settings->list_box));
+
+    /* Profiles ListBox */
+    settings->label_no_profiles = gtk_builder_get_object (builder, "label-no-profiles");
+    settings->box_profiles = gtk_builder_get_object (builder, "box-profiles");
+    settings->frame_profiles = gtk_builder_get_object (builder, "frame-profiles");
+    settings->profiles_list_box = GTK_LIST_BOX (gtk_list_box_new ());
+    gtk_list_box_set_header_func (settings->profiles_list_box,
+                              list_box_update_header_func,
+                              settings, NULL);
+    gtk_list_box_set_selection_mode (settings->profiles_list_box,
+                                 GTK_SELECTION_SINGLE);
+    gtk_list_box_set_activate_on_single_click (settings->profiles_list_box, TRUE);
+    settings->profiles_list_box_selected_id =
+        g_signal_connect (settings->profiles_list_box, "row-selected",
+                          G_CALLBACK (color_settings_profiles_list_box_row_activated_cb),
+                          settings);
+    settings->profiles_list_box_activated_id =
+    g_signal_connect (settings->profiles_list_box, "row-activated",
+                  G_CALLBACK (color_settings_profiles_list_box_row_activated_cb),
+                  settings);
+    settings->profiles_list_box_size = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
+
+    gtk_container_add (GTK_CONTAINER (settings->frame_profiles), GTK_WIDGET (settings->profiles_list_box));
+    gtk_widget_show (GTK_WIDGET (settings->profiles_list_box));
+
+    cd_client_connect (settings->client,
+                       settings->cancellable,
                        color_settings_connect_cb,
-                       color_settings);
+                       settings);
 }
 
 
@@ -267,9 +742,8 @@ main (gint argc, gchar **argv)
     if (gtk_builder_add_from_string (builder, color_dialog_ui,
                                      color_dialog_ui_length, &error) != 0)
     {
-        /* Configure widgets */
-        color_settings_dialog_init ();
-        color_settings_dialog_configure_widgets (builder);
+        /* Initialize the dialog */
+        color_settings_dialog_init (builder);
 
         if (G_UNLIKELY (opt_socket_id == 0))
         {

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Xfce4-commits mailing list