diff options
Diffstat (limited to 'panels/color/cc-color-panel.c')
-rw-r--r-- | panels/color/cc-color-panel.c | 2208 |
1 files changed, 2208 insertions, 0 deletions
diff --git a/panels/color/cc-color-panel.c b/panels/color/cc-color-panel.c new file mode 100644 index 0000000..42820c7 --- /dev/null +++ b/panels/color/cc-color-panel.c @@ -0,0 +1,2208 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Red Hat, Inc + * Copyright (C) 2011 Richard Hughes <richard@hughsie.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include <glib/gi18n.h> +#include <colord.h> +#include <gtk/gtk.h> +#include <gdk/x11/gdkx.h> + +#include "cc-color-calibrate.h" +#include "cc-color-cell-renderer-text.h" +#include "cc-color-panel.h" +#include "cc-color-resources.h" +#include "cc-color-common.h" +#include "cc-color-device.h" +#include "cc-color-profile.h" + +struct _CcColorPanel +{ + CcPanel parent_instance; + + CdClient *client; + CdDevice *current_device; + GPtrArray *devices; + GPtrArray *sensors; + GDBusProxy *proxy; + GSettings *settings; + GSettings *settings_colord; + GtkWidget *assistant_calib; + GtkWidget *box_calib_brightness; + GtkWidget *box_calib_kind; + GtkWidget *box_calib_quality; + GtkWidget *box_calib_sensor; + GtkWidget *box_calib_summary; + GtkWidget *box_calib_temp; + GtkWidget *box_calib_title; + GtkWidget *box_devices; + GtkWidget *button_assign_import; + GtkWidget *button_assign_ok; + GtkWidget *button_calib_export; + GtkWidget *dialog_assign; + GtkWidget *entry_calib_title; + GtkWidget *label_assign_warning; + GtkWidget *label_calib_summary_message; + GtkWidget *label_no_devices; + GtkTreeModel *liststore_assign; + GtkTreeModel *liststore_calib_kind; + GtkTreeModel *liststore_calib_sensor; + GtkWidget *toolbar_devices; + GtkWidget *toolbutton_device_calibrate; + GtkWidget *toolbutton_device_default; + GtkWidget *toolbutton_device_enable; + GtkWidget *toolbutton_profile_add; + GtkWidget *toolbutton_profile_remove; + GtkWidget *toolbutton_profile_view; + GtkWidget *treeview_assign; + GtkWidget *treeview_calib_kind; + GtkWidget *treeview_calib_quality; + GtkWidget *treeview_calib_sensor; + GtkWidget *treeview_calib_temp; + CcColorCalibrate *calibrate; + GtkListBox *list_box; + gchar *list_box_filter; + GtkSizeGroup *list_box_size; + gboolean is_live_cd; + gboolean model_is_changing; +}; + +CC_PANEL_REGISTER (CcColorPanel, cc_color_panel) + +enum { + GCM_PREFS_COMBO_COLUMN_TEXT, + GCM_PREFS_COMBO_COLUMN_PROFILE, + GCM_PREFS_COMBO_COLUMN_TYPE, + GCM_PREFS_COMBO_COLUMN_WARNING_FILENAME, + GCM_PREFS_COMBO_COLUMN_NUM_COLUMNS +}; + +/* for the GtkListStores */ +enum { + COLUMN_CALIB_KIND_DESCRIPTION, + COLUMN_CALIB_KIND_CAP_VALUE, + COLUMN_CALIB_KIND_VISIBLE, + COLUMN_CALIB_KIND_LAST +}; +enum { + COLUMN_CALIB_QUALITY_DESCRIPTION, + COLUMN_CALIB_QUALITY_APPROX_TIME, + COLUMN_CALIB_QUALITY_VALUE, + COLUMN_CALIB_QUALITY_LAST +}; +enum { + COLUMN_CALIB_SENSOR_OBJECT, + COLUMN_CALIB_SENSOR_DESCRIPTION, + COLUMN_CALIB_SENSOR_LAST +}; +enum { + COLUMN_CALIB_TEMP_DESCRIPTION, + COLUMN_CALIB_TEMP_VALUE_K, + COLUMN_CALIB_TEMP_LAST +}; + +#define COLORD_SETTINGS_SCHEMA "org.freedesktop.ColorHelper" +#define GCM_SETTINGS_SCHEMA "org.gnome.settings-daemon.plugins.color" +#define GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD "recalibrate-printer-threshold" +#define GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD "recalibrate-display-threshold" + +/* max number of devices and profiles to cause auto-expand at startup */ +#define GCM_PREFS_MAX_DEVICES_PROFILES_EXPANDED 5 + +static void gcm_prefs_refresh_toolbar_buttons (CcColorPanel *panel); + +static void +gcm_prefs_combobox_add_profile (CcColorPanel *prefs, + CdProfile *profile, + GtkTreeIter *iter) +{ + const gchar *id; + GtkTreeIter iter_tmp; + g_autoptr(GString) string = NULL; + gchar *escaped = NULL; + guint kind = 0; + const gchar *warning = NULL; +#if CD_CHECK_VERSION(0,1,25) + gchar **warnings; +#endif + + /* iter is optional */ + if (iter == NULL) + iter = &iter_tmp; + + /* use description */ + string = g_string_new (cd_profile_get_title (profile)); + + /* any source prefix? */ + id = cd_profile_get_metadata_item (profile, + CD_PROFILE_METADATA_DATA_SOURCE); + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_EDID) == 0) + { + /* TRANSLATORS: this is a profile prefix to signify the + * profile has been auto-generated for this hardware */ + g_string_prepend (string, _("Default: ")); + kind = 1; + } +#if CD_CHECK_VERSION(0,1,14) + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0) + { + /* TRANSLATORS: this is a profile prefix to signify the + * profile his a standard space like AdobeRGB */ + g_string_prepend (string, _("Colorspace: ")); + kind = 2; + } + if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_TEST) == 0) + { + /* TRANSLATORS: this is a profile prefix to signify the + * profile is a test profile */ + g_string_prepend (string, _("Test profile: ")); + kind = 3; + } +#endif + + /* is the profile faulty */ +#if CD_CHECK_VERSION(0,1,25) + warnings = cd_profile_get_warnings (profile); + if (warnings != NULL && warnings[0] != NULL) + warning = "dialog-warning-symbolic"; +#endif + + escaped = g_markup_escape_text (string->str, -1); + gtk_list_store_append (GTK_LIST_STORE (prefs->liststore_assign), iter); + gtk_list_store_set (GTK_LIST_STORE (prefs->liststore_assign), iter, + GCM_PREFS_COMBO_COLUMN_TEXT, escaped, + GCM_PREFS_COMBO_COLUMN_PROFILE, profile, + GCM_PREFS_COMBO_COLUMN_TYPE, kind, + GCM_PREFS_COMBO_COLUMN_WARNING_FILENAME, warning, + -1); +} + +static void +gcm_prefs_default_cb (CcColorPanel *prefs) +{ + g_autoptr(CdProfile) profile = NULL; + gboolean ret; + g_autoptr(GError) error = NULL; + + /* TODO: check if the profile is already systemwide */ + profile = cd_device_get_default_profile (prefs->current_device); + if (profile == NULL) + return; + + /* install somewhere out of $HOME */ + ret = cd_profile_install_system_wide_sync (profile, + cc_panel_get_cancellable (CC_PANEL (prefs)), + &error); + if (!ret) + g_warning ("failed to set profile system-wide: %s", + error->message); +} + +typedef struct +{ + GtkResponseType response; + GMainLoop *mainloop; +} DialogRunData; + +static void +dialog_response_cb (GtkDialog *dialog, + GtkResponseType response, + DialogRunData *run_data) +{ + run_data->response = response; + g_main_loop_quit (run_data->mainloop); +} + +static gboolean +dialog_close_cb (GtkDialog *dialog, + GtkResponseType response, + DialogRunData *run_data) +{ + g_main_loop_quit (run_data->mainloop); + return GDK_EVENT_PROPAGATE; +} + +static GtkResponseType +run_dialog (GtkDialog *dialog) +{ + g_autoptr(GMainLoop) mainloop = NULL; + DialogRunData run_data; + guint response_id; + guint close_id; + + mainloop = g_main_loop_new (NULL, FALSE); + + run_data = (DialogRunData) { + .response = GTK_RESPONSE_DELETE_EVENT, + .mainloop = mainloop, + }; + + response_id = g_signal_connect (dialog, "response", G_CALLBACK (dialog_response_cb), &run_data); + close_id = g_signal_connect (dialog, "close-request", G_CALLBACK (dialog_close_cb), &run_data); + + gtk_window_present (GTK_WINDOW (dialog)); + + g_main_loop_run (mainloop); + + g_signal_handler_disconnect (dialog, response_id); + g_signal_handler_disconnect (dialog, close_id); + + return run_data.response; +} + +static GFile * +gcm_prefs_file_chooser_get_icc_profile (CcColorPanel *prefs) +{ + g_autoptr(GFile) current_folder = NULL; + GtkWindow *window; + GtkWidget *dialog; + GFile *file = NULL; + GtkFileFilter *filter; + + /* create new dialog */ + window = GTK_WINDOW (prefs->dialog_assign); + /* TRANSLATORS: an ICC profile is a file containing colorspace data */ + dialog = gtk_file_chooser_dialog_new (_("Select ICC Profile File"), window, + GTK_FILE_CHOOSER_ACTION_OPEN, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Import"), GTK_RESPONSE_ACCEPT, + NULL); + current_folder = g_file_new_for_path (g_get_home_dir ()); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), current_folder, NULL); + gtk_file_chooser_set_create_folders (GTK_FILE_CHOOSER(dialog), FALSE); + + /* setup the filter */ + filter = gtk_file_filter_new (); + gtk_file_filter_add_mime_type (filter, "application/vnd.iccprofile"); + + /* TRANSLATORS: filter name on the file->open dialog */ + gtk_file_filter_set_name (filter, _("Supported ICC profiles")); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + + /* setup the all files filter */ + filter = gtk_file_filter_new (); + gtk_file_filter_add_pattern (filter, "*"); + /* TRANSLATORS: filter name on the file->open dialog */ + gtk_file_filter_set_name (filter, _("All files")); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter); + + /* did user choose file */ + if (run_dialog (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER(dialog)); + + /* we're done */ + gtk_window_destroy (GTK_WINDOW (dialog)); + + /* or NULL for missing */ + return file; +} + +static void +gcm_prefs_calib_cancel_cb (CcColorPanel *prefs) +{ + gtk_widget_hide (prefs->assistant_calib); +} + +static gboolean +gcm_prefs_calib_delayed_complete_cb (gpointer user_data) +{ + CcColorPanel *panel = CC_COLOR_PANEL (user_data); + GtkAssistant *assistant; + + assistant = GTK_ASSISTANT (panel->assistant_calib); + gtk_assistant_set_page_complete (assistant, panel->box_calib_brightness, TRUE); + return FALSE; +} + +static void +gcm_prefs_calib_prepare_cb (CcColorPanel *panel, + GtkWidget *page) +{ + /* give the user the indication they should actually manually set the + * desired brightness rather than clicking blindly by delaying the + * "Next" button deliberately for a second or so */ + if (page == panel->box_calib_brightness) + { + g_timeout_add_seconds (1, gcm_prefs_calib_delayed_complete_cb, panel); + return; + } + + /* disable the brightness page as we don't want to show a 'Finished' + * button if the user goes back at any point */ + gtk_assistant_set_page_complete (GTK_ASSISTANT (panel->assistant_calib), panel->box_calib_brightness, FALSE); +} + +static void +gcm_prefs_calib_apply_cb (CcColorPanel *prefs) +{ + gboolean ret; + g_autoptr(GError) error = NULL; + GtkWindow *window = NULL; + + /* setup the calibration object with items that can fail */ + ret = cc_color_calibrate_setup (prefs->calibrate, + &error); + if (!ret) + { + g_warning ("failed to setup calibrate: %s", error->message); + return; + } + + /* actually start the calibration */ + window = GTK_WINDOW (prefs->assistant_calib); + ret = cc_color_calibrate_start (prefs->calibrate, + window, + &error); + if (!ret) + { + g_warning ("failed to start calibrate: %s", error->message); + gtk_widget_hide (GTK_WIDGET (window)); + return; + } + + /* if we are a LiveCD then don't close the window as there is another + * summary pane with the export button */ + if (!prefs->is_live_cd) + gtk_widget_hide (GTK_WIDGET (window)); +} + +static void +gcm_prefs_calib_temp_treeview_clicked_cb (CcColorPanel *prefs, + GtkTreeSelection *selection) +{ + gboolean ret; + GtkTreeIter iter; + GtkTreeModel *model; + guint target_whitepoint; + GtkAssistant *assistant; + + /* check to see if anything is selected */ + ret = gtk_tree_selection_get_selected (selection, &model, &iter); + assistant = GTK_ASSISTANT (prefs->assistant_calib); + gtk_assistant_set_page_complete (assistant, prefs->box_calib_temp, ret); + if (!ret) + return; + + gtk_tree_model_get (model, &iter, + COLUMN_CALIB_TEMP_VALUE_K, &target_whitepoint, + -1); + cc_color_calibrate_set_temperature (prefs->calibrate, target_whitepoint); +} + +static void +gcm_prefs_calib_kind_treeview_clicked_cb (CcColorPanel *prefs, + GtkTreeSelection *selection) +{ + CdSensorCap device_kind; + gboolean ret; + GtkTreeIter iter; + GtkTreeModel *model; + GtkAssistant *assistant; + + /* check to see if anything is selected */ + ret = gtk_tree_selection_get_selected (selection, &model, &iter); + assistant = GTK_ASSISTANT (prefs->assistant_calib); + gtk_assistant_set_page_complete (assistant, prefs->box_calib_kind, ret); + if (!ret) + return; + + /* save the values if we have a selection */ + gtk_tree_model_get (model, &iter, + COLUMN_CALIB_KIND_CAP_VALUE, &device_kind, + -1); + cc_color_calibrate_set_kind (prefs->calibrate, device_kind); +} + +static void +gcm_prefs_calib_quality_treeview_clicked_cb (CcColorPanel *prefs, + GtkTreeSelection *selection) +{ + CdProfileQuality quality; + gboolean ret; + GtkAssistant *assistant; + GtkTreeIter iter; + GtkTreeModel *model; + + /* check to see if anything is selected */ + ret = gtk_tree_selection_get_selected (selection, &model, &iter); + assistant = GTK_ASSISTANT (prefs->assistant_calib); + gtk_assistant_set_page_complete (assistant, prefs->box_calib_quality, ret); + if (!ret) + return; + + /* save the values if we have a selection */ + gtk_tree_model_get (model, &iter, + COLUMN_CALIB_QUALITY_VALUE, &quality, + -1); + cc_color_calibrate_set_quality (prefs->calibrate, quality); +} + +static gboolean +gcm_prefs_calib_set_sensor_cap_supported_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + CdSensorCap cap; + CdSensor *sensor = CD_SENSOR (data); + gboolean supported; + + gtk_tree_model_get (model, iter, + COLUMN_CALIB_KIND_CAP_VALUE, &cap, + -1); + supported = cd_sensor_has_cap (sensor, cap); + g_debug ("%s(%s) is %s", + cd_sensor_get_model (sensor), + cd_sensor_cap_to_string (cap), + supported ? "supported" : "not-supported"); + gtk_list_store_set (GTK_LIST_STORE (model), iter, + COLUMN_CALIB_KIND_VISIBLE, supported, + -1); + return FALSE; +} + +static guint8 +_cd_bitfield_popcount (guint64 bitfield) +{ + guint8 i; + guint8 tmp = 0; + for (i = 0; i < 64; i++) + tmp += cd_bitfield_contain (bitfield, i); + return tmp; +} + +static void +gcm_prefs_calib_set_sensor (CcColorPanel *prefs, + CdSensor *sensor) +{ + guint64 caps; + guint8 i; + + /* use this sensor for calibration */ + cc_color_calibrate_set_sensor (prefs->calibrate, sensor); + + /* hide display types the sensor does not support */ + gtk_tree_model_foreach (prefs->liststore_calib_kind, + gcm_prefs_calib_set_sensor_cap_supported_cb, + sensor); + + /* if the sensor only supports one kind then do not show the panel at all */ + caps = cd_sensor_get_caps (sensor); + if (_cd_bitfield_popcount (caps) == 1) + { + gtk_widget_set_visible (prefs->box_calib_kind, FALSE); + for (i = 0; i < CD_SENSOR_CAP_LAST; i++) + { + if (cd_bitfield_contain (caps, i)) + cc_color_calibrate_set_kind (prefs->calibrate, i); + } + } + else + { + cc_color_calibrate_set_kind (prefs->calibrate, CD_SENSOR_CAP_UNKNOWN); + gtk_widget_set_visible (prefs->box_calib_kind, TRUE); + } +} + +static void +gcm_prefs_calib_sensor_treeview_clicked_cb (CcColorPanel *prefs, + GtkTreeSelection *selection) +{ + gboolean ret; + GtkTreeIter iter; + GtkTreeModel *model; + g_autoptr(CdSensor) sensor = NULL; + GtkAssistant *assistant; + + /* check to see if anything is selected */ + ret = gtk_tree_selection_get_selected (selection, &model, &iter); + assistant = GTK_ASSISTANT (prefs->assistant_calib); + gtk_assistant_set_page_complete (assistant, prefs->box_calib_sensor, ret); + if (!ret) + return; + + /* save the values if we have a selection */ + gtk_tree_model_get (model, &iter, + COLUMN_CALIB_SENSOR_OBJECT, &sensor, + -1); + gcm_prefs_calib_set_sensor (prefs, sensor); +} + +static void +gcm_prefs_calibrate_display (CcColorPanel *prefs) +{ + CdSensor *sensor_tmp; + const gchar *tmp; + GtkTreeIter iter; + guint i; + + /* set target device */ + cc_color_calibrate_set_device (prefs->calibrate, prefs->current_device); + + /* add sensors to list */ + gtk_list_store_clear (GTK_LIST_STORE (prefs->liststore_calib_sensor)); + if (prefs->sensors->len > 1) + { + for (i = 0; i < prefs->sensors->len; i++) + { + sensor_tmp = g_ptr_array_index (prefs->sensors, i); + gtk_list_store_append (GTK_LIST_STORE (prefs->liststore_calib_sensor), &iter); + gtk_list_store_set (GTK_LIST_STORE (prefs->liststore_calib_sensor), &iter, + COLUMN_CALIB_SENSOR_OBJECT, sensor_tmp, + COLUMN_CALIB_SENSOR_DESCRIPTION, cd_sensor_get_model (sensor_tmp), + -1); + } + gtk_widget_set_visible (prefs->box_calib_sensor, TRUE); + } + else + { + sensor_tmp = g_ptr_array_index (prefs->sensors, 0); + gcm_prefs_calib_set_sensor (prefs, sensor_tmp); + gtk_widget_set_visible (prefs->box_calib_sensor, FALSE); + } + + /* set default profile title */ + tmp = cd_device_get_model (prefs->current_device); + if (tmp == NULL) + tmp = cd_device_get_vendor (prefs->current_device); + if (tmp == NULL) + tmp = _("Screen"); + gtk_editable_set_text (GTK_EDITABLE (prefs->entry_calib_title), tmp); + cc_color_calibrate_set_title (prefs->calibrate, tmp); + + /* set the display whitepoint to D65 by default */ + //FIXME? + + /* show ui */ + gtk_window_set_transient_for (GTK_WINDOW (prefs->assistant_calib), + GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (prefs)))); + gtk_widget_show (prefs->assistant_calib); +} + +static void +gcm_prefs_title_entry_changed_cb (CcColorPanel *prefs) +{ + GtkAssistant *assistant; + const gchar *value; + + assistant = GTK_ASSISTANT (prefs->assistant_calib); + value = gtk_editable_get_text (GTK_EDITABLE (prefs->entry_calib_title)); + cc_color_calibrate_set_title (prefs->calibrate, value); + gtk_assistant_set_page_complete (assistant, prefs->box_calib_title, value[0] != '\0'); +} + +static void +gcm_prefs_calibrate_cb (CcColorPanel *prefs) +{ + GtkNative *native; + GdkSurface *surface; + gboolean ret; + g_autoptr(GError) error = NULL; + guint xid = 0; + g_autoptr(GPtrArray) argv = NULL; + + /* use the new-style calibration helper */ + if (cd_device_get_kind (prefs->current_device) == CD_DEVICE_KIND_DISPLAY) + { + gcm_prefs_calibrate_display (prefs); + return; + } + + /* get xid */ + native = gtk_widget_get_native (GTK_WIDGET (prefs)); + surface = gtk_native_get_surface (native); + + if (GDK_IS_X11_SURFACE (surface)) + xid = gdk_x11_surface_get_xid (GDK_X11_SURFACE (surface)); + + /* run with modal set */ + argv = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (argv, g_strdup ("gcm-calibrate")); + g_ptr_array_add (argv, g_strdup ("--device")); + g_ptr_array_add (argv, g_strdup (cd_device_get_id (prefs->current_device))); + g_ptr_array_add (argv, g_strdup ("--parent-window")); + g_ptr_array_add (argv, g_strdup_printf ("%i", xid)); + g_ptr_array_add (argv, NULL); + ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, &error); + if (!ret) + g_warning ("failed to run calibrate: %s", error->message); +} + +static gboolean +gcm_prefs_is_profile_suitable_for_device (CdProfile *profile, + CdDevice *device) +{ + const gchar *data_source; + CdProfileKind profile_kind_tmp; + CdProfileKind profile_kind; + CdColorspace profile_colorspace; + CdColorspace device_colorspace = 0; + gboolean ret = FALSE; + CdDeviceKind device_kind; + CdStandardSpace standard_space; + + /* not the right colorspace */ + device_colorspace = cd_device_get_colorspace (device); + profile_colorspace = cd_profile_get_colorspace (profile); + if (device_colorspace != profile_colorspace) + goto out; + + /* if this is a display matching with one of the standard spaces that displays + * could emulate, also mark it as suitable */ + if (cd_device_get_kind (device) == CD_DEVICE_KIND_DISPLAY && + cd_profile_get_kind (profile) == CD_PROFILE_KIND_DISPLAY_DEVICE) + { + data_source = cd_profile_get_metadata_item (profile, + CD_PROFILE_METADATA_STANDARD_SPACE); + standard_space = cd_standard_space_from_string (data_source); + if (standard_space == CD_STANDARD_SPACE_SRGB || + standard_space == CD_STANDARD_SPACE_ADOBE_RGB) + { + ret = TRUE; + goto out; + } + } + + /* not the correct kind */ + device_kind = cd_device_get_kind (device); + profile_kind_tmp = cd_profile_get_kind (profile); + profile_kind = cd_device_kind_to_profile_kind (device_kind); + if (profile_kind_tmp != profile_kind) + goto out; + + /* ignore the colorspace profiles */ + data_source = cd_profile_get_metadata_item (profile, + CD_PROFILE_METADATA_DATA_SOURCE); + if (g_strcmp0 (data_source, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0) + goto out; + + /* success */ + ret = TRUE; +out: + return ret; +} + +static gint +gcm_prefs_combo_sort_func_cb (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data) +{ + gint type_a, type_b; + g_autofree gchar *text_a = NULL; + g_autofree gchar *text_b = NULL; + + /* get data from model */ + gtk_tree_model_get (model, a, + GCM_PREFS_COMBO_COLUMN_TYPE, &type_a, + GCM_PREFS_COMBO_COLUMN_TEXT, &text_a, + -1); + gtk_tree_model_get (model, b, + GCM_PREFS_COMBO_COLUMN_TYPE, &type_b, + GCM_PREFS_COMBO_COLUMN_TEXT, &text_b, + -1); + + /* prefer normal type profiles over the 'Other Profile...' entry */ + if (type_a < type_b) + return -1; + else if (type_a > type_b) + return 1; + else + return g_strcmp0 (text_a, text_b); +} + +static gboolean +gcm_prefs_profile_exists_in_array (GPtrArray *array, CdProfile *profile) +{ + CdProfile *profile_tmp; + guint i; + + for (i = 0; i < array->len; i++) + { + profile_tmp = g_ptr_array_index (array, i); + if (cd_profile_equal (profile, profile_tmp)) + return TRUE; + } + return FALSE; +} + +static void +gcm_prefs_add_profiles_suitable_for_devices (CcColorPanel *prefs, + GPtrArray *profiles) +{ + CdProfile *profile_tmp; + gboolean ret; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) profile_array = NULL; + GtkTreeIter iter; + guint i; + + gtk_list_store_clear (GTK_LIST_STORE (prefs->liststore_assign)); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (prefs->liststore_assign), + GCM_PREFS_COMBO_COLUMN_TEXT, + GTK_SORT_ASCENDING); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (prefs->liststore_assign), + GCM_PREFS_COMBO_COLUMN_TEXT, + gcm_prefs_combo_sort_func_cb, + prefs->liststore_assign, NULL); + + gtk_widget_hide (prefs->label_assign_warning); + + /* get profiles */ + profile_array = cd_client_get_profiles_sync (prefs->client, + cc_panel_get_cancellable (CC_PANEL (prefs)), + &error); + if (profile_array == NULL) + { + g_warning ("failed to get profiles: %s", + error->message); + return; + } + + /* add profiles of the right kind */ + for (i = 0; i < profile_array->len; i++) + { + profile_tmp = g_ptr_array_index (profile_array, i); + + /* get properties */ + ret = cd_profile_connect_sync (profile_tmp, + cc_panel_get_cancellable (CC_PANEL (prefs)), + &error); + if (!ret) + { + g_warning ("failed to get profile: %s", error->message); + return; + } + + /* don't add any of the already added profiles */ + if (profiles != NULL) + { + if (gcm_prefs_profile_exists_in_array (profiles, profile_tmp)) + continue; + } + + /* only add correct types */ + ret = gcm_prefs_is_profile_suitable_for_device (profile_tmp, + prefs->current_device); + if (!ret) + continue; + +#if CD_CHECK_VERSION(0,1,13) + /* ignore profiles from other user accounts */ + if (!cd_profile_has_access (profile_tmp)) + continue; +#endif + + /* add */ + gcm_prefs_combobox_add_profile (prefs, + profile_tmp, + &iter); + } +} + +static void +gcm_prefs_calib_export_cb (CcColorPanel *prefs) +{ + CdProfile *profile; + gboolean ret; + g_autofree gchar *default_name = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) destination = NULL; + g_autoptr(GFile) source = NULL; + GtkWidget *dialog; + + profile = cc_color_calibrate_get_profile (prefs->calibrate); + ret = cd_profile_connect_sync (profile, NULL, &error); + if (!ret) + { + g_warning ("Failed to get imported profile: %s", error->message); + return; + } + + /* TRANSLATORS: this is the dialog to save the ICC profile */ + dialog = gtk_file_chooser_dialog_new (_("Save Profile"), + GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (prefs))), + GTK_FILE_CHOOSER_ACTION_SAVE, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Save"), GTK_RESPONSE_ACCEPT, + NULL); + + default_name = g_strdup_printf ("%s.icc", cd_profile_get_title (profile)); + gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), default_name); + + if (run_dialog (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + source = g_file_new_for_path (cd_profile_get_filename (profile)); + destination = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); + ret = g_file_copy (source, + destination, + G_FILE_COPY_OVERWRITE, + NULL, + NULL, + NULL, + &error); + if (!ret) + g_warning ("Failed to copy profile: %s", error->message); + } + + gtk_window_destroy (GTK_WINDOW (dialog)); +} + +static void +gcm_prefs_calib_export_link_cb (CcColorPanel *prefs, + const gchar *url) +{ + gtk_show_uri (GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (prefs))), + "help:gnome-help/color-howtoimport", + GDK_CURRENT_TIME); +} + +static void +gcm_prefs_profile_add_cb (CcColorPanel *prefs) +{ + g_autoptr(GPtrArray) profiles = NULL; + + /* add profiles of the right kind */ + profiles = cd_device_get_profiles (prefs->current_device); + gcm_prefs_add_profiles_suitable_for_devices (prefs, profiles); + + /* make insensitive until we have a selection */ + gtk_widget_set_sensitive (prefs->button_assign_ok, FALSE); + + /* show the dialog */ + gtk_window_set_transient_for (GTK_WINDOW (prefs->dialog_assign), + GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (prefs)))); + + gtk_widget_show (prefs->dialog_assign); +} + +static void +gcm_prefs_profile_remove_cb (CcColorPanel *prefs) +{ + CdProfile *profile; + gboolean ret = FALSE; + g_autoptr(GError) error = NULL; + GtkListBoxRow *row; + + /* get the selected profile */ + row = gtk_list_box_get_selected_row (prefs->list_box); + if (row == NULL) + return; + profile = cc_color_profile_get_profile (CC_COLOR_PROFILE (row)); + if (profile == NULL) + { + g_warning ("failed to get the active profile"); + return; + } + + /* just remove it, the list store will get ::changed */ + ret = cd_device_remove_profile_sync (prefs->current_device, + profile, + cc_panel_get_cancellable (CC_PANEL (prefs)), + &error); + if (!ret) + g_warning ("failed to remove profile: %s", error->message); +} + +static void +gcm_prefs_make_profile_default_cb (GObject *object, + GAsyncResult *res, + CcColorPanel *prefs) +{ + 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); + } + else + { + gcm_prefs_refresh_toolbar_buttons (prefs); + } +} + +static void +gcm_prefs_device_profile_enable_cb (CcColorPanel *prefs) +{ + CdProfile *profile; + GtkListBoxRow *row; + + /* get the selected profile */ + row = gtk_list_box_get_selected_row (prefs->list_box); + if (row == NULL) + return; + profile = cc_color_profile_get_profile (CC_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 (prefs->current_device)); + cd_device_make_profile_default (prefs->current_device, + profile, + cc_panel_get_cancellable (CC_PANEL (prefs)), + (GAsyncReadyCallback) gcm_prefs_make_profile_default_cb, + prefs); +} + +static void +gcm_prefs_profile_view (CcColorPanel *prefs, CdProfile *profile) +{ + GtkNative *native; + GdkSurface *surface; + g_autoptr(GPtrArray) argv = NULL; + guint xid = 0; + gboolean ret; + g_autoptr(GError) error = NULL; + + /* get xid */ + native = gtk_widget_get_native (GTK_WIDGET (prefs)); + surface = gtk_native_get_surface (native); + + if (GDK_IS_X11_SURFACE (surface)) + xid = gdk_x11_surface_get_xid (GDK_X11_SURFACE (surface)); + + /* open up gcm-viewer as a info pane */ + argv = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (argv, g_strdup ("gcm-viewer")); + g_ptr_array_add (argv, g_strdup ("--profile")); + g_ptr_array_add (argv, g_strdup (cd_profile_get_id (profile))); + g_ptr_array_add (argv, g_strdup ("--parent-window")); + g_ptr_array_add (argv, g_strdup_printf ("%i", xid)); + g_ptr_array_add (argv, NULL); + ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, &error); + if (!ret) + g_warning ("failed to run calibrate: %s", error->message); +} + +static void +gcm_prefs_profile_assign_link_activate_cb (CcColorPanel *prefs, + const gchar *uri) +{ + CdProfile *profile; + GtkListBoxRow *row; + + /* get the selected profile */ + row = gtk_list_box_get_selected_row (prefs->list_box); + if (row == NULL) + return; + profile = cc_color_profile_get_profile (CC_COLOR_PROFILE (row)); + if (profile == NULL) + { + g_warning ("failed to get the active profile"); + return; + } + + /* show it in the viewer */ + gcm_prefs_profile_view (prefs, profile); +} + +static void +gcm_prefs_profile_view_cb (CcColorPanel *prefs) +{ + CdProfile *profile; + GtkListBoxRow *row; + + /* get the selected profile */ + row = gtk_list_box_get_selected_row (prefs->list_box); + if (row == NULL) + return; + profile = cc_color_profile_get_profile (CC_COLOR_PROFILE (row)); + if (profile == NULL) + { + g_warning ("failed to get the active profile"); + return; + } + + /* open up gcm-viewer as a info pane */ + gcm_prefs_profile_view (prefs, profile); +} + +static void +gcm_prefs_button_assign_ok_cb (CcColorPanel *prefs) +{ + GtkTreeIter iter; + GtkTreeModel *model; + g_autoptr(CdProfile) profile = NULL; + gboolean ret = FALSE; + g_autoptr(GError) error = NULL; + GtkTreeSelection *selection; + + /* hide window */ + gtk_widget_hide (GTK_WIDGET (prefs->dialog_assign)); + + /* get the selected profile */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->treeview_assign)); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + gtk_tree_model_get (model, &iter, + GCM_PREFS_COMBO_COLUMN_PROFILE, &profile, + -1); + if (profile == NULL) + { + g_warning ("failed to get the active profile"); + return; + } + + /* if the device is disabled, enable the device so that we can + * add color profiles to it */ + if (!cd_device_get_enabled (prefs->current_device)) + { + ret = cd_device_set_enabled_sync (prefs->current_device, + TRUE, + cc_panel_get_cancellable (CC_PANEL (prefs)), + &error); + if (!ret) + { + g_warning ("failed to enabled device: %s", error->message); + return; + } + } + + /* just add it, the list store will get ::changed */ + ret = cd_device_add_profile_sync (prefs->current_device, + CD_DEVICE_RELATION_HARD, + profile, + cc_panel_get_cancellable (CC_PANEL (prefs)), + &error); + if (!ret) + { + g_warning ("failed to add: %s", error->message); + return; + } + + /* make it default */ + cd_device_make_profile_default (prefs->current_device, + profile, + cc_panel_get_cancellable (CC_PANEL (prefs)), + (GAsyncReadyCallback) gcm_prefs_make_profile_default_cb, + prefs); +} + +static void +gcm_prefs_add_profiles_columns (CcColorPanel *prefs, + GtkTreeView *treeview) +{ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + /* text */ + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "markup", GCM_PREFS_COMBO_COLUMN_TEXT); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (treeview, column); + + /* image */ + column = gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_add_attribute (column, renderer, + "icon-name", GCM_PREFS_COMBO_COLUMN_WARNING_FILENAME); + gtk_tree_view_append_column (treeview, column); +} + +static void +gcm_prefs_set_calibrate_button_sensitivity (CcColorPanel *prefs) +{ + gboolean ret = FALSE; + const gchar *tooltip; + CdDeviceKind kind; + CdSensor *sensor_tmp; + + /* TRANSLATORS: this is when the button is sensitive */ + tooltip = _("Create a color profile for the selected device"); + + /* no device selected */ + if (prefs->current_device == NULL) + goto out; + + /* are we a display */ + kind = cd_device_get_kind (prefs->current_device); + if (kind == CD_DEVICE_KIND_DISPLAY) + { + + /* find whether we have hardware installed */ + if (prefs->sensors == NULL || prefs->sensors->len == 0) + { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected."); + goto out; + } + + /* success */ + ret = TRUE; + + } + else if (kind == CD_DEVICE_KIND_SCANNER || + kind == CD_DEVICE_KIND_CAMERA || + kind == CD_DEVICE_KIND_WEBCAM) + { + + /* TODO: find out if we can scan using gnome-scan */ + ret = TRUE; + + } + else if (kind == CD_DEVICE_KIND_PRINTER) + { + + /* find whether we have hardware installed */ + if (prefs->sensors == NULL || prefs->sensors->len == 0) + { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected."); + goto out; + } + + /* find whether we have hardware installed */ + sensor_tmp = g_ptr_array_index (prefs->sensors, 0); + ret = cd_sensor_has_cap (sensor_tmp, CD_SENSOR_CAP_PRINTER); + if (!ret) + { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The measuring instrument does not support printer profiling."); + goto out; + } + + /* success */ + ret = TRUE; + + } + else + { + /* TRANSLATORS: this is when the button is insensitive */ + tooltip = _("The device type is not currently supported."); + } +out: + /* control the tooltip and sensitivity of the button */ + gtk_widget_set_tooltip_text (prefs->toolbutton_device_calibrate, tooltip); + gtk_widget_set_sensitive (prefs->toolbutton_device_calibrate, ret); +} + +static void +gcm_prefs_device_clicked (CcColorPanel *prefs, CdDevice *device) +{ + /* we have a new device */ + g_debug ("selected device is: %s", + cd_device_get_id (device)); + + /* can this device calibrate */ + gcm_prefs_set_calibrate_button_sensitivity (prefs); +} + +static void +gcm_prefs_profile_clicked (CcColorPanel *prefs, CdProfile *profile, CdDevice *device) +{ + g_autofree gchar *s = NULL; + + /* get profile */ + g_debug ("selected profile = %s", + cd_profile_get_filename (profile)); + + /* allow getting profile info */ + if (cd_profile_get_filename (profile) != NULL && + (s = g_find_program_in_path ("gcm-viewer")) != NULL) + gtk_widget_set_sensitive (prefs->toolbutton_profile_view, TRUE); + else + gtk_widget_set_sensitive (prefs->toolbutton_profile_view, FALSE); +} + +static void +gcm_prefs_profiles_treeview_clicked_cb (CcColorPanel *prefs, + GtkTreeSelection *selection) +{ + GtkTreeModel *model; + GtkTreeIter iter; + g_autoptr(CdProfile) profile = NULL; +#if CD_CHECK_VERSION(0,1,25) + gchar **warnings; +#endif + + /* get selection */ + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + gtk_tree_model_get (model, &iter, + GCM_PREFS_COMBO_COLUMN_PROFILE, &profile, + -1); + + /* as soon as anything is selected, make the Add button sensitive */ + gtk_widget_set_sensitive (prefs->button_assign_ok, TRUE); + + /* is the profile faulty */ +#if CD_CHECK_VERSION(0,1,25) + warnings = cd_profile_get_warnings (profile); + gtk_widget_set_visible (prefs->label_assign_warning, warnings != NULL && warnings[0] != NULL); +#else + gtk_widget_set_visible (prefs->label_assign_warning, FALSE); +#endif +} + +static void +gcm_prefs_profiles_row_activated_cb (CcColorPanel *prefs, + GtkTreePath *path) +{ + GtkTreeIter iter; + gboolean ret; + + ret = gtk_tree_model_get_iter (gtk_tree_view_get_model (GTK_TREE_VIEW (prefs->treeview_assign)), &iter, path); + if (!ret) + return; + gcm_prefs_button_assign_ok_cb (prefs); +} + + +static void +gcm_prefs_button_assign_import_cb (CcColorPanel *prefs) +{ + g_autoptr(GFile) file = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(CdProfile) profile = NULL; + + file = gcm_prefs_file_chooser_get_icc_profile (prefs); + if (file == NULL) + { + g_warning ("failed to get ICC file"); + gtk_widget_hide (GTK_WIDGET (prefs->dialog_assign)); + return; + } + +#if CD_CHECK_VERSION(0,1,12) + profile = cd_client_import_profile_sync (prefs->client, + file, + cc_panel_get_cancellable (CC_PANEL (prefs)), + &error); + if (profile == NULL) + { + g_warning ("failed to get imported profile: %s", error->message); + return; + } +#endif + + /* add to list view */ + gcm_prefs_profile_add_cb (prefs); +} + +static void +gcm_prefs_sensor_coldplug (CcColorPanel *prefs) +{ + CdSensor *sensor_tmp; + gboolean ret; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) sensors = NULL; + guint i; + + /* unref old */ + g_clear_pointer (&prefs->sensors, g_ptr_array_unref); + + /* no present */ + sensors = cd_client_get_sensors_sync (prefs->client, NULL, &error); + if (sensors == NULL) + { + g_warning ("%s", error->message); + return; + } + if (sensors->len == 0) + return; + + /* save a copy of the sensor list */ + prefs->sensors = g_ptr_array_ref (sensors); + + /* connect to each sensor */ + for (i = 0; i < sensors->len; i++) + { + sensor_tmp = g_ptr_array_index (sensors, i); + ret = cd_sensor_connect_sync (sensor_tmp, NULL, &error); + if (!ret) + { + g_warning ("%s", error->message); + return; + } + } +} + +static void +gcm_prefs_client_sensor_changed_cb (CdClient *client, + CdSensor *sensor, + CcColorPanel *prefs) +{ + gcm_prefs_sensor_coldplug (prefs); + gcm_prefs_set_calibrate_button_sensitivity (prefs); +} + +static void +gcm_prefs_add_device_profile (CcColorPanel *prefs, + CdDevice *device, + CdProfile *profile, + gboolean is_default) +{ + gboolean ret; + g_autoptr(GError) error = NULL; + GtkWidget *widget; + + /* get properties */ + ret = cd_profile_connect_sync (profile, + cc_panel_get_cancellable (CC_PANEL (prefs)), + &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 = cc_color_profile_new (device, profile, is_default); + gtk_list_box_append (prefs->list_box, widget); + gtk_size_group_add_widget (prefs->list_box_size, widget); +} + +static void +gcm_prefs_add_device_profiles (CcColorPanel *prefs, CdDevice *device) +{ + CdProfile *profile_tmp; + g_autoptr(GPtrArray) profiles = NULL; + guint i; + + /* 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); + gcm_prefs_add_device_profile (prefs, device, profile_tmp, i == 0); + } +} + +/* find the profile in the array -- for flicker-free changes */ +static gboolean +gcm_prefs_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 +gcm_prefs_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 (!CC_IS_COLOR_PROFILE (l->data)) + continue; + + /* correct device ? */ + device_tmp = cc_color_profile_get_device (CC_COLOR_PROFILE (l->data)); + if (g_strcmp0 (object_path_device, + cd_device_get_object_path (device_tmp)) != 0) + { + continue; + } + + /* this profile */ + profile_tmp = cc_color_profile_get_profile (CC_COLOR_PROFILE (l->data)); + if (g_strcmp0 (object_path_profile, + cd_profile_get_object_path (profile_tmp)) == 0) + { + return TRUE; + } + } + return FALSE; +} + +static void +gcm_prefs_device_changed_cb (CcColorPanel *prefs, CdDevice *device) +{ + GtkWidget *child; + CdDevice *device_tmp; + CdProfile *profile_tmp; + gboolean ret; + 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); + child = gtk_widget_get_first_child (GTK_WIDGET (prefs->list_box)); + while (child) + { + GtkWidget *next = gtk_widget_get_next_sibling (child); + + if (!CC_IS_COLOR_PROFILE (child)) + { + list = g_list_prepend (list, child); + goto next; + } + + /* correct device ? */ + device_tmp = cc_color_profile_get_device (CC_COLOR_PROFILE (child)); + if (g_strcmp0 (cd_device_get_id (device), + cd_device_get_id (device_tmp)) != 0) + { + list = g_list_prepend (list, child); + goto next; + } + + /* if profile is not in Device.Profiles then remove */ + profile_tmp = cc_color_profile_get_profile (CC_COLOR_PROFILE (child)); + ret = gcm_prefs_find_profile_by_object_path (profiles, + cd_profile_get_object_path (profile_tmp)); + if (!ret) + gtk_list_box_remove (prefs->list_box, child); + else + list = g_list_prepend (list, child); + +next: + child = next; + } + + /* 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 = gcm_prefs_find_widget_by_object_path (list, + cd_device_get_object_path (device), + cd_profile_get_object_path (profile_tmp)); + if (!ret) + gcm_prefs_add_device_profile (prefs, device, profile_tmp, i == 0); + } + + /* resort */ + gtk_list_box_invalidate_sort (prefs->list_box); +} + +static void +gcm_prefs_device_expanded_changed_cb (CcColorPanel *prefs, + gboolean is_expanded, + CcColorDevice *widget) +{ + /* ignore internal changes */ + if (prefs->model_is_changing) + return; + + g_free (prefs->list_box_filter); + if (is_expanded) + { + GtkWidget *child; + + prefs->list_box_filter = g_strdup (cd_device_get_id (cc_color_device_get_device (widget))); + + /* unexpand other device widgets */ + prefs->model_is_changing = TRUE; + for (child = gtk_widget_get_first_child (GTK_WIDGET (prefs->list_box)); + child != NULL; + child = gtk_widget_get_next_sibling (child)) + { + if (!CC_IS_COLOR_DEVICE (child)) + continue; + if (CC_COLOR_DEVICE (child) != widget) + cc_color_device_set_expanded (CC_COLOR_DEVICE (child), FALSE); + } + prefs->model_is_changing = FALSE; + } + else + { + prefs->list_box_filter = NULL; + } + gtk_list_box_invalidate_filter (prefs->list_box); +} + +static void +gcm_prefs_add_device (CcColorPanel *prefs, CdDevice *device) +{ + gboolean ret; + g_autoptr(GError) error = NULL; + GtkWidget *widget; + + /* get device properties */ + ret = cd_device_connect_sync (device, cc_panel_get_cancellable (CC_PANEL (prefs)), &error); + if (!ret) + { + g_warning ("failed to connect to the device: %s", error->message); + return; + } + + /* add device */ + widget = cc_color_device_new (device); + g_signal_connect_object (widget, "expanded-changed", + G_CALLBACK (gcm_prefs_device_expanded_changed_cb), prefs, G_CONNECT_SWAPPED); + gtk_list_box_append (prefs->list_box, widget); + gtk_size_group_add_widget (prefs->list_box_size, widget); + + /* add profiles */ + gcm_prefs_add_device_profiles (prefs, device); + + /* watch for changes */ + g_ptr_array_add (prefs->devices, g_object_ref (device)); + g_signal_connect_object (device, "changed", + G_CALLBACK (gcm_prefs_device_changed_cb), prefs, G_CONNECT_SWAPPED); + gtk_list_box_invalidate_sort (prefs->list_box); +} + +static void +gcm_prefs_remove_device (CcColorPanel *prefs, CdDevice *device) +{ + GtkWidget *child; + CdDevice *device_tmp; + + child = gtk_widget_get_first_child (GTK_WIDGET (prefs->list_box)); + while (child) + { + GtkWidget *next = gtk_widget_get_next_sibling (child); + + if (CC_IS_COLOR_DEVICE (child)) + device_tmp = cc_color_device_get_device (CC_COLOR_DEVICE (child)); + else + device_tmp = cc_color_profile_get_device (CC_COLOR_PROFILE (child)); + if (g_strcmp0 (cd_device_get_object_path (device), + cd_device_get_object_path (device_tmp)) == 0) + { + gtk_list_box_remove (prefs->list_box, child); + } + + child = next; + } + g_signal_handlers_disconnect_by_func (device, + G_CALLBACK (gcm_prefs_device_changed_cb), + prefs); + g_ptr_array_remove (prefs->devices, device); +} + +static void +gcm_prefs_update_device_list_extra_entry (CcColorPanel *prefs) +{ + GtkListBoxRow *first_row; + + /* any devices to show? */ + first_row = gtk_list_box_get_row_at_index (prefs->list_box, 0); + gtk_widget_set_visible (prefs->label_no_devices, first_row == NULL); + gtk_widget_set_visible (prefs->box_devices, first_row != NULL); + + /* if we have only one device expand it by default */ + if (first_row != NULL && + gtk_list_box_get_row_at_index (prefs->list_box, 1) == NULL) + cc_color_device_set_expanded (CC_COLOR_DEVICE (first_row), TRUE); +} + +static void +gcm_prefs_device_added_cb (CdClient *client, + CdDevice *device, + CcColorPanel *prefs) +{ + /* add the device */ + gcm_prefs_add_device (prefs, device); + + /* ensure we're not showing the 'No devices detected' entry */ + gcm_prefs_update_device_list_extra_entry (prefs); +} + +static void +gcm_prefs_device_removed_cb (CdClient *client, + CdDevice *device, + CcColorPanel *prefs) +{ + /* remove from the UI */ + gcm_prefs_remove_device (prefs, device); + + /* ensure we showing the 'No devices detected' entry if required */ + gcm_prefs_update_device_list_extra_entry (prefs); +} + +static void +gcm_prefs_get_devices_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + CcColorPanel *prefs = (CcColorPanel *) user_data; + CdClient *client = CD_CLIENT (object); + CdDevice *device; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) devices = NULL; + guint i; + + /* get devices and add them */ + devices = cd_client_get_devices_finish (client, res, &error); + if (devices == NULL) + { + g_warning ("failed to add connected devices: %s", + error->message); + return; + } + for (i = 0; i < devices->len; i++) + { + device = g_ptr_array_index (devices, i); + gcm_prefs_add_device (prefs, device); + } + + /* ensure we show the 'No devices detected' entry if empty */ + gcm_prefs_update_device_list_extra_entry (prefs); +} + +static void +gcm_prefs_list_box_row_selected_cb (CcColorPanel *panel, + GtkListBoxRow *row) +{ + if (gtk_widget_in_destruction (panel->toolbar_devices)) + return; + + gcm_prefs_refresh_toolbar_buttons (panel); +} + +static void +gcm_prefs_refresh_toolbar_buttons (CcColorPanel *panel) +{ + CdProfile *profile = NULL; + GtkListBoxRow *row; + gboolean is_device; + + /* get the selected profile */ + row = gtk_list_box_get_selected_row (panel->list_box); + + is_device = CC_IS_COLOR_DEVICE (row); + + /* nothing selected */ + gtk_widget_set_visible (panel->toolbar_devices, row != NULL); + if (row == NULL) + return; + + /* save current device */ + g_clear_object (&panel->current_device); + g_object_get (row, "device", &panel->current_device, NULL); + + /* device actions */ + g_debug ("%s selected", is_device ? "device" : "profile"); + if (CC_IS_COLOR_DEVICE (row)) + { + gcm_prefs_device_clicked (panel, panel->current_device); + cc_color_device_set_expanded (CC_COLOR_DEVICE (row), TRUE); + } + else if (CC_IS_COLOR_PROFILE (row)) + { + profile = cc_color_profile_get_profile (CC_COLOR_PROFILE (row)); + gcm_prefs_profile_clicked (panel, profile, panel->current_device); + } + else + g_assert_not_reached (); + + gtk_widget_set_visible (panel->toolbutton_device_default, !is_device && cc_color_profile_get_is_default (CC_COLOR_PROFILE (row))); + if (profile) + gtk_widget_set_sensitive (panel->toolbutton_device_default, !cd_profile_get_is_system_wide (profile)); + gtk_widget_set_visible (panel->toolbutton_device_enable, !is_device && !cc_color_profile_get_is_default (CC_COLOR_PROFILE (row))); + gtk_widget_set_visible (panel->toolbutton_device_calibrate, is_device); + gtk_widget_set_visible (panel->toolbutton_profile_add, is_device); + gtk_widget_set_visible (panel->toolbutton_profile_view, !is_device); + gtk_widget_set_visible (panel->toolbutton_profile_remove, !is_device); +} + +static void +gcm_prefs_list_box_row_activated_cb (CcColorPanel *prefs, + GtkListBoxRow *row) +{ + if (CC_IS_COLOR_PROFILE (row)) + { + gcm_prefs_device_profile_enable_cb (prefs); + } +} + +static void +gcm_prefs_connect_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + CcColorPanel *prefs; + gboolean ret; + g_autoptr(GError) error = NULL; + + ret = cd_client_connect_finish (CD_CLIENT (object), + res, + &error); + if (!ret) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("failed to connect to colord: %s", error->message); + return; + } + + /* 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. */ + prefs = CC_COLOR_PANEL (user_data); + + /* set calibrate button sensitivity */ + gcm_prefs_sensor_coldplug (prefs); + + /* get devices */ + cd_client_get_devices (prefs->client, + cc_panel_get_cancellable (CC_PANEL (prefs)), + gcm_prefs_get_devices_cb, + prefs); +} + +static gboolean +gcm_prefs_is_livecd (void) +{ +#ifdef __linux__ + gboolean ret = TRUE; + g_autofree gchar *data = NULL; + g_autoptr(GError) error = NULL; + + /* allow testing */ + if (g_getenv ("CC_COLOR_PANEL_IS_LIVECD") != NULL) + return TRUE; + + /* get the kernel commandline */ + ret = g_file_get_contents ("/proc/cmdline", &data, NULL, &error); + if (!ret) + { + g_warning ("failed to get kernel command line: %s", + error->message); + return TRUE; + } + return (g_strstr_len (data, -1, "liveimg") != NULL || + g_strstr_len (data, -1, "casper") != NULL); +#else + return FALSE; +#endif +} + +static const char * +cc_color_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/color"; +} + +static void +cc_color_panel_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_color_panel_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +cc_color_panel_dispose (GObject *object) +{ + CcColorPanel *prefs = CC_COLOR_PANEL (object); + + g_clear_object (&prefs->settings); + g_clear_object (&prefs->settings_colord); + g_clear_object (&prefs->client); + g_clear_object (&prefs->current_device); + g_clear_pointer (&prefs->devices, g_ptr_array_unref); + g_clear_object (&prefs->calibrate); + g_clear_object (&prefs->list_box_size); + g_clear_pointer (&prefs->sensors, g_ptr_array_unref); + g_clear_pointer (&prefs->list_box_filter, g_free); + g_clear_pointer ((GtkWindow **)&prefs->dialog_assign, gtk_window_destroy); + + G_OBJECT_CLASS (cc_color_panel_parent_class)->dispose (object); +} + +static void +cc_color_panel_finalize (GObject *object) +{ + G_OBJECT_CLASS (cc_color_panel_parent_class)->finalize (object); +} + +static void +cc_color_panel_class_init (CcColorPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + panel_class->get_help_uri = cc_color_panel_get_help_uri; + + object_class->get_property = cc_color_panel_get_property; + object_class->set_property = cc_color_panel_set_property; + object_class->dispose = cc_color_panel_dispose; + object_class->finalize = cc_color_panel_finalize; + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/color/cc-color-panel.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, assistant_calib); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_brightness); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_kind); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_quality); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_sensor); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_summary); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_temp); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_title); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_devices); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, button_assign_import); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, button_assign_ok); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, button_calib_export); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, dialog_assign); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, entry_calib_title); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, label_assign_warning); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, label_calib_summary_message); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, label_no_devices); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, list_box); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, liststore_assign); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, liststore_calib_kind); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, liststore_calib_sensor); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbar_devices); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_device_calibrate); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_device_default); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_device_enable); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_profile_add); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_profile_remove); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_profile_view); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, treeview_assign); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, treeview_calib_kind); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, treeview_calib_quality); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, treeview_calib_sensor); + gtk_widget_class_bind_template_child (widget_class, CcColorPanel, treeview_calib_temp); +} + +static gint +cc_color_panel_sort_func (GtkListBoxRow *a, + GtkListBoxRow *b, + gpointer user_data) +{ + const gchar *sort_a = NULL; + const gchar *sort_b = NULL; + if (CC_IS_COLOR_DEVICE (a)) + sort_a = cc_color_device_get_sortable (CC_COLOR_DEVICE (a)); + else if (CC_IS_COLOR_PROFILE (a)) + sort_a = cc_color_profile_get_sortable (CC_COLOR_PROFILE (a)); + else + g_assert_not_reached (); + if (CC_IS_COLOR_DEVICE (b)) + sort_b = cc_color_device_get_sortable (CC_COLOR_DEVICE (b)); + else if (CC_IS_COLOR_PROFILE (b)) + sort_b = cc_color_profile_get_sortable (CC_COLOR_PROFILE (b)); + else + g_assert_not_reached (); + return g_strcmp0 (sort_b, sort_a); +} + +static gboolean +cc_color_panel_filter_func (GtkListBoxRow *row, void *user_data) +{ + CcColorPanel *prefs = CC_COLOR_PANEL (user_data); + g_autoptr(CdDevice) device = NULL; + + /* always show all devices */ + if (CC_IS_COLOR_DEVICE (row)) + return TRUE; + + g_object_get (row, "device", &device, NULL); + return g_strcmp0 (cd_device_get_id (device), prefs->list_box_filter) == 0; +} + +static gboolean +cc_color_panel_treeview_quality_default_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + CdProfileQuality quality; + GtkTreeSelection *selection = GTK_TREE_SELECTION (data); + + gtk_tree_model_get (model, iter, + COLUMN_CALIB_QUALITY_VALUE, &quality, + -1); + if (quality == CD_PROFILE_QUALITY_MEDIUM) + gtk_tree_selection_select_iter (selection, iter); + return FALSE; +} + +static void +cc_color_panel_init (CcColorPanel *prefs) +{ + GtkCellRenderer *renderer; + GtkTreeModel *model; + GtkTreeModel *model_filter; + GtkTreeSelection *selection; + GtkTreeViewColumn *column; + + g_resources_register (cc_color_get_resource ()); + + gtk_widget_init_template (GTK_WIDGET (prefs)); + + prefs->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + + /* can do native display calibration using colord-session */ + prefs->calibrate = cc_color_calibrate_new (); + cc_color_calibrate_set_quality (prefs->calibrate, CD_PROFILE_QUALITY_MEDIUM); + + /* setup defaults */ + prefs->settings = g_settings_new (GCM_SETTINGS_SCHEMA); + prefs->settings_colord = g_settings_new (COLORD_SETTINGS_SCHEMA); + + /* assign buttons */ + g_signal_connect_object (prefs->toolbutton_profile_add, "clicked", + G_CALLBACK (gcm_prefs_profile_add_cb), prefs, G_CONNECT_SWAPPED); + g_signal_connect_object (prefs->toolbutton_profile_remove, "clicked", + G_CALLBACK (gcm_prefs_profile_remove_cb), prefs, G_CONNECT_SWAPPED); + g_signal_connect_object (prefs->toolbutton_profile_view, "clicked", + G_CALLBACK (gcm_prefs_profile_view_cb), prefs, G_CONNECT_SWAPPED); + + /* href */ + g_signal_connect_object (prefs->label_assign_warning, "activate-link", + G_CALLBACK (gcm_prefs_profile_assign_link_activate_cb), prefs, G_CONNECT_SWAPPED); + + /* add columns to profile tree view */ + gcm_prefs_add_profiles_columns (prefs, GTK_TREE_VIEW (prefs->treeview_assign)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->treeview_assign)); + g_signal_connect_object (selection, "changed", + G_CALLBACK (gcm_prefs_profiles_treeview_clicked_cb), + prefs, G_CONNECT_SWAPPED); + g_signal_connect_object (prefs->treeview_assign, "row-activated", + G_CALLBACK (gcm_prefs_profiles_row_activated_cb), + prefs, G_CONNECT_SWAPPED); + + g_signal_connect_object (prefs->toolbutton_device_default, "clicked", + G_CALLBACK (gcm_prefs_default_cb), prefs, G_CONNECT_SWAPPED); + g_signal_connect_object (prefs->toolbutton_device_enable, "clicked", + G_CALLBACK (gcm_prefs_device_profile_enable_cb), prefs, G_CONNECT_SWAPPED); + g_signal_connect_object (prefs->toolbutton_device_calibrate, "clicked", + G_CALLBACK (gcm_prefs_calibrate_cb), prefs, G_CONNECT_SWAPPED); + + /* set up assign dialog */ + g_signal_connect_object (prefs->button_assign_ok, "clicked", + G_CALLBACK (gcm_prefs_button_assign_ok_cb), prefs, G_CONNECT_SWAPPED); + + /* setup icc profiles list */ + g_signal_connect_object (prefs->button_assign_import, "clicked", + G_CALLBACK (gcm_prefs_button_assign_import_cb), prefs, G_CONNECT_SWAPPED); + + /* setup the calibration helper */ + g_signal_connect_object (prefs->assistant_calib, "apply", + G_CALLBACK (gcm_prefs_calib_apply_cb), + prefs, G_CONNECT_SWAPPED); + g_signal_connect_object (prefs->assistant_calib, "cancel", + G_CALLBACK (gcm_prefs_calib_cancel_cb), + prefs, G_CONNECT_SWAPPED); + g_signal_connect_object (prefs->assistant_calib, "close", + G_CALLBACK (gcm_prefs_calib_cancel_cb), + prefs, G_CONNECT_SWAPPED); + g_signal_connect_object (prefs->assistant_calib, "prepare", + G_CALLBACK (gcm_prefs_calib_prepare_cb), + prefs, G_CONNECT_SWAPPED); + + /* setup the calibration helper ::TreeView */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->treeview_calib_quality)); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (prefs->treeview_calib_quality)); + gtk_tree_model_foreach (model, + cc_color_panel_treeview_quality_default_cb, + selection); + g_signal_connect_object (selection, "changed", + G_CALLBACK (gcm_prefs_calib_quality_treeview_clicked_cb), + prefs, G_CONNECT_SWAPPED); + column = gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 9, + "ypad", 9, + NULL); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "markup", COLUMN_CALIB_QUALITY_DESCRIPTION); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (prefs->treeview_calib_quality), + GTK_TREE_VIEW_COLUMN (column)); + column = gtk_tree_view_column_new (); + renderer = cc_color_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 9, + "ypad", 9, + "is-dim-label", TRUE, + NULL); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "markup", COLUMN_CALIB_QUALITY_APPROX_TIME); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_append_column (GTK_TREE_VIEW (prefs->treeview_calib_quality), + GTK_TREE_VIEW_COLUMN (column)); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->treeview_calib_sensor)); + g_signal_connect_object (selection, "changed", + G_CALLBACK (gcm_prefs_calib_sensor_treeview_clicked_cb), + prefs, G_CONNECT_SWAPPED); + column = gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 9, + "ypad", 9, + NULL); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "markup", COLUMN_CALIB_SENSOR_DESCRIPTION); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (prefs->treeview_calib_sensor), + GTK_TREE_VIEW_COLUMN (column)); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->treeview_calib_kind)); + g_signal_connect_object (selection, "changed", + G_CALLBACK (gcm_prefs_calib_kind_treeview_clicked_cb), + prefs, G_CONNECT_SWAPPED); + column = gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 9, + "ypad", 9, + NULL); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "markup", COLUMN_CALIB_KIND_DESCRIPTION); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (prefs->treeview_calib_kind)); + model_filter = gtk_tree_model_filter_new (model, NULL); + gtk_tree_view_set_model (GTK_TREE_VIEW (prefs->treeview_calib_kind), model_filter); + gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (model_filter), + COLUMN_CALIB_KIND_VISIBLE); + + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (prefs->treeview_calib_kind), + GTK_TREE_VIEW_COLUMN (column)); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (prefs->treeview_calib_temp)); + g_signal_connect_object (selection, "changed", + G_CALLBACK (gcm_prefs_calib_temp_treeview_clicked_cb), + prefs, G_CONNECT_SWAPPED); + column = gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, + "xpad", 9, + "ypad", 9, + NULL); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_add_attribute (column, renderer, + "markup", COLUMN_CALIB_TEMP_DESCRIPTION); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (prefs->treeview_calib_temp), + GTK_TREE_VIEW_COLUMN (column)); + g_signal_connect_object (prefs->entry_calib_title, "notify::text", + G_CALLBACK (gcm_prefs_title_entry_changed_cb), prefs, G_CONNECT_SWAPPED); + + /* use a device client array */ + prefs->client = cd_client_new (); + g_signal_connect_object (prefs->client, "device-added", + G_CALLBACK (gcm_prefs_device_added_cb), prefs, 0); + g_signal_connect_object (prefs->client, "device-removed", + G_CALLBACK (gcm_prefs_device_removed_cb), prefs, 0); + + /* use a listbox for the main UI */ + gtk_list_box_set_filter_func (prefs->list_box, + cc_color_panel_filter_func, + prefs, + NULL); + gtk_list_box_set_sort_func (prefs->list_box, + cc_color_panel_sort_func, + prefs, + NULL); + g_signal_connect_object (prefs->list_box, "row-selected", + G_CALLBACK (gcm_prefs_list_box_row_selected_cb), + prefs, G_CONNECT_SWAPPED); + g_signal_connect_object (prefs->list_box, "row-activated", + G_CALLBACK (gcm_prefs_list_box_row_activated_cb), + prefs, G_CONNECT_SWAPPED); + prefs->list_box_size = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); + + /* connect to colord */ + cd_client_connect (prefs->client, + cc_panel_get_cancellable (CC_PANEL (prefs)), + gcm_prefs_connect_cb, + prefs); + + /* use the color sensor */ + g_signal_connect_object (prefs->client, "sensor-added", + G_CALLBACK (gcm_prefs_client_sensor_changed_cb), + prefs, 0); + g_signal_connect_object (prefs->client, "sensor-removed", + G_CALLBACK (gcm_prefs_client_sensor_changed_cb), + prefs, 0); + + /* set calibrate button sensitivity */ + gcm_prefs_set_calibrate_button_sensitivity (prefs); + + /* show the confirmation export page if we are running from a LiveCD */ + prefs->is_live_cd = gcm_prefs_is_livecd (); + gtk_widget_set_visible (prefs->box_calib_summary, prefs->is_live_cd); + g_signal_connect_object (prefs->button_calib_export, "clicked", + G_CALLBACK (gcm_prefs_calib_export_cb), prefs, G_CONNECT_SWAPPED); + g_signal_connect_object (prefs->label_calib_summary_message, "activate-link", + G_CALLBACK (gcm_prefs_calib_export_link_cb), prefs, G_CONNECT_SWAPPED); +} |