GCC Code Coverage Report


Directory: ./
File: panels/color/cc-color-profile.c
Date: 2024-05-03 09:46:52
Exec Total Coverage
Lines: 0 197 0.0%
Functions: 0 21 0.0%
Branches: 0 85 0.0%

Line Branch Exec Source
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (C) 2012 Richard Hughes <richard@hughsie.com>
4 *
5 * Licensed under the GNU General Public License Version 2
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include "config.h"
23
24 #include <glib/gi18n.h>
25 #include <gtk/gtk.h>
26
27 #include "cc-color-common.h"
28 #include "cc-color-profile.h"
29 #include "cc-list-row-info-button.h"
30
31 struct _CcColorProfile
32 {
33 GtkListBoxRow parent_instance;
34
35 GtkWidget *box;
36 CdDevice *device;
37 CdProfile *profile;
38 gboolean is_default;
39 gchar *sortable;
40 GtkWidget *widget_description;
41 GtkWidget *widget_image;
42 GtkWidget *widget_info;
43 GSettings *settings;
44 };
45
46 #define GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD "recalibrate-printer-threshold"
47 #define GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD "recalibrate-display-threshold"
48
49
50 #define IMAGE_WIDGET_PADDING 12
51
52 G_DEFINE_TYPE (CcColorProfile, cc_color_profile, GTK_TYPE_LIST_BOX_ROW)
53
54 enum
55 {
56 PROP_0,
57 PROP_DEVICE,
58 PROP_PROFILE,
59 PROP_IS_DEFAULT,
60 PROP_LAST
61 };
62
63 static gchar *
64 cc_color_profile_get_profile_date (CdProfile *profile)
65 {
66 gint64 created;
67 g_autoptr(GDateTime) dt = NULL;
68
69 /* get profile age */
70 created = cd_profile_get_created (profile);
71 if (created == 0)
72 return NULL;
73 dt = g_date_time_new_from_unix_utc (created);
74 return g_date_time_format (dt, "%x");
75 }
76
77 static gchar *
78 gcm_prefs_get_profile_title (CdProfile *profile)
79 {
80 CdColorspace colorspace;
81 const gchar *tmp;
82 GString *str;
83
84 str = g_string_new ("");
85
86 /* add date only if it's a calibration profile or the profile has
87 * not been tagged with this data */
88 tmp = cd_profile_get_metadata_item (profile, CD_PROFILE_METADATA_DATA_SOURCE);
89 if (tmp == NULL || g_strcmp0 (tmp, CD_PROFILE_METADATA_DATA_SOURCE_CALIB) == 0)
90 {
91 tmp = cc_color_profile_get_profile_date (profile);
92 if (tmp != NULL)
93 g_string_append_printf (str, "%s - ", tmp);
94 }
95 else if (g_strcmp0 (tmp, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0)
96 {
97 /* TRANSLATORS: standard spaces are well known colorspaces like
98 * sRGB, AdobeRGB and ProPhotoRGB */
99 g_string_append_printf (str, "%s - ", _("Standard Space"));
100 }
101 else if (g_strcmp0 (tmp, CD_PROFILE_METADATA_DATA_SOURCE_TEST) == 0)
102 {
103 /* TRANSLATORS: test profiles do things like changing the screen
104 * a different color, or swap the red and green channels */
105 g_string_append_printf (str, "%s - ", _("Test Profile"));
106 }
107 else if (g_strcmp0 (tmp, CD_PROFILE_METADATA_DATA_SOURCE_EDID) == 0)
108 {
109 /* TRANSLATORS: automatic profiles are generated automatically
110 * by the color management system based on manufacturing data,
111 * for instance the default monitor profile is created from the
112 * primaries specified in the monitor EDID */
113 g_string_append_printf (str, "%s - ", C_("Automatically generated profile", "Automatic"));
114 }
115
116 /* add quality if it exists */
117 tmp = cd_profile_get_metadata_item (profile, CD_PROFILE_METADATA_QUALITY);
118 if (g_strcmp0 (tmp, CD_PROFILE_METADATA_QUALITY_LOW) == 0)
119 {
120 /* TRANSLATORS: the profile quality - low quality profiles take
121 * much less time to generate but may be a poor reflection of the
122 * device capability */
123 g_string_append_printf (str, "%s - ", C_("Profile quality", "Low Quality"));
124 }
125 else if (g_strcmp0 (tmp, CD_PROFILE_METADATA_QUALITY_MEDIUM) == 0)
126 {
127 /* TRANSLATORS: the profile quality */
128 g_string_append_printf (str, "%s - ", C_("Profile quality", "Medium Quality"));
129 }
130 else if (g_strcmp0 (tmp, CD_PROFILE_METADATA_QUALITY_HIGH) == 0)
131 {
132 /* TRANSLATORS: the profile quality - high quality profiles take
133 * a *long* time, and have the best calibration and
134 * characterisation data. */
135 g_string_append_printf (str, "%s - ", C_("Profile quality", "High Quality"));
136 }
137
138 /* add profile description */
139 tmp = cd_profile_get_title (profile);
140 if (tmp != NULL)
141 {
142 g_string_append (str, tmp);
143 goto out;
144 }
145
146 /* some meta profiles do not have ICC profiles */
147 colorspace = cd_profile_get_colorspace (profile);
148 if (colorspace == CD_COLORSPACE_RGB)
149 {
150 /* TRANSLATORS: this default RGB space is used for printers that
151 * do not have additional printer profiles specified in the PPD */
152 g_string_append (str, C_("Colorspace fallback", "Default RGB"));
153 goto out;
154 }
155 if (colorspace == CD_COLORSPACE_CMYK)
156 {
157 /* TRANSLATORS: this default CMYK space is used for printers that
158 * do not have additional printer profiles specified in the PPD */
159 g_string_append (str, C_("Colorspace fallback", "Default CMYK"));
160 goto out;
161 }
162 if (colorspace == CD_COLORSPACE_GRAY)
163 {
164 /* TRANSLATORS: this default gray space is used for printers that
165 * do not have additional printer profiles specified in the PPD */
166 g_string_append (str, C_("Colorspace fallback", "Default Gray"));
167 goto out;
168 }
169
170 /* fall back to ID, ick */
171 tmp = g_strdup (cd_profile_get_id (profile));
172 g_string_append (str, tmp);
173 out:
174 return g_string_free (str, FALSE);
175 }
176
177 static const gchar *
178 cc_color_profile_get_warnings (CcColorProfile *color_profile)
179 {
180 const gchar *tooltip = NULL;
181 const guint seconds_in_one_day = 60 * 60 * 24;
182 gint num_days;
183 guint threshold_days = 0;
184
185 /* autogenerated printer defaults */
186 if (cd_device_get_kind (color_profile->device) == CD_DEVICE_KIND_PRINTER &&
187 cd_profile_get_filename (color_profile->profile) == NULL)
188 {
189 tooltip = _("Vendor supplied factory calibration data");
190 goto out;
191 }
192
193 /* autogenerated profiles are crap */
194 if (cd_device_get_kind (color_profile->device) == CD_DEVICE_KIND_DISPLAY &&
195 cd_profile_get_kind (color_profile->profile) == CD_PROFILE_KIND_DISPLAY_DEVICE &&
196 !cd_profile_get_has_vcgt (color_profile->profile))
197 {
198 tooltip = _("Full-screen display correction not possible with this profile");
199 goto out;
200 }
201
202 /* greater than the calibration threshold for the device type */
203 num_days = cd_profile_get_age (color_profile->profile) / seconds_in_one_day;
204 if (cd_device_get_kind (color_profile->device) == CD_DEVICE_KIND_DISPLAY)
205 {
206 g_settings_get (color_profile->settings,
207 GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD,
208 "u",
209 &threshold_days);
210 }
211 else if (cd_device_get_kind (color_profile->device) == CD_DEVICE_KIND_DISPLAY)
212 {
213 g_settings_get (color_profile->settings,
214 GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD,
215 "u",
216 &threshold_days);
217 }
218 if (threshold_days > 0 && num_days > threshold_days)
219 {
220 tooltip = _("This profile may no longer be accurate");
221 goto out;
222 }
223 out:
224 return tooltip;
225 }
226
227 static void
228 cc_color_profile_refresh (CcColorProfile *color_profile)
229 {
230 const gchar *warnings;
231 g_autofree gchar *title = NULL;
232
233 /* show the image if the profile is default */
234 gtk_widget_set_visible (color_profile->widget_image, color_profile->is_default);
235 gtk_widget_set_margin_start (color_profile->widget_description,
236 color_profile->is_default ? 0 : IMAGE_WIDGET_PADDING * 4);
237
238 /* set the title */
239 title = gcm_prefs_get_profile_title (color_profile->profile);
240 gtk_label_set_markup (GTK_LABEL (color_profile->widget_description), title);
241
242 /* show any information */
243 warnings = cc_color_profile_get_warnings (color_profile);
244 gtk_widget_set_visible (color_profile->widget_info, warnings != NULL);
245 cc_list_row_info_button_set_text (CC_LIST_ROW_INFO_BUTTON (color_profile->widget_info), warnings);
246 }
247
248 CdDevice *
249 cc_color_profile_get_device (CcColorProfile *color_profile)
250 {
251 g_return_val_if_fail (CC_IS_COLOR_PROFILE (color_profile), NULL);
252 return color_profile->device;
253 }
254
255 CdProfile *
256 cc_color_profile_get_profile (CcColorProfile *color_profile)
257 {
258 g_return_val_if_fail (CC_IS_COLOR_PROFILE (color_profile), NULL);
259 return color_profile->profile;
260 }
261
262 const gchar *
263 cc_color_profile_get_sortable (CcColorProfile *color_profile)
264 {
265 g_return_val_if_fail (CC_IS_COLOR_PROFILE (color_profile), NULL);
266 return color_profile->sortable;
267 }
268
269 gboolean
270 cc_color_profile_get_is_default (CcColorProfile *color_profile)
271 {
272 g_return_val_if_fail (CC_IS_COLOR_PROFILE (color_profile), 0);
273 return color_profile->is_default;
274 }
275
276 void
277 cc_color_profile_set_is_default (CcColorProfile *color_profile, gboolean is_default)
278 {
279 g_return_if_fail (CC_IS_COLOR_PROFILE (color_profile));
280 color_profile->is_default = is_default;
281 cc_color_profile_refresh (color_profile);
282 }
283
284 static void
285 cc_color_profile_get_property (GObject *object, guint param_id,
286 GValue *value, GParamSpec *pspec)
287 {
288 CcColorProfile *color_profile = CC_COLOR_PROFILE (object);
289 switch (param_id)
290 {
291 case PROP_DEVICE:
292 g_value_set_object (value, color_profile->device);
293 break;
294 case PROP_PROFILE:
295 g_value_set_object (value, color_profile->profile);
296 break;
297 case PROP_IS_DEFAULT:
298 g_value_set_boolean (value, color_profile->is_default);
299 break;
300 default:
301 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
302 break;
303 }
304 }
305
306 static void
307 cc_color_profile_set_property (GObject *object, guint param_id,
308 const GValue *value, GParamSpec *pspec)
309 {
310 CcColorProfile *color_profile = CC_COLOR_PROFILE (object);
311
312 switch (param_id)
313 {
314 case PROP_DEVICE:
315 color_profile->device = g_value_dup_object (value);
316 break;
317 case PROP_PROFILE:
318 color_profile->profile = g_value_dup_object (value);
319 break;
320 case PROP_IS_DEFAULT:
321 color_profile->is_default = g_value_get_boolean (value);
322 break;
323 default:
324 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
325 break;
326 }
327 }
328
329 static void
330 cc_color_profile_finalize (GObject *object)
331 {
332 CcColorProfile *color_profile = CC_COLOR_PROFILE (object);
333
334 g_free (color_profile->sortable);
335 g_object_unref (color_profile->device);
336 g_object_unref (color_profile->profile);
337 g_object_unref (color_profile->settings);
338
339 G_OBJECT_CLASS (cc_color_profile_parent_class)->finalize (object);
340 }
341
342 static void
343 cc_color_profile_changed_cb (CcColorProfile *color_profile)
344 {
345 g_autoptr(CdProfile) profile = NULL;
346
347 /* check to see if the default has changed */
348 profile = cd_device_get_default_profile (color_profile->device);
349 if (profile != NULL)
350 color_profile->is_default = g_strcmp0 (cd_profile_get_object_path (profile),
351 cd_profile_get_object_path (color_profile->profile)) == 0;
352 cc_color_profile_refresh (color_profile);
353 }
354
355 static const gchar *
356 cc_color_profile_get_profile_sort_data_source (CdProfile *profile)
357 {
358 const gchar *tmp;
359 tmp = cd_profile_get_metadata_item (profile, CD_PROFILE_METADATA_DATA_SOURCE);
360 if (tmp == NULL)
361 return "9";
362 if (g_strcmp0 (tmp, CD_PROFILE_METADATA_DATA_SOURCE_CALIB) == 0)
363 return "3";
364 if (g_strcmp0 (tmp, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0)
365 return "2";
366 if (g_strcmp0 (tmp, CD_PROFILE_METADATA_DATA_SOURCE_TEST) == 0)
367 return "1";
368 return "0";
369 }
370
371 static void
372 cc_color_profile_constructed (GObject *object)
373 {
374 CcColorProfile *color_profile = CC_COLOR_PROFILE (object);
375 const gchar *sortable_data_source;
376 g_autofree gchar *sortable_device = NULL;
377 g_autofree gchar *title = NULL;
378
379 /* watch to see if the default changes */
380 g_signal_connect_object (color_profile->device, "changed",
381 G_CALLBACK (cc_color_profile_changed_cb), color_profile, G_CONNECT_SWAPPED);
382 g_signal_connect_object (color_profile->profile, "changed",
383 G_CALLBACK (cc_color_profile_changed_cb), color_profile, G_CONNECT_SWAPPED);
384
385 /* sort the profiles in the list by:
386 * 1. their device (required)
387 * 2. the data source (so calibration profiles are listed before autogenerated ones)
388 * 3. the date the profiles were created (newest first)
389 * 4. the alpha sorting of the filename
390 */
391 title = gcm_prefs_get_profile_title (color_profile->profile);
392 sortable_device = cc_color_device_get_sortable_base (color_profile->device);
393 sortable_data_source = cc_color_profile_get_profile_sort_data_source (color_profile->profile);
394 color_profile->sortable = g_strdup_printf ("%s-%s-%012" G_GINT64_FORMAT "-%s",
395 sortable_device,
396 sortable_data_source,
397 cd_profile_get_created (color_profile->profile),
398 title);
399
400 cc_color_profile_refresh (color_profile);
401 }
402
403 static void
404 cc_color_profile_class_init (CcColorProfileClass *klass)
405 {
406 GObjectClass *object_class = G_OBJECT_CLASS (klass);
407 object_class->get_property = cc_color_profile_get_property;
408 object_class->set_property = cc_color_profile_set_property;
409 object_class->constructed = cc_color_profile_constructed;
410 object_class->finalize = cc_color_profile_finalize;
411
412 g_object_class_install_property (object_class, PROP_DEVICE,
413 g_param_spec_object ("device", NULL,
414 NULL,
415 CD_TYPE_DEVICE,
416 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
417 g_object_class_install_property (object_class, PROP_PROFILE,
418 g_param_spec_object ("profile", NULL,
419 NULL,
420 CD_TYPE_PROFILE,
421 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
422 g_object_class_install_property (object_class, PROP_IS_DEFAULT,
423 g_param_spec_boolean ("is-default", NULL,
424 NULL,
425 FALSE,
426 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
427 }
428
429 static void
430 cc_color_profile_init (CcColorProfile *color_profile)
431 {
432 GtkWidget *box;
433
434 color_profile->settings = g_settings_new (GCM_SETTINGS_SCHEMA);
435
436 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 9);
437
438 /* default tick */
439 color_profile->widget_image = gtk_image_new_from_icon_name ("object-select-symbolic");
440 gtk_widget_set_margin_start (color_profile->widget_image, IMAGE_WIDGET_PADDING);
441 gtk_widget_set_margin_end (color_profile->widget_image, IMAGE_WIDGET_PADDING);
442 gtk_box_append (GTK_BOX (box), color_profile->widget_image);
443
444 /* description */
445 color_profile->widget_description = gtk_label_new ("");
446 gtk_widget_set_margin_top (color_profile->widget_description, 9);
447 gtk_widget_set_margin_bottom (color_profile->widget_description, 9);
448 gtk_widget_set_halign (color_profile->widget_description, GTK_ALIGN_START);
449 gtk_label_set_ellipsize (GTK_LABEL (color_profile->widget_description), PANGO_ELLIPSIZE_END);
450 gtk_label_set_xalign (GTK_LABEL (color_profile->widget_description), 0);
451 gtk_widget_set_hexpand (color_profile->widget_description, TRUE);
452 gtk_widget_set_vexpand (color_profile->widget_description, TRUE);
453 gtk_box_append (GTK_BOX (box), color_profile->widget_description);
454
455 /* profile warnings/info */
456 color_profile->widget_info = g_object_new (CC_TYPE_LIST_ROW_INFO_BUTTON,
457 "valign", GTK_ALIGN_CENTER,
458 "margin-start", 6,
459 "margin-end", 6,
460 NULL);
461 gtk_box_append (GTK_BOX (box), color_profile->widget_info);
462
463 /* refresh */
464 gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (color_profile), box);
465 }
466
467 GtkWidget *
468 cc_color_profile_new (CdDevice *device,
469 CdProfile *profile,
470 gboolean is_default)
471 {
472 return g_object_new (CC_TYPE_COLOR_PROFILE,
473 "device", device,
474 "profile", profile,
475 "is-default", is_default,
476 NULL);
477 }
478
479