GCC Code Coverage Report


Directory: ./
File: panels/color/cc-color-panel.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 896 0.0%
Functions: 0 72 0.0%
Branches: 0 387 0.0%

Line Branch Exec Source
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (C) 2010 Red Hat, Inc
4 * Copyright (C) 2011 Richard Hughes <richard@hughsie.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <config.h>
22
23 #include <glib/gi18n.h>
24 #include <colord.h>
25 #include <gtk/gtk.h>
26 #include <gdk/x11/gdkx.h>
27
28 #include "cc-color-calibrate.h"
29 #include "cc-color-cell-renderer-text.h"
30 #include "cc-color-panel.h"
31 #include "cc-color-resources.h"
32 #include "cc-color-common.h"
33 #include "cc-color-device.h"
34 #include "cc-color-profile.h"
35
36 struct _CcColorPanel
37 {
38 CcPanel parent_instance;
39
40 CdClient *client;
41 CdDevice *current_device;
42 GPtrArray *devices;
43 GPtrArray *sensors;
44 GDBusProxy *proxy;
45 GSettings *settings;
46 GSettings *settings_colord;
47 GtkWidget *assistant_calib;
48 GtkWidget *box_calib_brightness;
49 GtkWidget *box_calib_kind;
50 GtkWidget *box_calib_quality;
51 GtkWidget *box_calib_sensor;
52 GtkWidget *box_calib_summary;
53 GtkWidget *box_calib_temp;
54 GtkWidget *box_calib_title;
55 GtkWidget *button_assign_import;
56 GtkWidget *button_assign_ok;
57 GtkWidget *button_calib_export;
58 GtkWidget *dialog_assign;
59 GtkWidget *entry_calib_title;
60 GtkWidget *label_assign_warning;
61 GtkWidget *label_calib_summary_message;
62 GtkTreeModel *liststore_assign;
63 GtkTreeModel *liststore_calib_kind;
64 GtkTreeModel *liststore_calib_sensor;
65 AdwViewStack *stack;
66 AdwPreferencesPage *color_page;
67 GtkWidget *toolbar_devices;
68 GtkWidget *toolbutton_device_calibrate;
69 GtkWidget *toolbutton_device_default;
70 GtkWidget *toolbutton_device_enable;
71 GtkWidget *toolbutton_profile_add;
72 GtkWidget *toolbutton_profile_remove;
73 GtkWidget *toolbutton_profile_view;
74 GtkWidget *treeview_assign;
75 GtkWidget *treeview_calib_kind;
76 GtkWidget *treeview_calib_quality;
77 GtkWidget *treeview_calib_sensor;
78 GtkWidget *treeview_calib_temp;
79 CcColorCalibrate *calibrate;
80 GtkListBox *list_box;
81 gchar *list_box_filter;
82 GtkSizeGroup *list_box_size;
83 gboolean is_live_cd;
84 gboolean model_is_changing;
85 };
86
87 CC_PANEL_REGISTER (CcColorPanel, cc_color_panel)
88
89 enum {
90 GCM_PREFS_COMBO_COLUMN_TEXT,
91 GCM_PREFS_COMBO_COLUMN_PROFILE,
92 GCM_PREFS_COMBO_COLUMN_TYPE,
93 GCM_PREFS_COMBO_COLUMN_WARNING_FILENAME,
94 GCM_PREFS_COMBO_COLUMN_NUM_COLUMNS
95 };
96
97 /* for the GtkListStores */
98 enum {
99 COLUMN_CALIB_KIND_DESCRIPTION,
100 COLUMN_CALIB_KIND_CAP_VALUE,
101 COLUMN_CALIB_KIND_VISIBLE,
102 COLUMN_CALIB_KIND_LAST
103 };
104 enum {
105 COLUMN_CALIB_QUALITY_DESCRIPTION,
106 COLUMN_CALIB_QUALITY_APPROX_TIME,
107 COLUMN_CALIB_QUALITY_VALUE,
108 COLUMN_CALIB_QUALITY_LAST
109 };
110 enum {
111 COLUMN_CALIB_SENSOR_OBJECT,
112 COLUMN_CALIB_SENSOR_DESCRIPTION,
113 COLUMN_CALIB_SENSOR_LAST
114 };
115 enum {
116 COLUMN_CALIB_TEMP_DESCRIPTION,
117 COLUMN_CALIB_TEMP_VALUE_K,
118 COLUMN_CALIB_TEMP_LAST
119 };
120
121 #define COLORD_SETTINGS_SCHEMA "org.freedesktop.ColorHelper"
122 #define GCM_SETTINGS_SCHEMA "org.gnome.settings-daemon.plugins.color"
123 #define GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD "recalibrate-printer-threshold"
124 #define GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD "recalibrate-display-threshold"
125
126 /* max number of devices and profiles to cause auto-expand at startup */
127 #define GCM_PREFS_MAX_DEVICES_PROFILES_EXPANDED 5
128
129 static void gcm_prefs_profile_add_cb (CcColorPanel *self);
130 static void gcm_prefs_refresh_toolbar_buttons (CcColorPanel *self);
131
132 static void
133 gcm_prefs_combobox_add_profile (CcColorPanel *self,
134 CdProfile *profile,
135 GtkTreeIter *iter)
136 {
137 const gchar *id;
138 GtkTreeIter iter_tmp;
139 g_autoptr(GString) string = NULL;
140 gchar *escaped = NULL;
141 guint kind = 0;
142 const gchar *warning = NULL;
143 #if CD_CHECK_VERSION(0,1,25)
144 gchar **warnings;
145 #endif
146
147 /* iter is optional */
148 if (iter == NULL)
149 iter = &iter_tmp;
150
151 /* use description */
152 string = g_string_new (cd_profile_get_title (profile));
153
154 /* any source prefix? */
155 id = cd_profile_get_metadata_item (profile,
156 CD_PROFILE_METADATA_DATA_SOURCE);
157 if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_EDID) == 0)
158 {
159 /* TRANSLATORS: this is a profile prefix to signify the
160 * profile has been auto-generated for this hardware */
161 g_string_prepend (string, _("Default: "));
162 kind = 1;
163 }
164 #if CD_CHECK_VERSION(0,1,14)
165 if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0)
166 {
167 /* TRANSLATORS: this is a profile prefix to signify the
168 * profile his a standard space like AdobeRGB */
169 g_string_prepend (string, _("Colorspace: "));
170 kind = 2;
171 }
172 if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_TEST) == 0)
173 {
174 /* TRANSLATORS: this is a profile prefix to signify the
175 * profile is a test profile */
176 g_string_prepend (string, _("Test profile: "));
177 kind = 3;
178 }
179 #endif
180
181 /* is the profile faulty */
182 #if CD_CHECK_VERSION(0,1,25)
183 warnings = cd_profile_get_warnings (profile);
184 if (warnings != NULL && warnings[0] != NULL)
185 warning = "dialog-warning-symbolic";
186 #endif
187
188 escaped = g_markup_escape_text (string->str, -1);
189 gtk_list_store_append (GTK_LIST_STORE (self->liststore_assign), iter);
190 gtk_list_store_set (GTK_LIST_STORE (self->liststore_assign), iter,
191 GCM_PREFS_COMBO_COLUMN_TEXT, escaped,
192 GCM_PREFS_COMBO_COLUMN_PROFILE, profile,
193 GCM_PREFS_COMBO_COLUMN_TYPE, kind,
194 GCM_PREFS_COMBO_COLUMN_WARNING_FILENAME, warning,
195 -1);
196 }
197
198 static void
199 gcm_prefs_default_cb (CcColorPanel *self)
200 {
201 g_autoptr(CdProfile) profile = NULL;
202 gboolean ret;
203 g_autoptr(GError) error = NULL;
204
205 /* TODO: check if the profile is already systemwide */
206 profile = cd_device_get_default_profile (self->current_device);
207 if (profile == NULL)
208 return;
209
210 /* install somewhere out of $HOME */
211 ret = cd_profile_install_system_wide_sync (profile,
212 cc_panel_get_cancellable (CC_PANEL (self)),
213 &error);
214 if (!ret)
215 g_warning ("failed to set profile system-wide: %s",
216 error->message);
217 }
218
219 static void
220 icc_prefs_imported_cb (GObject *source,
221 GAsyncResult *res,
222 gpointer user_data)
223 {
224 CcColorPanel *self = CC_COLOR_PANEL (user_data);
225 GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
226 g_autoptr(GFile) file = NULL;
227 g_autoptr(GError) error = NULL;
228 g_autoptr(CdProfile) profile = NULL;
229
230 file = gtk_file_dialog_open_finish (dialog, res, &error);
231 if (file == NULL)
232 {
233 g_warning ("Failed to get ICC file: %s", error->message);
234 gtk_widget_set_visible (GTK_WIDGET (self->dialog_assign), FALSE);
235 return;
236 }
237
238 #if CD_CHECK_VERSION(0,1,12)
239 profile = cd_client_import_profile_sync (self->client,
240 file,
241 cc_panel_get_cancellable (CC_PANEL (self)),
242 &error);
243 if (profile == NULL)
244 {
245 g_warning ("failed to get imported profile: %s", error->message);
246 return;
247 }
248 #endif
249
250 /* add to list view */
251 gcm_prefs_profile_add_cb (self);
252 }
253
254 static void
255 gcm_prefs_file_chooser_get_icc_profile (CcColorPanel *self)
256 {
257 g_autoptr(GFile) current_folder = NULL;
258 GtkWindow *window;
259 GtkFileDialog *dialog;
260 GtkFileFilter *filter;
261 GListStore *filters;
262
263 /* create new dialog */
264 window = GTK_WINDOW (self->dialog_assign);
265 dialog = gtk_file_dialog_new ();
266 /* TRANSLATORS: an ICC profile is a file containing colorspace data */
267 gtk_file_dialog_set_title (dialog, _("Select ICC Profile File"));
268 gtk_file_dialog_set_modal (dialog, TRUE);
269
270 gtk_file_dialog_set_accept_label (dialog, _("Import"));
271 current_folder = g_file_new_for_path (g_get_home_dir ());
272 gtk_file_dialog_set_initial_folder (dialog, current_folder);
273
274 filters = g_list_store_new (GTK_TYPE_FILE_FILTER);
275 gtk_file_dialog_set_filters (dialog, G_LIST_MODEL (filters));
276
277 /* setup the filter */
278 filter = gtk_file_filter_new ();
279 gtk_file_filter_add_mime_type (filter, "application/vnd.iccprofile");
280
281 /* TRANSLATORS: filter name on the file->open dialog */
282 gtk_file_filter_set_name (filter, _("Supported ICC profiles"));
283 g_list_store_append (filters, filter);
284
285 /* setup the all files filter */
286 filter = gtk_file_filter_new ();
287 gtk_file_filter_add_pattern (filter, "*");
288 /* TRANSLATORS: filter name on the file->open dialog */
289 gtk_file_filter_set_name (filter, _("All files"));
290 g_list_store_append (filters, filter);
291
292 gtk_file_dialog_open (dialog, window, NULL,
293 icc_prefs_imported_cb, self);
294 }
295
296 static void
297 gcm_prefs_calib_cancel_cb (CcColorPanel *self)
298 {
299 gtk_widget_set_visible (self->assistant_calib, FALSE);
300 }
301
302 static gboolean
303 gcm_prefs_calib_delayed_complete_cb (gpointer user_data)
304 {
305 CcColorPanel *self = CC_COLOR_PANEL (user_data);
306 GtkAssistant *assistant;
307
308 assistant = GTK_ASSISTANT (self->assistant_calib);
309 gtk_assistant_set_page_complete (assistant, self->box_calib_brightness, TRUE);
310 return FALSE;
311 }
312
313 static void
314 gcm_prefs_calib_prepare_cb (CcColorPanel *self,
315 GtkWidget *page)
316 {
317 /* give the user the indication they should actually manually set the
318 * desired brightness rather than clicking blindly by delaying the
319 * "Next" button deliberately for a second or so */
320 if (page == self->box_calib_brightness)
321 {
322 g_timeout_add_seconds (1, gcm_prefs_calib_delayed_complete_cb, self);
323 return;
324 }
325
326 /* disable the brightness page as we don't want to show a 'Finished'
327 * button if the user goes back at any point */
328 gtk_assistant_set_page_complete (GTK_ASSISTANT (self->assistant_calib), self->box_calib_brightness, FALSE);
329 }
330
331 static void
332 gcm_prefs_calib_apply_cb (CcColorPanel *self)
333 {
334 gboolean ret;
335 g_autoptr(GError) error = NULL;
336 GtkWindow *window = NULL;
337
338 /* setup the calibration object with items that can fail */
339 ret = cc_color_calibrate_setup (self->calibrate,
340 &error);
341 if (!ret)
342 {
343 g_warning ("failed to setup calibrate: %s", error->message);
344 return;
345 }
346
347 /* actually start the calibration */
348 window = GTK_WINDOW (self->assistant_calib);
349 ret = cc_color_calibrate_start (self->calibrate,
350 window,
351 &error);
352 if (!ret)
353 {
354 g_warning ("failed to start calibrate: %s", error->message);
355 gtk_window_close (window);
356 return;
357 }
358
359 /* if we are a LiveCD then don't close the window as there is another
360 * summary pane with the export button */
361 if (!self->is_live_cd)
362 gtk_window_close (window);
363 }
364
365 static void
366 gcm_prefs_calib_temp_treeview_clicked_cb (CcColorPanel *self,
367 GtkTreeSelection *selection)
368 {
369 gboolean ret;
370 GtkTreeIter iter;
371 GtkTreeModel *model;
372 guint target_whitepoint;
373 GtkAssistant *assistant;
374
375 /* check to see if anything is selected */
376 ret = gtk_tree_selection_get_selected (selection, &model, &iter);
377 assistant = GTK_ASSISTANT (self->assistant_calib);
378 gtk_assistant_set_page_complete (assistant, self->box_calib_temp, ret);
379 if (!ret)
380 return;
381
382 gtk_tree_model_get (model, &iter,
383 COLUMN_CALIB_TEMP_VALUE_K, &target_whitepoint,
384 -1);
385 cc_color_calibrate_set_temperature (self->calibrate, target_whitepoint);
386 }
387
388 static void
389 gcm_prefs_calib_kind_treeview_clicked_cb (CcColorPanel *self,
390 GtkTreeSelection *selection)
391 {
392 CdSensorCap device_kind;
393 gboolean ret;
394 GtkTreeIter iter;
395 GtkTreeModel *model;
396 GtkAssistant *assistant;
397
398 /* check to see if anything is selected */
399 ret = gtk_tree_selection_get_selected (selection, &model, &iter);
400 assistant = GTK_ASSISTANT (self->assistant_calib);
401 gtk_assistant_set_page_complete (assistant, self->box_calib_kind, ret);
402 if (!ret)
403 return;
404
405 /* save the values if we have a selection */
406 gtk_tree_model_get (model, &iter,
407 COLUMN_CALIB_KIND_CAP_VALUE, &device_kind,
408 -1);
409 cc_color_calibrate_set_kind (self->calibrate, device_kind);
410 }
411
412 static void
413 gcm_prefs_calib_quality_treeview_clicked_cb (CcColorPanel *self,
414 GtkTreeSelection *selection)
415 {
416 CdProfileQuality quality;
417 gboolean ret;
418 GtkAssistant *assistant;
419 GtkTreeIter iter;
420 GtkTreeModel *model;
421
422 /* check to see if anything is selected */
423 ret = gtk_tree_selection_get_selected (selection, &model, &iter);
424 assistant = GTK_ASSISTANT (self->assistant_calib);
425 gtk_assistant_set_page_complete (assistant, self->box_calib_quality, ret);
426 if (!ret)
427 return;
428
429 /* save the values if we have a selection */
430 gtk_tree_model_get (model, &iter,
431 COLUMN_CALIB_QUALITY_VALUE, &quality,
432 -1);
433 cc_color_calibrate_set_quality (self->calibrate, quality);
434 }
435
436 static gboolean
437 gcm_prefs_calib_set_sensor_cap_supported_cb (GtkTreeModel *model,
438 GtkTreePath *path,
439 GtkTreeIter *iter,
440 gpointer data)
441 {
442 CdSensorCap cap;
443 CdSensor *sensor = CD_SENSOR (data);
444 gboolean supported;
445
446 gtk_tree_model_get (model, iter,
447 COLUMN_CALIB_KIND_CAP_VALUE, &cap,
448 -1);
449 supported = cd_sensor_has_cap (sensor, cap);
450 g_debug ("%s(%s) is %s",
451 cd_sensor_get_model (sensor),
452 cd_sensor_cap_to_string (cap),
453 supported ? "supported" : "not-supported");
454 gtk_list_store_set (GTK_LIST_STORE (model), iter,
455 COLUMN_CALIB_KIND_VISIBLE, supported,
456 -1);
457 return FALSE;
458 }
459
460 static guint8
461 _cd_bitfield_popcount (guint64 bitfield)
462 {
463 guint8 i;
464 guint8 tmp = 0;
465 for (i = 0; i < 64; i++)
466 tmp += cd_bitfield_contain (bitfield, i);
467 return tmp;
468 }
469
470 static void
471 gcm_prefs_calib_set_sensor (CcColorPanel *self,
472 CdSensor *sensor)
473 {
474 guint64 caps;
475 guint8 i;
476
477 /* use this sensor for calibration */
478 cc_color_calibrate_set_sensor (self->calibrate, sensor);
479
480 /* hide display types the sensor does not support */
481 gtk_tree_model_foreach (self->liststore_calib_kind,
482 gcm_prefs_calib_set_sensor_cap_supported_cb,
483 sensor);
484
485 /* if the sensor only supports one kind then do not show the panel at all */
486 caps = cd_sensor_get_caps (sensor);
487 if (_cd_bitfield_popcount (caps) == 1)
488 {
489 gtk_widget_set_visible (self->box_calib_kind, FALSE);
490 for (i = 0; i < CD_SENSOR_CAP_LAST; i++)
491 {
492 if (cd_bitfield_contain (caps, i))
493 cc_color_calibrate_set_kind (self->calibrate, i);
494 }
495 }
496 else
497 {
498 cc_color_calibrate_set_kind (self->calibrate, CD_SENSOR_CAP_UNKNOWN);
499 gtk_widget_set_visible (self->box_calib_kind, TRUE);
500 }
501 }
502
503 static void
504 gcm_prefs_calib_sensor_treeview_clicked_cb (CcColorPanel *self,
505 GtkTreeSelection *selection)
506 {
507 gboolean ret;
508 GtkTreeIter iter;
509 GtkTreeModel *model;
510 g_autoptr(CdSensor) sensor = NULL;
511 GtkAssistant *assistant;
512
513 /* check to see if anything is selected */
514 ret = gtk_tree_selection_get_selected (selection, &model, &iter);
515 assistant = GTK_ASSISTANT (self->assistant_calib);
516 gtk_assistant_set_page_complete (assistant, self->box_calib_sensor, ret);
517 if (!ret)
518 return;
519
520 /* save the values if we have a selection */
521 gtk_tree_model_get (model, &iter,
522 COLUMN_CALIB_SENSOR_OBJECT, &sensor,
523 -1);
524 gcm_prefs_calib_set_sensor (self, sensor);
525 }
526
527 static void
528 gcm_prefs_calibrate_display (CcColorPanel *self)
529 {
530 CdSensor *sensor_tmp;
531 const gchar *tmp;
532 GtkTreeIter iter;
533 guint i;
534
535 /* set target device */
536 cc_color_calibrate_set_device (self->calibrate, self->current_device);
537
538 /* add sensors to list */
539 gtk_list_store_clear (GTK_LIST_STORE (self->liststore_calib_sensor));
540 if (self->sensors->len > 1)
541 {
542 for (i = 0; i < self->sensors->len; i++)
543 {
544 sensor_tmp = g_ptr_array_index (self->sensors, i);
545 gtk_list_store_append (GTK_LIST_STORE (self->liststore_calib_sensor), &iter);
546 gtk_list_store_set (GTK_LIST_STORE (self->liststore_calib_sensor), &iter,
547 COLUMN_CALIB_SENSOR_OBJECT, sensor_tmp,
548 COLUMN_CALIB_SENSOR_DESCRIPTION, cd_sensor_get_model (sensor_tmp),
549 -1);
550 }
551 gtk_widget_set_visible (self->box_calib_sensor, TRUE);
552 }
553 else
554 {
555 sensor_tmp = g_ptr_array_index (self->sensors, 0);
556 gcm_prefs_calib_set_sensor (self, sensor_tmp);
557 gtk_widget_set_visible (self->box_calib_sensor, FALSE);
558 }
559
560 /* set default profile title */
561 tmp = cd_device_get_model (self->current_device);
562 if (tmp == NULL)
563 tmp = cd_device_get_vendor (self->current_device);
564 if (tmp == NULL)
565 tmp = _("Screen");
566 gtk_editable_set_text (GTK_EDITABLE (self->entry_calib_title), tmp);
567 cc_color_calibrate_set_title (self->calibrate, tmp);
568
569 /* set the display whitepoint to D65 by default */
570 //FIXME?
571
572 /* show ui */
573 gtk_window_set_transient_for (GTK_WINDOW (self->assistant_calib),
574 GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (self))));
575 gtk_widget_set_visible (self->assistant_calib, TRUE);
576 }
577
578 static void
579 gcm_prefs_title_entry_changed_cb (CcColorPanel *self)
580 {
581 GtkAssistant *assistant;
582 const gchar *value;
583
584 assistant = GTK_ASSISTANT (self->assistant_calib);
585 value = gtk_editable_get_text (GTK_EDITABLE (self->entry_calib_title));
586 cc_color_calibrate_set_title (self->calibrate, value);
587 gtk_assistant_set_page_complete (assistant, self->box_calib_title, value[0] != '\0');
588 }
589
590 static void
591 gcm_prefs_calibrate_cb (CcColorPanel *self)
592 {
593 GtkNative *native;
594 GdkSurface *surface;
595 gboolean ret;
596 g_autoptr(GError) error = NULL;
597 guint xid = 0;
598 g_autoptr(GPtrArray) argv = NULL;
599
600 /* use the new-style calibration helper */
601 if (cd_device_get_kind (self->current_device) == CD_DEVICE_KIND_DISPLAY)
602 {
603 gcm_prefs_calibrate_display (self);
604 return;
605 }
606
607 /* get xid */
608 native = gtk_widget_get_native (GTK_WIDGET (self));
609 surface = gtk_native_get_surface (native);
610
611 if (GDK_IS_X11_SURFACE (surface))
612 xid = gdk_x11_surface_get_xid (GDK_X11_SURFACE (surface));
613
614 /* run with modal set */
615 argv = g_ptr_array_new_with_free_func (g_free);
616 g_ptr_array_add (argv, g_strdup ("gcm-calibrate"));
617 g_ptr_array_add (argv, g_strdup ("--device"));
618 g_ptr_array_add (argv, g_strdup (cd_device_get_id (self->current_device)));
619 g_ptr_array_add (argv, g_strdup ("--parent-window"));
620 g_ptr_array_add (argv, g_strdup_printf ("%i", xid));
621 g_ptr_array_add (argv, NULL);
622 ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, G_SPAWN_SEARCH_PATH,
623 NULL, NULL, NULL, &error);
624 if (!ret)
625 g_warning ("failed to run calibrate: %s", error->message);
626 }
627
628 static gboolean
629 gcm_prefs_is_profile_suitable_for_device (CdProfile *profile,
630 CdDevice *device)
631 {
632 const gchar *data_source;
633 CdProfileKind profile_kind_tmp;
634 CdProfileKind profile_kind;
635 CdColorspace profile_colorspace;
636 CdColorspace device_colorspace = 0;
637 gboolean ret = FALSE;
638 CdDeviceKind device_kind;
639 CdStandardSpace standard_space;
640
641 /* not the right colorspace */
642 device_colorspace = cd_device_get_colorspace (device);
643 profile_colorspace = cd_profile_get_colorspace (profile);
644 if (device_colorspace != profile_colorspace)
645 goto out;
646
647 /* if this is a display matching with one of the standard spaces that displays
648 * could emulate, also mark it as suitable */
649 if (cd_device_get_kind (device) == CD_DEVICE_KIND_DISPLAY &&
650 cd_profile_get_kind (profile) == CD_PROFILE_KIND_DISPLAY_DEVICE)
651 {
652 data_source = cd_profile_get_metadata_item (profile,
653 CD_PROFILE_METADATA_STANDARD_SPACE);
654 standard_space = cd_standard_space_from_string (data_source);
655 if (standard_space == CD_STANDARD_SPACE_SRGB ||
656 standard_space == CD_STANDARD_SPACE_ADOBE_RGB)
657 {
658 ret = TRUE;
659 goto out;
660 }
661 }
662
663 /* not the correct kind */
664 device_kind = cd_device_get_kind (device);
665 profile_kind_tmp = cd_profile_get_kind (profile);
666 profile_kind = cd_device_kind_to_profile_kind (device_kind);
667 if (profile_kind_tmp != profile_kind)
668 goto out;
669
670 /* ignore the colorspace profiles */
671 data_source = cd_profile_get_metadata_item (profile,
672 CD_PROFILE_METADATA_DATA_SOURCE);
673 if (g_strcmp0 (data_source, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0)
674 goto out;
675
676 /* success */
677 ret = TRUE;
678 out:
679 return ret;
680 }
681
682 static gint
683 gcm_prefs_combo_sort_func_cb (GtkTreeModel *model,
684 GtkTreeIter *a,
685 GtkTreeIter *b,
686 gpointer user_data)
687 {
688 gint type_a, type_b;
689 g_autofree gchar *text_a = NULL;
690 g_autofree gchar *text_b = NULL;
691
692 /* get data from model */
693 gtk_tree_model_get (model, a,
694 GCM_PREFS_COMBO_COLUMN_TYPE, &type_a,
695 GCM_PREFS_COMBO_COLUMN_TEXT, &text_a,
696 -1);
697 gtk_tree_model_get (model, b,
698 GCM_PREFS_COMBO_COLUMN_TYPE, &type_b,
699 GCM_PREFS_COMBO_COLUMN_TEXT, &text_b,
700 -1);
701
702 /* prefer normal type profiles over the 'Other Profile...' entry */
703 if (type_a < type_b)
704 return -1;
705 else if (type_a > type_b)
706 return 1;
707 else
708 return g_strcmp0 (text_a, text_b);
709 }
710
711 static gboolean
712 gcm_prefs_profile_exists_in_array (GPtrArray *array, CdProfile *profile)
713 {
714 CdProfile *profile_tmp;
715 guint i;
716
717 for (i = 0; i < array->len; i++)
718 {
719 profile_tmp = g_ptr_array_index (array, i);
720 if (cd_profile_equal (profile, profile_tmp))
721 return TRUE;
722 }
723 return FALSE;
724 }
725
726 static void
727 gcm_prefs_add_profiles_suitable_for_devices (CcColorPanel *self,
728 GPtrArray *profiles)
729 {
730 CdProfile *profile_tmp;
731 gboolean ret;
732 g_autoptr(GError) error = NULL;
733 g_autoptr(GPtrArray) profile_array = NULL;
734 GtkTreeIter iter;
735 guint i;
736
737 gtk_list_store_clear (GTK_LIST_STORE (self->liststore_assign));
738 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self->liststore_assign),
739 GCM_PREFS_COMBO_COLUMN_TEXT,
740 GTK_SORT_ASCENDING);
741 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (self->liststore_assign),
742 GCM_PREFS_COMBO_COLUMN_TEXT,
743 gcm_prefs_combo_sort_func_cb,
744 self->liststore_assign, NULL);
745
746 gtk_widget_set_visible (self->label_assign_warning, FALSE);
747
748 /* get profiles */
749 profile_array = cd_client_get_profiles_sync (self->client,
750 cc_panel_get_cancellable (CC_PANEL (self)),
751 &error);
752 if (profile_array == NULL)
753 {
754 g_warning ("failed to get profiles: %s",
755 error->message);
756 return;
757 }
758
759 /* add profiles of the right kind */
760 for (i = 0; i < profile_array->len; i++)
761 {
762 profile_tmp = g_ptr_array_index (profile_array, i);
763
764 /* get properties */
765 ret = cd_profile_connect_sync (profile_tmp,
766 cc_panel_get_cancellable (CC_PANEL (self)),
767 &error);
768 if (!ret)
769 {
770 g_warning ("failed to get profile: %s", error->message);
771 return;
772 }
773
774 /* don't add any of the already added profiles */
775 if (profiles != NULL)
776 {
777 if (gcm_prefs_profile_exists_in_array (profiles, profile_tmp))
778 continue;
779 }
780
781 /* only add correct types */
782 ret = gcm_prefs_is_profile_suitable_for_device (profile_tmp,
783 self->current_device);
784 if (!ret)
785 continue;
786
787 #if CD_CHECK_VERSION(0,1,13)
788 /* ignore profiles from other user accounts */
789 if (!cd_profile_has_access (profile_tmp))
790 continue;
791 #endif
792
793 /* add */
794 gcm_prefs_combobox_add_profile (self,
795 profile_tmp,
796 &iter);
797 }
798 }
799
800 static void
801 profile_exported_cb (GObject *source_object,
802 GAsyncResult *res,
803 gpointer user_data)
804 {
805 CdProfile *profile = CD_PROFILE (user_data);
806 GtkFileDialog *dialog = GTK_FILE_DIALOG (source_object);
807 g_autoptr(GError) error = NULL;
808 g_autoptr(GFile) source = NULL;
809 g_autoptr(GFile) destination = NULL;
810 gboolean ret;
811
812 source = g_file_new_for_path (cd_profile_get_filename (profile));
813 destination = gtk_file_dialog_save_finish (dialog, res, &error);
814
815 if (!destination)
816 {
817 g_warning ("Failed to copy profile: %s", error->message);
818 return;
819 }
820
821 ret = g_file_copy (source,
822 destination,
823 G_FILE_COPY_OVERWRITE,
824 NULL,
825 NULL,
826 NULL,
827 &error);
828 if (!ret)
829 g_warning ("Failed to copy profile: %s", error->message);
830 }
831
832 static void
833 gcm_prefs_calib_export_cb (CcColorPanel *self)
834 {
835 CdProfile *profile;
836 gboolean ret;
837 g_autofree gchar *default_name = NULL;
838 g_autoptr(GError) error = NULL;
839 GtkFileDialog *dialog;
840
841 profile = cc_color_calibrate_get_profile (self->calibrate);
842 ret = cd_profile_connect_sync (profile, NULL, &error);
843 if (!ret)
844 {
845 g_warning ("Failed to get imported profile: %s", error->message);
846 return;
847 }
848
849 dialog = gtk_file_dialog_new ();
850 /* TRANSLATORS: this is the dialog to save the ICC profile */
851 gtk_file_dialog_set_title (dialog, _("Save Profile"));
852 gtk_file_dialog_set_modal (dialog, TRUE);
853
854 default_name = g_strdup_printf ("%s.icc", cd_profile_get_title (profile));
855 gtk_file_dialog_set_initial_name (dialog, default_name);
856
857 gtk_file_dialog_save (dialog,
858 GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
859 NULL,
860 profile_exported_cb,
861 profile);
862 }
863
864 static void
865 gcm_prefs_calib_export_link_cb (CcColorPanel *self,
866 const gchar *url)
867 {
868 gtk_show_uri (GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (self))),
869 "help:gnome-help/color-howtoimport",
870 GDK_CURRENT_TIME);
871 }
872
873 static void
874 gcm_prefs_profile_add_cb (CcColorPanel *self)
875 {
876 g_autoptr(GPtrArray) profiles = NULL;
877
878 /* add profiles of the right kind */
879 profiles = cd_device_get_profiles (self->current_device);
880 gcm_prefs_add_profiles_suitable_for_devices (self, profiles);
881
882 /* make insensitive until we have a selection */
883 gtk_widget_set_sensitive (self->button_assign_ok, FALSE);
884
885 /* show the dialog */
886 gtk_window_set_transient_for (GTK_WINDOW (self->dialog_assign),
887 GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (self))));
888
889 gtk_window_present (GTK_WINDOW (self->dialog_assign));
890 }
891
892 static void
893 gcm_prefs_profile_remove_cb (CcColorPanel *self)
894 {
895 CdProfile *profile;
896 gboolean ret = FALSE;
897 g_autoptr(GError) error = NULL;
898 GtkListBoxRow *row;
899
900 /* get the selected profile */
901 row = gtk_list_box_get_selected_row (self->list_box);
902 if (row == NULL)
903 return;
904 profile = cc_color_profile_get_profile (CC_COLOR_PROFILE (row));
905 if (profile == NULL)
906 {
907 g_warning ("failed to get the active profile");
908 return;
909 }
910
911 /* just remove it, the list store will get ::changed */
912 ret = cd_device_remove_profile_sync (self->current_device,
913 profile,
914 cc_panel_get_cancellable (CC_PANEL (self)),
915 &error);
916 if (!ret)
917 g_warning ("failed to remove profile: %s", error->message);
918 }
919
920 static void
921 gcm_prefs_make_profile_default_cb (GObject *object,
922 GAsyncResult *res,
923 CcColorPanel *self)
924 {
925 CdDevice *device = CD_DEVICE (object);
926 gboolean ret = FALSE;
927 g_autoptr(GError) error = NULL;
928
929 ret = cd_device_make_profile_default_finish (device,
930 res,
931 &error);
932 if (!ret)
933 {
934 g_warning ("failed to set default profile on %s: %s",
935 cd_device_get_id (device),
936 error->message);
937 }
938 else
939 {
940 gcm_prefs_refresh_toolbar_buttons (self);
941 }
942 }
943
944 static void
945 gcm_prefs_device_profile_enable_cb (CcColorPanel *self)
946 {
947 CdProfile *profile;
948 GtkListBoxRow *row;
949
950 /* get the selected profile */
951 row = gtk_list_box_get_selected_row (self->list_box);
952 if (row == NULL)
953 return;
954 profile = cc_color_profile_get_profile (CC_COLOR_PROFILE (row));
955 if (profile == NULL)
956 {
957 g_warning ("failed to get the active profile");
958 return;
959 }
960
961 /* just set it default */
962 g_debug ("setting %s default on %s",
963 cd_profile_get_id (profile),
964 cd_device_get_id (self->current_device));
965 cd_device_make_profile_default (self->current_device,
966 profile,
967 cc_panel_get_cancellable (CC_PANEL (self)),
968 (GAsyncReadyCallback) gcm_prefs_make_profile_default_cb,
969 self);
970 }
971
972 static void
973 gcm_prefs_profile_view (CcColorPanel *self, CdProfile *profile)
974 {
975 GtkNative *native;
976 GdkSurface *surface;
977 g_autoptr(GPtrArray) argv = NULL;
978 guint xid = 0;
979 gboolean ret;
980 g_autoptr(GError) error = NULL;
981
982 /* get xid */
983 native = gtk_widget_get_native (GTK_WIDGET (self));
984 surface = gtk_native_get_surface (native);
985
986 if (GDK_IS_X11_SURFACE (surface))
987 xid = gdk_x11_surface_get_xid (GDK_X11_SURFACE (surface));
988
989 /* open up gcm-viewer as a info pane */
990 argv = g_ptr_array_new_with_free_func (g_free);
991 g_ptr_array_add (argv, g_strdup ("gcm-viewer"));
992 g_ptr_array_add (argv, g_strdup ("--profile"));
993 g_ptr_array_add (argv, g_strdup (cd_profile_get_id (profile)));
994 g_ptr_array_add (argv, g_strdup ("--parent-window"));
995 g_ptr_array_add (argv, g_strdup_printf ("%i", xid));
996 g_ptr_array_add (argv, NULL);
997 ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, G_SPAWN_SEARCH_PATH,
998 NULL, NULL, NULL, &error);
999 if (!ret)
1000 g_warning ("failed to run calibrate: %s", error->message);
1001 }
1002
1003 static void
1004 gcm_prefs_profile_assign_link_activate_cb (CcColorPanel *self,
1005 const gchar *uri)
1006 {
1007 CdProfile *profile;
1008 GtkListBoxRow *row;
1009
1010 /* get the selected profile */
1011 row = gtk_list_box_get_selected_row (self->list_box);
1012 if (row == NULL)
1013 return;
1014 profile = cc_color_profile_get_profile (CC_COLOR_PROFILE (row));
1015 if (profile == NULL)
1016 {
1017 g_warning ("failed to get the active profile");
1018 return;
1019 }
1020
1021 /* show it in the viewer */
1022 gcm_prefs_profile_view (self, profile);
1023 }
1024
1025 static void
1026 gcm_prefs_profile_view_cb (CcColorPanel *self)
1027 {
1028 CdProfile *profile;
1029 GtkListBoxRow *row;
1030
1031 /* get the selected profile */
1032 row = gtk_list_box_get_selected_row (self->list_box);
1033 if (row == NULL)
1034 return;
1035 profile = cc_color_profile_get_profile (CC_COLOR_PROFILE (row));
1036 if (profile == NULL)
1037 {
1038 g_warning ("failed to get the active profile");
1039 return;
1040 }
1041
1042 /* open up gcm-viewer as a info pane */
1043 gcm_prefs_profile_view (self, profile);
1044 }
1045
1046 static void
1047 gcm_prefs_button_assign_ok_cb (CcColorPanel *self)
1048 {
1049 GtkTreeIter iter;
1050 GtkTreeModel *model;
1051 g_autoptr(CdProfile) profile = NULL;
1052 gboolean ret = FALSE;
1053 g_autoptr(GError) error = NULL;
1054 GtkTreeSelection *selection;
1055
1056 /* hide window */
1057 gtk_window_close (GTK_WINDOW (self->dialog_assign));
1058
1059 /* get the selected profile */
1060 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->treeview_assign));
1061 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
1062 return;
1063 gtk_tree_model_get (model, &iter,
1064 GCM_PREFS_COMBO_COLUMN_PROFILE, &profile,
1065 -1);
1066 if (profile == NULL)
1067 {
1068 g_warning ("failed to get the active profile");
1069 return;
1070 }
1071
1072 /* if the device is disabled, enable the device so that we can
1073 * add color profiles to it */
1074 if (!cd_device_get_enabled (self->current_device))
1075 {
1076 ret = cd_device_set_enabled_sync (self->current_device,
1077 TRUE,
1078 cc_panel_get_cancellable (CC_PANEL (self)),
1079 &error);
1080 if (!ret)
1081 {
1082 g_warning ("failed to enabled device: %s", error->message);
1083 return;
1084 }
1085 }
1086
1087 /* just add it, the list store will get ::changed */
1088 ret = cd_device_add_profile_sync (self->current_device,
1089 CD_DEVICE_RELATION_HARD,
1090 profile,
1091 cc_panel_get_cancellable (CC_PANEL (self)),
1092 &error);
1093 if (!ret)
1094 {
1095 g_warning ("failed to add: %s", error->message);
1096 return;
1097 }
1098
1099 /* make it default */
1100 cd_device_make_profile_default (self->current_device,
1101 profile,
1102 cc_panel_get_cancellable (CC_PANEL (self)),
1103 (GAsyncReadyCallback) gcm_prefs_make_profile_default_cb,
1104 self);
1105 }
1106
1107 static void
1108 gcm_prefs_add_profiles_columns (CcColorPanel *self,
1109 GtkTreeView *treeview)
1110 {
1111 GtkCellRenderer *renderer;
1112 GtkTreeViewColumn *column;
1113
1114 /* text */
1115 renderer = gtk_cell_renderer_text_new ();
1116 column = gtk_tree_view_column_new ();
1117 gtk_tree_view_column_pack_start (column, renderer, TRUE);
1118 gtk_tree_view_column_add_attribute (column, renderer,
1119 "markup", GCM_PREFS_COMBO_COLUMN_TEXT);
1120 gtk_tree_view_column_set_expand (column, TRUE);
1121 gtk_tree_view_append_column (treeview, column);
1122
1123 /* image */
1124 column = gtk_tree_view_column_new ();
1125 renderer = gtk_cell_renderer_pixbuf_new ();
1126 gtk_tree_view_column_pack_start (column, renderer, FALSE);
1127 gtk_tree_view_column_add_attribute (column, renderer,
1128 "icon-name", GCM_PREFS_COMBO_COLUMN_WARNING_FILENAME);
1129 gtk_tree_view_append_column (treeview, column);
1130 }
1131
1132 static void
1133 gcm_prefs_set_calibrate_button_sensitivity (CcColorPanel *self)
1134 {
1135 gboolean ret = FALSE;
1136 const gchar *tooltip;
1137 CdDeviceKind kind;
1138 CdSensor *sensor_tmp;
1139
1140 /* TRANSLATORS: this is when the button is sensitive */
1141 tooltip = _("Create a color profile for the selected device");
1142
1143 /* no device selected */
1144 if (self->current_device == NULL)
1145 goto out;
1146
1147 /* are we a display */
1148 kind = cd_device_get_kind (self->current_device);
1149 if (kind == CD_DEVICE_KIND_DISPLAY)
1150 {
1151
1152 /* find whether we have hardware installed */
1153 if (self->sensors == NULL || self->sensors->len == 0)
1154 {
1155 /* TRANSLATORS: this is when the button is insensitive */
1156 tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected.");
1157 goto out;
1158 }
1159
1160 /* success */
1161 ret = TRUE;
1162
1163 }
1164 else if (kind == CD_DEVICE_KIND_SCANNER ||
1165 kind == CD_DEVICE_KIND_CAMERA ||
1166 kind == CD_DEVICE_KIND_WEBCAM)
1167 {
1168
1169 /* TODO: find out if we can scan using gnome-scan */
1170 ret = TRUE;
1171
1172 }
1173 else if (kind == CD_DEVICE_KIND_PRINTER)
1174 {
1175
1176 /* find whether we have hardware installed */
1177 if (self->sensors == NULL || self->sensors->len == 0)
1178 {
1179 /* TRANSLATORS: this is when the button is insensitive */
1180 tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected.");
1181 goto out;
1182 }
1183
1184 /* find whether we have hardware installed */
1185 sensor_tmp = g_ptr_array_index (self->sensors, 0);
1186 ret = cd_sensor_has_cap (sensor_tmp, CD_SENSOR_CAP_PRINTER);
1187 if (!ret)
1188 {
1189 /* TRANSLATORS: this is when the button is insensitive */
1190 tooltip = _("The measuring instrument does not support printer profiling.");
1191 goto out;
1192 }
1193
1194 /* success */
1195 ret = TRUE;
1196
1197 }
1198 else
1199 {
1200 /* TRANSLATORS: this is when the button is insensitive */
1201 tooltip = _("The device type is not currently supported.");
1202 }
1203 out:
1204 /* control the tooltip and sensitivity of the button */
1205 gtk_widget_set_tooltip_text (self->toolbutton_device_calibrate, tooltip);
1206 gtk_widget_set_sensitive (self->toolbutton_device_calibrate, ret);
1207 }
1208
1209 static void
1210 gcm_prefs_device_clicked (CcColorPanel *self, CdDevice *device)
1211 {
1212 /* we have a new device */
1213 g_debug ("selected device is: %s",
1214 cd_device_get_id (device));
1215
1216 /* can this device calibrate */
1217 gcm_prefs_set_calibrate_button_sensitivity (self);
1218 }
1219
1220 static void
1221 gcm_prefs_profile_clicked (CcColorPanel *self, CdProfile *profile, CdDevice *device)
1222 {
1223 g_autofree gchar *s = NULL;
1224
1225 /* get profile */
1226 g_debug ("selected profile = %s",
1227 cd_profile_get_filename (profile));
1228
1229 /* allow getting profile info */
1230 if (cd_profile_get_filename (profile) != NULL &&
1231 (s = g_find_program_in_path ("gcm-viewer")) != NULL)
1232 gtk_widget_set_sensitive (self->toolbutton_profile_view, TRUE);
1233 else
1234 gtk_widget_set_sensitive (self->toolbutton_profile_view, FALSE);
1235 }
1236
1237 static void
1238 gcm_prefs_profiles_treeview_clicked_cb (CcColorPanel *self,
1239 GtkTreeSelection *selection)
1240 {
1241 GtkTreeModel *model;
1242 GtkTreeIter iter;
1243 g_autoptr(CdProfile) profile = NULL;
1244 #if CD_CHECK_VERSION(0,1,25)
1245 gchar **warnings;
1246 #endif
1247
1248 /* get selection */
1249 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
1250 return;
1251 gtk_tree_model_get (model, &iter,
1252 GCM_PREFS_COMBO_COLUMN_PROFILE, &profile,
1253 -1);
1254
1255 /* as soon as anything is selected, make the Add button sensitive */
1256 gtk_widget_set_sensitive (self->button_assign_ok, TRUE);
1257
1258 /* is the profile faulty */
1259 #if CD_CHECK_VERSION(0,1,25)
1260 warnings = cd_profile_get_warnings (profile);
1261 gtk_widget_set_visible (self->label_assign_warning, warnings != NULL && warnings[0] != NULL);
1262 #else
1263 gtk_widget_set_visible (self->label_assign_warning, FALSE);
1264 #endif
1265 }
1266
1267 static void
1268 gcm_prefs_profiles_row_activated_cb (CcColorPanel *self,
1269 GtkTreePath *path)
1270 {
1271 GtkTreeIter iter;
1272 gboolean ret;
1273
1274 ret = gtk_tree_model_get_iter (gtk_tree_view_get_model (GTK_TREE_VIEW (self->treeview_assign)), &iter, path);
1275 if (!ret)
1276 return;
1277 gcm_prefs_button_assign_ok_cb (self);
1278 }
1279
1280
1281 static void
1282 gcm_prefs_button_assign_import_cb (CcColorPanel *self)
1283 {
1284 gcm_prefs_file_chooser_get_icc_profile (self);
1285 }
1286
1287 static void
1288 gcm_prefs_sensor_coldplug (CcColorPanel *self)
1289 {
1290 CdSensor *sensor_tmp;
1291 gboolean ret;
1292 g_autoptr(GError) error = NULL;
1293 g_autoptr(GPtrArray) sensors = NULL;
1294 guint i;
1295
1296 /* unref old */
1297 g_clear_pointer (&self->sensors, g_ptr_array_unref);
1298
1299 /* no present */
1300 sensors = cd_client_get_sensors_sync (self->client, NULL, &error);
1301 if (sensors == NULL)
1302 {
1303 g_warning ("%s", error->message);
1304 return;
1305 }
1306 if (sensors->len == 0)
1307 return;
1308
1309 /* save a copy of the sensor list */
1310 self->sensors = g_ptr_array_ref (sensors);
1311
1312 /* connect to each sensor */
1313 for (i = 0; i < sensors->len; i++)
1314 {
1315 sensor_tmp = g_ptr_array_index (sensors, i);
1316 ret = cd_sensor_connect_sync (sensor_tmp, NULL, &error);
1317 if (!ret)
1318 {
1319 g_warning ("%s", error->message);
1320 return;
1321 }
1322 }
1323 }
1324
1325 static void
1326 gcm_prefs_client_sensor_changed_cb (CdClient *client,
1327 CdSensor *sensor,
1328 CcColorPanel *self)
1329 {
1330 gcm_prefs_sensor_coldplug (self);
1331 gcm_prefs_set_calibrate_button_sensitivity (self);
1332 }
1333
1334 static void
1335 gcm_prefs_add_device_profile (CcColorPanel *self,
1336 CdDevice *device,
1337 CdProfile *profile,
1338 gboolean is_default)
1339 {
1340 gboolean ret;
1341 g_autoptr(GError) error = NULL;
1342 GtkWidget *widget;
1343
1344 /* get properties */
1345 ret = cd_profile_connect_sync (profile,
1346 cc_panel_get_cancellable (CC_PANEL (self)),
1347 &error);
1348 if (!ret)
1349 {
1350 g_warning ("failed to get profile: %s", error->message);
1351 return;
1352 }
1353
1354 /* ignore profiles from other user accounts */
1355 if (!cd_profile_has_access (profile))
1356 {
1357 /* only print the filename if it exists */
1358 if (cd_profile_get_filename (profile) != NULL)
1359 {
1360 g_warning ("%s is not usable by this user",
1361 cd_profile_get_filename (profile));
1362 }
1363 else
1364 {
1365 g_warning ("%s is not usable by this user",
1366 cd_profile_get_id (profile));
1367 }
1368 return;
1369 }
1370
1371 /* add to listbox */
1372 widget = cc_color_profile_new (device, profile, is_default);
1373 gtk_list_box_append (self->list_box, widget);
1374 gtk_size_group_add_widget (self->list_box_size, widget);
1375 }
1376
1377 static void
1378 gcm_prefs_add_device_profiles (CcColorPanel *self, CdDevice *device)
1379 {
1380 CdProfile *profile_tmp;
1381 g_autoptr(GPtrArray) profiles = NULL;
1382 guint i;
1383
1384 /* add profiles */
1385 profiles = cd_device_get_profiles (device);
1386 if (profiles == NULL)
1387 return;
1388 for (i = 0; i < profiles->len; i++)
1389 {
1390 profile_tmp = g_ptr_array_index (profiles, i);
1391 gcm_prefs_add_device_profile (self, device, profile_tmp, i == 0);
1392 }
1393 }
1394
1395 /* find the profile in the array -- for flicker-free changes */
1396 static gboolean
1397 gcm_prefs_find_profile_by_object_path (GPtrArray *profiles,
1398 const gchar *object_path)
1399 {
1400 CdProfile *profile_tmp;
1401 guint i;
1402
1403 for (i = 0; i < profiles->len; i++)
1404 {
1405 profile_tmp = g_ptr_array_index (profiles, i);
1406 if (g_strcmp0 (cd_profile_get_object_path (profile_tmp), object_path) == 0)
1407 return TRUE;
1408 }
1409 return FALSE;
1410 }
1411
1412 /* find the profile in the list view -- for flicker-free changes */
1413 static gboolean
1414 gcm_prefs_find_widget_by_object_path (GList *list,
1415 const gchar *object_path_device,
1416 const gchar *object_path_profile)
1417 {
1418 GList *l;
1419 CdDevice *device_tmp;
1420 CdProfile *profile_tmp;
1421
1422 for (l = list; l != NULL; l = l->next)
1423 {
1424 if (!CC_IS_COLOR_PROFILE (l->data))
1425 continue;
1426
1427 /* correct device ? */
1428 device_tmp = cc_color_profile_get_device (CC_COLOR_PROFILE (l->data));
1429 if (g_strcmp0 (object_path_device,
1430 cd_device_get_object_path (device_tmp)) != 0)
1431 {
1432 continue;
1433 }
1434
1435 /* this profile */
1436 profile_tmp = cc_color_profile_get_profile (CC_COLOR_PROFILE (l->data));
1437 if (g_strcmp0 (object_path_profile,
1438 cd_profile_get_object_path (profile_tmp)) == 0)
1439 {
1440 return TRUE;
1441 }
1442 }
1443 return FALSE;
1444 }
1445
1446 static void
1447 gcm_prefs_device_changed_cb (CcColorPanel *self, CdDevice *device)
1448 {
1449 GtkWidget *child;
1450 CdDevice *device_tmp;
1451 CdProfile *profile_tmp;
1452 gboolean ret;
1453 g_autoptr(GList) list = NULL;
1454 GPtrArray *profiles;
1455 guint i;
1456
1457 /* remove anything in the list view that's not in Device.Profiles */
1458 profiles = cd_device_get_profiles (device);
1459 child = gtk_widget_get_first_child (GTK_WIDGET (self->list_box));
1460 while (child)
1461 {
1462 GtkWidget *next = gtk_widget_get_next_sibling (child);
1463
1464 if (!CC_IS_COLOR_PROFILE (child))
1465 {
1466 list = g_list_prepend (list, child);
1467 goto next;
1468 }
1469
1470 /* correct device ? */
1471 device_tmp = cc_color_profile_get_device (CC_COLOR_PROFILE (child));
1472 if (g_strcmp0 (cd_device_get_id (device),
1473 cd_device_get_id (device_tmp)) != 0)
1474 {
1475 list = g_list_prepend (list, child);
1476 goto next;
1477 }
1478
1479 /* if profile is not in Device.Profiles then remove */
1480 profile_tmp = cc_color_profile_get_profile (CC_COLOR_PROFILE (child));
1481 ret = gcm_prefs_find_profile_by_object_path (profiles,
1482 cd_profile_get_object_path (profile_tmp));
1483 if (!ret)
1484 gtk_list_box_remove (self->list_box, child);
1485 else
1486 list = g_list_prepend (list, child);
1487
1488 next:
1489 child = next;
1490 }
1491
1492 /* add anything in Device.Profiles that's not in the list view */
1493 for (i = 0; i < profiles->len; i++)
1494 {
1495 profile_tmp = g_ptr_array_index (profiles, i);
1496 ret = gcm_prefs_find_widget_by_object_path (list,
1497 cd_device_get_object_path (device),
1498 cd_profile_get_object_path (profile_tmp));
1499 if (!ret)
1500 gcm_prefs_add_device_profile (self, device, profile_tmp, i == 0);
1501 }
1502
1503 /* resort */
1504 gtk_list_box_invalidate_sort (self->list_box);
1505 }
1506
1507 static void
1508 gcm_prefs_device_expanded_changed_cb (CcColorPanel *self,
1509 gboolean is_expanded,
1510 CcColorDevice *widget)
1511 {
1512 /* ignore internal changes */
1513 if (self->model_is_changing)
1514 return;
1515
1516 g_free (self->list_box_filter);
1517 if (is_expanded)
1518 {
1519 GtkWidget *child;
1520
1521 self->list_box_filter = g_strdup (cd_device_get_id (cc_color_device_get_device (widget)));
1522
1523 /* unexpand other device widgets */
1524 self->model_is_changing = TRUE;
1525 for (child = gtk_widget_get_first_child (GTK_WIDGET (self->list_box));
1526 child != NULL;
1527 child = gtk_widget_get_next_sibling (child))
1528 {
1529 if (!CC_IS_COLOR_DEVICE (child))
1530 continue;
1531 if (CC_COLOR_DEVICE (child) != widget)
1532 cc_color_device_set_expanded (CC_COLOR_DEVICE (child), FALSE);
1533 }
1534 self->model_is_changing = FALSE;
1535 }
1536 else
1537 {
1538 self->list_box_filter = NULL;
1539 }
1540 gtk_list_box_invalidate_filter (self->list_box);
1541 }
1542
1543 static void
1544 gcm_prefs_add_device (CcColorPanel *self, CdDevice *device)
1545 {
1546 gboolean ret;
1547 g_autoptr(GError) error = NULL;
1548 GtkWidget *widget;
1549
1550 /* get device properties */
1551 ret = cd_device_connect_sync (device, cc_panel_get_cancellable (CC_PANEL (self)), &error);
1552 if (!ret)
1553 {
1554 g_warning ("failed to connect to the device: %s", error->message);
1555 return;
1556 }
1557
1558 /* add device */
1559 widget = cc_color_device_new (device);
1560 g_signal_connect_object (widget, "expanded-changed",
1561 G_CALLBACK (gcm_prefs_device_expanded_changed_cb), self, G_CONNECT_SWAPPED);
1562 gtk_list_box_append (self->list_box, widget);
1563 gtk_size_group_add_widget (self->list_box_size, widget);
1564
1565 /* add profiles */
1566 gcm_prefs_add_device_profiles (self, device);
1567
1568 /* watch for changes */
1569 g_ptr_array_add (self->devices, g_object_ref (device));
1570 g_signal_connect_object (device, "changed",
1571 G_CALLBACK (gcm_prefs_device_changed_cb), self, G_CONNECT_SWAPPED);
1572 gtk_list_box_invalidate_sort (self->list_box);
1573 }
1574
1575 static void
1576 gcm_prefs_remove_device (CcColorPanel *self, CdDevice *device)
1577 {
1578 GtkWidget *child;
1579 CdDevice *device_tmp;
1580
1581 child = gtk_widget_get_first_child (GTK_WIDGET (self->list_box));
1582 while (child)
1583 {
1584 GtkWidget *next = gtk_widget_get_next_sibling (child);
1585
1586 if (CC_IS_COLOR_DEVICE (child))
1587 device_tmp = cc_color_device_get_device (CC_COLOR_DEVICE (child));
1588 else
1589 device_tmp = cc_color_profile_get_device (CC_COLOR_PROFILE (child));
1590 if (g_strcmp0 (cd_device_get_object_path (device),
1591 cd_device_get_object_path (device_tmp)) == 0)
1592 {
1593 gtk_list_box_remove (self->list_box, child);
1594 }
1595
1596 child = next;
1597 }
1598 g_signal_handlers_disconnect_by_func (device,
1599 G_CALLBACK (gcm_prefs_device_changed_cb),
1600 self);
1601 g_ptr_array_remove (self->devices, device);
1602 }
1603
1604 static void
1605 gcm_prefs_update_device_list_extra_entry (CcColorPanel *self)
1606 {
1607 GtkListBoxRow *first_row;
1608
1609 /* any devices to show? */
1610 first_row = gtk_list_box_get_row_at_index (self->list_box, 0);
1611
1612 if (first_row == NULL)
1613 adw_view_stack_set_visible_child_name (self->stack, "no-devices-page");
1614 else
1615 adw_view_stack_set_visible_child_name (self->stack, "color-page");
1616
1617 /* if we have only one device expand it by default */
1618 if (first_row != NULL &&
1619 gtk_list_box_get_row_at_index (self->list_box, 1) == NULL)
1620 cc_color_device_set_expanded (CC_COLOR_DEVICE (first_row), TRUE);
1621 }
1622
1623 static void
1624 gcm_prefs_device_added_cb (CdClient *client,
1625 CdDevice *device,
1626 CcColorPanel *self)
1627 {
1628 /* add the device */
1629 gcm_prefs_add_device (self, device);
1630
1631 /* ensure we're not showing the 'No devices detected' entry */
1632 gcm_prefs_update_device_list_extra_entry (self);
1633 }
1634
1635 static void
1636 gcm_prefs_device_removed_cb (CdClient *client,
1637 CdDevice *device,
1638 CcColorPanel *self)
1639 {
1640 /* remove from the UI */
1641 gcm_prefs_remove_device (self, device);
1642
1643 /* ensure we showing the 'No devices detected' entry if required */
1644 gcm_prefs_update_device_list_extra_entry (self);
1645 }
1646
1647 static void
1648 gcm_prefs_get_devices_cb (GObject *object,
1649 GAsyncResult *res,
1650 gpointer user_data)
1651 {
1652 CcColorPanel *self = (CcColorPanel *) user_data;
1653 CdClient *client = CD_CLIENT (object);
1654 CdDevice *device;
1655 g_autoptr(GError) error = NULL;
1656 g_autoptr(GPtrArray) devices = NULL;
1657 guint i;
1658
1659 /* get devices and add them */
1660 devices = cd_client_get_devices_finish (client, res, &error);
1661 if (devices == NULL)
1662 {
1663 g_warning ("failed to add connected devices: %s",
1664 error->message);
1665 return;
1666 }
1667 for (i = 0; i < devices->len; i++)
1668 {
1669 device = g_ptr_array_index (devices, i);
1670 gcm_prefs_add_device (self, device);
1671 }
1672
1673 /* ensure we show the 'No devices detected' entry if empty */
1674 gcm_prefs_update_device_list_extra_entry (self);
1675 }
1676
1677 static void
1678 gcm_prefs_list_box_row_selected_cb (CcColorPanel *self,
1679 GtkListBoxRow *row)
1680 {
1681 if (!self->toolbar_devices ||
1682 gtk_widget_in_destruction (self->toolbar_devices))
1683 return;
1684
1685 gcm_prefs_refresh_toolbar_buttons (self);
1686 }
1687
1688 static void
1689 gcm_prefs_refresh_toolbar_buttons (CcColorPanel *self)
1690 {
1691 CdProfile *profile = NULL;
1692 GtkListBoxRow *row;
1693 gboolean is_device;
1694
1695 /* get the selected profile */
1696 row = gtk_list_box_get_selected_row (self->list_box);
1697
1698 is_device = CC_IS_COLOR_DEVICE (row);
1699
1700 /* nothing selected */
1701 gtk_widget_set_visible (self->toolbar_devices, row != NULL);
1702 if (row == NULL)
1703 return;
1704
1705 /* save current device */
1706 g_clear_object (&self->current_device);
1707 g_object_get (row, "device", &self->current_device, NULL);
1708
1709 /* device actions */
1710 g_debug ("%s selected", is_device ? "device" : "profile");
1711 if (CC_IS_COLOR_DEVICE (row))
1712 {
1713 gcm_prefs_device_clicked (self, self->current_device);
1714 cc_color_device_set_expanded (CC_COLOR_DEVICE (row), TRUE);
1715 }
1716 else if (CC_IS_COLOR_PROFILE (row))
1717 {
1718 profile = cc_color_profile_get_profile (CC_COLOR_PROFILE (row));
1719 gcm_prefs_profile_clicked (self, profile, self->current_device);
1720 }
1721 else
1722 g_assert_not_reached ();
1723
1724 gtk_widget_set_visible (self->toolbutton_device_default, !is_device && cc_color_profile_get_is_default (CC_COLOR_PROFILE (row)));
1725 if (profile)
1726 gtk_widget_set_sensitive (self->toolbutton_device_default, !cd_profile_get_is_system_wide (profile));
1727 gtk_widget_set_visible (self->toolbutton_device_enable, !is_device && !cc_color_profile_get_is_default (CC_COLOR_PROFILE (row)));
1728 gtk_widget_set_visible (self->toolbutton_device_calibrate, is_device);
1729 gtk_widget_set_visible (self->toolbutton_profile_add, is_device);
1730 gtk_widget_set_visible (self->toolbutton_profile_view, !is_device);
1731 gtk_widget_set_visible (self->toolbutton_profile_remove, !is_device);
1732 }
1733
1734 static void
1735 gcm_prefs_list_box_row_activated_cb (CcColorPanel *self,
1736 GtkListBoxRow *row)
1737 {
1738 if (CC_IS_COLOR_PROFILE (row))
1739 {
1740 gcm_prefs_device_profile_enable_cb (self);
1741 }
1742 }
1743
1744 static void
1745 gcm_prefs_connect_cb (GObject *object,
1746 GAsyncResult *res,
1747 gpointer user_data)
1748 {
1749 CcColorPanel *self;
1750 gboolean ret;
1751 g_autoptr(GError) error = NULL;
1752
1753 ret = cd_client_connect_finish (CD_CLIENT (object),
1754 res,
1755 &error);
1756 if (!ret)
1757 {
1758 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1759 g_warning ("failed to connect to colord: %s", error->message);
1760 return;
1761 }
1762
1763 /* Only cast the parameters after making sure it didn't fail. At this point,
1764 * the user can potentially already have changed to another panel, effectively
1765 * making user_data invalid. */
1766 self = CC_COLOR_PANEL (user_data);
1767
1768 /* set calibrate button sensitivity */
1769 gcm_prefs_sensor_coldplug (self);
1770
1771 /* get devices */
1772 cd_client_get_devices (self->client,
1773 cc_panel_get_cancellable (CC_PANEL (self)),
1774 gcm_prefs_get_devices_cb,
1775 self);
1776 }
1777
1778 static gboolean
1779 gcm_prefs_is_livecd (void)
1780 {
1781 #ifdef __linux__
1782 gboolean ret = TRUE;
1783 g_autofree gchar *data = NULL;
1784 g_autoptr(GError) error = NULL;
1785
1786 /* allow testing */
1787 if (g_getenv ("CC_COLOR_PANEL_IS_LIVECD") != NULL)
1788 return TRUE;
1789
1790 /* get the kernel commandline */
1791 ret = g_file_get_contents ("/proc/cmdline", &data, NULL, &error);
1792 if (!ret)
1793 {
1794 g_warning ("failed to get kernel command line: %s",
1795 error->message);
1796 return TRUE;
1797 }
1798 return (g_strstr_len (data, -1, "liveimg") != NULL ||
1799 g_strstr_len (data, -1, "casper") != NULL);
1800 #else
1801 return FALSE;
1802 #endif
1803 }
1804
1805 static const char *
1806 cc_color_panel_get_help_uri (CcPanel *panel)
1807 {
1808 return "help:gnome-help/color";
1809 }
1810
1811 static void
1812 cc_color_panel_get_property (GObject *object,
1813 guint property_id,
1814 GValue *value,
1815 GParamSpec *pspec)
1816 {
1817 switch (property_id)
1818 {
1819 default:
1820 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1821 }
1822 }
1823
1824 static void
1825 cc_color_panel_set_property (GObject *object,
1826 guint property_id,
1827 const GValue *value,
1828 GParamSpec *pspec)
1829 {
1830 switch (property_id)
1831 {
1832 default:
1833 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1834 }
1835 }
1836
1837 static void
1838 cc_color_panel_dispose (GObject *object)
1839 {
1840 CcColorPanel *self = CC_COLOR_PANEL (object);
1841
1842 g_clear_object (&self->settings);
1843 g_clear_object (&self->settings_colord);
1844 g_clear_object (&self->client);
1845 g_clear_object (&self->current_device);
1846 g_clear_pointer (&self->devices, g_ptr_array_unref);
1847 g_clear_object (&self->calibrate);
1848 g_clear_object (&self->list_box_size);
1849 g_clear_pointer (&self->sensors, g_ptr_array_unref);
1850 g_clear_pointer (&self->list_box_filter, g_free);
1851 g_clear_pointer ((GtkWindow **)&self->dialog_assign, gtk_window_destroy);
1852
1853 G_OBJECT_CLASS (cc_color_panel_parent_class)->dispose (object);
1854 }
1855
1856 static void
1857 cc_color_panel_finalize (GObject *object)
1858 {
1859 G_OBJECT_CLASS (cc_color_panel_parent_class)->finalize (object);
1860 }
1861
1862 static void
1863 cc_color_panel_class_init (CcColorPanelClass *klass)
1864 {
1865 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1866 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
1867 CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
1868
1869 panel_class->get_help_uri = cc_color_panel_get_help_uri;
1870
1871 object_class->get_property = cc_color_panel_get_property;
1872 object_class->set_property = cc_color_panel_set_property;
1873 object_class->dispose = cc_color_panel_dispose;
1874 object_class->finalize = cc_color_panel_finalize;
1875
1876 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/color/cc-color-panel.ui");
1877
1878 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, assistant_calib);
1879 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_brightness);
1880 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_kind);
1881 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_quality);
1882 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_sensor);
1883 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_summary);
1884 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_temp);
1885 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_title);
1886 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, button_assign_import);
1887 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, button_assign_ok);
1888 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, button_calib_export);
1889 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, dialog_assign);
1890 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, entry_calib_title);
1891 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, label_assign_warning);
1892 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, label_calib_summary_message);
1893 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, list_box);
1894 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, liststore_assign);
1895 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, liststore_calib_kind);
1896 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, liststore_calib_sensor);
1897 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, stack);
1898 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, color_page);
1899 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbar_devices);
1900 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_device_calibrate);
1901 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_device_default);
1902 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_device_enable);
1903 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_profile_add);
1904 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_profile_remove);
1905 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, toolbutton_profile_view);
1906 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, treeview_assign);
1907 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, treeview_calib_kind);
1908 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, treeview_calib_quality);
1909 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, treeview_calib_sensor);
1910 gtk_widget_class_bind_template_child (widget_class, CcColorPanel, treeview_calib_temp);
1911 }
1912
1913 static gint
1914 cc_color_panel_sort_func (GtkListBoxRow *a,
1915 GtkListBoxRow *b,
1916 gpointer user_data)
1917 {
1918 const gchar *sort_a = NULL;
1919 const gchar *sort_b = NULL;
1920 if (CC_IS_COLOR_DEVICE (a))
1921 sort_a = cc_color_device_get_sortable (CC_COLOR_DEVICE (a));
1922 else if (CC_IS_COLOR_PROFILE (a))
1923 sort_a = cc_color_profile_get_sortable (CC_COLOR_PROFILE (a));
1924 else
1925 g_assert_not_reached ();
1926 if (CC_IS_COLOR_DEVICE (b))
1927 sort_b = cc_color_device_get_sortable (CC_COLOR_DEVICE (b));
1928 else if (CC_IS_COLOR_PROFILE (b))
1929 sort_b = cc_color_profile_get_sortable (CC_COLOR_PROFILE (b));
1930 else
1931 g_assert_not_reached ();
1932 return g_strcmp0 (sort_b, sort_a);
1933 }
1934
1935 static gboolean
1936 cc_color_panel_filter_func (GtkListBoxRow *row, void *user_data)
1937 {
1938 CcColorPanel *self = CC_COLOR_PANEL (user_data);
1939 g_autoptr(CdDevice) device = NULL;
1940
1941 /* always show all devices */
1942 if (CC_IS_COLOR_DEVICE (row))
1943 return TRUE;
1944
1945 g_object_get (row, "device", &device, NULL);
1946 return g_strcmp0 (cd_device_get_id (device), self->list_box_filter) == 0;
1947 }
1948
1949 static gboolean
1950 cc_color_panel_treeview_quality_default_cb (GtkTreeModel *model,
1951 GtkTreePath *path,
1952 GtkTreeIter *iter,
1953 gpointer data)
1954 {
1955 CdProfileQuality quality;
1956 GtkTreeSelection *selection = GTK_TREE_SELECTION (data);
1957
1958 gtk_tree_model_get (model, iter,
1959 COLUMN_CALIB_QUALITY_VALUE, &quality,
1960 -1);
1961 if (quality == CD_PROFILE_QUALITY_MEDIUM)
1962 gtk_tree_selection_select_iter (selection, iter);
1963 return FALSE;
1964 }
1965
1966 static void
1967 cc_color_panel_init (CcColorPanel *self)
1968 {
1969 GtkCellRenderer *renderer;
1970 GtkTreeModel *model;
1971 GtkTreeModel *model_filter;
1972 GtkTreeSelection *selection;
1973 GtkTreeViewColumn *column;
1974 g_autofree gchar *learn_more_link = NULL;
1975 g_autofree gchar *panel_description = NULL;
1976
1977 g_resources_register (cc_color_get_resource ());
1978
1979 gtk_widget_init_template (GTK_WIDGET (self));
1980
1981 self->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
1982
1983 /* can do native display calibration using colord-session */
1984 self->calibrate = cc_color_calibrate_new ();
1985 cc_color_calibrate_set_quality (self->calibrate, CD_PROFILE_QUALITY_MEDIUM);
1986
1987 /* setup defaults */
1988 self->settings = g_settings_new (GCM_SETTINGS_SCHEMA);
1989 self->settings_colord = g_settings_new (COLORD_SETTINGS_SCHEMA);
1990
1991 /* Translators: This will be presented as the text of a link to the documentation */
1992 learn_more_link = g_strdup_printf ("<a href='help:gnome-help/color-whyimportant'>%s</a>", _("learn more"));
1993 /* Translators: %s is a link to the documentation with the label "learn more" */
1994 panel_description = g_strdup_printf (_("Each device needs an up to date color profile to be color managed — %s."), learn_more_link);
1995 adw_preferences_page_set_description (self->color_page, panel_description);
1996
1997 /* assign buttons */
1998 g_signal_connect_object (self->toolbutton_profile_add, "clicked",
1999 G_CALLBACK (gcm_prefs_profile_add_cb), self, G_CONNECT_SWAPPED);
2000 g_signal_connect_object (self->toolbutton_profile_remove, "clicked",
2001 G_CALLBACK (gcm_prefs_profile_remove_cb), self, G_CONNECT_SWAPPED);
2002 g_signal_connect_object (self->toolbutton_profile_view, "clicked",
2003 G_CALLBACK (gcm_prefs_profile_view_cb), self, G_CONNECT_SWAPPED);
2004
2005 /* href */
2006 g_signal_connect_object (self->label_assign_warning, "activate-link",
2007 G_CALLBACK (gcm_prefs_profile_assign_link_activate_cb), self, G_CONNECT_SWAPPED);
2008
2009 /* add columns to profile tree view */
2010 gcm_prefs_add_profiles_columns (self, GTK_TREE_VIEW (self->treeview_assign));
2011 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->treeview_assign));
2012 g_signal_connect_object (selection, "changed",
2013 G_CALLBACK (gcm_prefs_profiles_treeview_clicked_cb),
2014 self, G_CONNECT_SWAPPED);
2015 g_signal_connect_object (self->treeview_assign, "row-activated",
2016 G_CALLBACK (gcm_prefs_profiles_row_activated_cb),
2017 self, G_CONNECT_SWAPPED);
2018
2019 g_signal_connect_object (self->toolbutton_device_default, "clicked",
2020 G_CALLBACK (gcm_prefs_default_cb), self, G_CONNECT_SWAPPED);
2021 g_signal_connect_object (self->toolbutton_device_enable, "clicked",
2022 G_CALLBACK (gcm_prefs_device_profile_enable_cb), self, G_CONNECT_SWAPPED);
2023 g_signal_connect_object (self->toolbutton_device_calibrate, "clicked",
2024 G_CALLBACK (gcm_prefs_calibrate_cb), self, G_CONNECT_SWAPPED);
2025
2026 /* set up assign dialog */
2027 g_signal_connect_object (self->button_assign_ok, "clicked",
2028 G_CALLBACK (gcm_prefs_button_assign_ok_cb), self, G_CONNECT_SWAPPED);
2029
2030 /* setup icc profiles list */
2031 g_signal_connect_object (self->button_assign_import, "clicked",
2032 G_CALLBACK (gcm_prefs_button_assign_import_cb), self, G_CONNECT_SWAPPED);
2033
2034 /* setup the calibration helper */
2035 g_signal_connect_object (self->assistant_calib, "apply",
2036 G_CALLBACK (gcm_prefs_calib_apply_cb),
2037 self, G_CONNECT_SWAPPED);
2038 g_signal_connect_object (self->assistant_calib, "cancel",
2039 G_CALLBACK (gcm_prefs_calib_cancel_cb),
2040 self, G_CONNECT_SWAPPED);
2041 g_signal_connect_object (self->assistant_calib, "close",
2042 G_CALLBACK (gcm_prefs_calib_cancel_cb),
2043 self, G_CONNECT_SWAPPED);
2044 g_signal_connect_object (self->assistant_calib, "prepare",
2045 G_CALLBACK (gcm_prefs_calib_prepare_cb),
2046 self, G_CONNECT_SWAPPED);
2047
2048 /* setup the calibration helper ::TreeView */
2049 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->treeview_calib_quality));
2050 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->treeview_calib_quality));
2051 gtk_tree_model_foreach (model,
2052 cc_color_panel_treeview_quality_default_cb,
2053 selection);
2054 g_signal_connect_object (selection, "changed",
2055 G_CALLBACK (gcm_prefs_calib_quality_treeview_clicked_cb),
2056 self, G_CONNECT_SWAPPED);
2057 column = gtk_tree_view_column_new ();
2058 renderer = gtk_cell_renderer_text_new ();
2059 g_object_set (renderer,
2060 "xpad", 9,
2061 "ypad", 9,
2062 NULL);
2063 gtk_tree_view_column_pack_start (column, renderer, TRUE);
2064 gtk_tree_view_column_add_attribute (column, renderer,
2065 "markup", COLUMN_CALIB_QUALITY_DESCRIPTION);
2066 gtk_tree_view_column_set_expand (column, TRUE);
2067 gtk_tree_view_append_column (GTK_TREE_VIEW (self->treeview_calib_quality),
2068 GTK_TREE_VIEW_COLUMN (column));
2069 column = gtk_tree_view_column_new ();
2070 renderer = cc_color_cell_renderer_text_new ();
2071 g_object_set (renderer,
2072 "xpad", 9,
2073 "ypad", 9,
2074 "is-dim-label", TRUE,
2075 NULL);
2076 gtk_tree_view_column_pack_start (column, renderer, TRUE);
2077 gtk_tree_view_column_add_attribute (column, renderer,
2078 "markup", COLUMN_CALIB_QUALITY_APPROX_TIME);
2079 gtk_tree_view_column_set_expand (column, FALSE);
2080 gtk_tree_view_append_column (GTK_TREE_VIEW (self->treeview_calib_quality),
2081 GTK_TREE_VIEW_COLUMN (column));
2082
2083 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->treeview_calib_sensor));
2084 g_signal_connect_object (selection, "changed",
2085 G_CALLBACK (gcm_prefs_calib_sensor_treeview_clicked_cb),
2086 self, G_CONNECT_SWAPPED);
2087 column = gtk_tree_view_column_new ();
2088 renderer = gtk_cell_renderer_text_new ();
2089 g_object_set (renderer,
2090 "xpad", 9,
2091 "ypad", 9,
2092 NULL);
2093 gtk_tree_view_column_pack_start (column, renderer, TRUE);
2094 gtk_tree_view_column_add_attribute (column, renderer,
2095 "markup", COLUMN_CALIB_SENSOR_DESCRIPTION);
2096 gtk_tree_view_column_set_expand (column, TRUE);
2097 gtk_tree_view_append_column (GTK_TREE_VIEW (self->treeview_calib_sensor),
2098 GTK_TREE_VIEW_COLUMN (column));
2099
2100 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->treeview_calib_kind));
2101 g_signal_connect_object (selection, "changed",
2102 G_CALLBACK (gcm_prefs_calib_kind_treeview_clicked_cb),
2103 self, G_CONNECT_SWAPPED);
2104 column = gtk_tree_view_column_new ();
2105 renderer = gtk_cell_renderer_text_new ();
2106 g_object_set (renderer,
2107 "xpad", 9,
2108 "ypad", 9,
2109 NULL);
2110 gtk_tree_view_column_pack_start (column, renderer, TRUE);
2111 gtk_tree_view_column_add_attribute (column, renderer,
2112 "markup", COLUMN_CALIB_KIND_DESCRIPTION);
2113 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->treeview_calib_kind));
2114 model_filter = gtk_tree_model_filter_new (model, NULL);
2115 gtk_tree_view_set_model (GTK_TREE_VIEW (self->treeview_calib_kind), model_filter);
2116 gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (model_filter),
2117 COLUMN_CALIB_KIND_VISIBLE);
2118
2119 gtk_tree_view_column_set_expand (column, TRUE);
2120 gtk_tree_view_append_column (GTK_TREE_VIEW (self->treeview_calib_kind),
2121 GTK_TREE_VIEW_COLUMN (column));
2122
2123 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->treeview_calib_temp));
2124 g_signal_connect_object (selection, "changed",
2125 G_CALLBACK (gcm_prefs_calib_temp_treeview_clicked_cb),
2126 self, G_CONNECT_SWAPPED);
2127 column = gtk_tree_view_column_new ();
2128 renderer = gtk_cell_renderer_text_new ();
2129 g_object_set (renderer,
2130 "xpad", 9,
2131 "ypad", 9,
2132 NULL);
2133 gtk_tree_view_column_pack_start (column, renderer, TRUE);
2134 gtk_tree_view_column_add_attribute (column, renderer,
2135 "markup", COLUMN_CALIB_TEMP_DESCRIPTION);
2136 gtk_tree_view_column_set_expand (column, TRUE);
2137 gtk_tree_view_append_column (GTK_TREE_VIEW (self->treeview_calib_temp),
2138 GTK_TREE_VIEW_COLUMN (column));
2139 g_signal_connect_object (self->entry_calib_title, "notify::text",
2140 G_CALLBACK (gcm_prefs_title_entry_changed_cb), self, G_CONNECT_SWAPPED);
2141
2142 /* use a device client array */
2143 self->client = cd_client_new ();
2144 g_signal_connect_object (self->client, "device-added",
2145 G_CALLBACK (gcm_prefs_device_added_cb), self, 0);
2146 g_signal_connect_object (self->client, "device-removed",
2147 G_CALLBACK (gcm_prefs_device_removed_cb), self, 0);
2148
2149 /* use a listbox for the main UI */
2150 gtk_list_box_set_filter_func (self->list_box,
2151 cc_color_panel_filter_func,
2152 self,
2153 NULL);
2154 gtk_list_box_set_sort_func (self->list_box,
2155 cc_color_panel_sort_func,
2156 self,
2157 NULL);
2158 g_signal_connect_object (self->list_box, "row-selected",
2159 G_CALLBACK (gcm_prefs_list_box_row_selected_cb),
2160 self, G_CONNECT_SWAPPED);
2161 g_signal_connect_object (self->list_box, "row-activated",
2162 G_CALLBACK (gcm_prefs_list_box_row_activated_cb),
2163 self, G_CONNECT_SWAPPED);
2164 self->list_box_size = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
2165
2166 /* connect to colord */
2167 cd_client_connect (self->client,
2168 cc_panel_get_cancellable (CC_PANEL (self)),
2169 gcm_prefs_connect_cb,
2170 self);
2171
2172 /* use the color sensor */
2173 g_signal_connect_object (self->client, "sensor-added",
2174 G_CALLBACK (gcm_prefs_client_sensor_changed_cb),
2175 self, 0);
2176 g_signal_connect_object (self->client, "sensor-removed",
2177 G_CALLBACK (gcm_prefs_client_sensor_changed_cb),
2178 self, 0);
2179
2180 /* set calibrate button sensitivity */
2181 gcm_prefs_set_calibrate_button_sensitivity (self);
2182
2183 /* show the confirmation export page if we are running from a LiveCD */
2184 self->is_live_cd = gcm_prefs_is_livecd ();
2185 gtk_widget_set_visible (self->box_calib_summary, self->is_live_cd);
2186 g_signal_connect_object (self->button_calib_export, "clicked",
2187 G_CALLBACK (gcm_prefs_calib_export_cb), self, G_CONNECT_SWAPPED);
2188 g_signal_connect_object (self->label_calib_summary_message, "activate-link",
2189 G_CALLBACK (gcm_prefs_calib_export_link_cb), self, G_CONNECT_SWAPPED);
2190 }
2191