1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
4
* Copyright (C) 2011 Richard Hughes <richard@hughsie.com>
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.
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.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
#include <glib/gi18n.h>
26
#include <libnotify/notify.h>
30
#include <canberra-gtk.h>
32
#define GNOME_DESKTOP_USE_UNSTABLE_API
33
#include <libgnome-desktop/gnome-rr.h>
35
#include "gnome-settings-plugin.h"
36
#include "gnome-settings-profile.h"
37
#include "gnome-settings-session.h"
38
#include "gsd-color-manager.h"
39
#include "gcm-profile-store.h"
43
#define GSD_COLOR_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_COLOR_MANAGER, GsdColorManagerPrivate))
45
#define GCM_SESSION_NOTIFY_TIMEOUT 30000 /* ms */
46
#define GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD "recalibrate-printer-threshold"
47
#define GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD "recalibrate-display-threshold"
49
struct GsdColorManagerPrivate
54
GcmProfileStore *profile_store;
56
GnomeRRScreen *x11_screen;
57
GHashTable *edid_cache;
58
GdkWindow *gdk_window;
59
gboolean session_is_active;
60
GHashTable *device_assign_hash;
67
static void gsd_color_manager_class_init (GsdColorManagerClass *klass);
68
static void gsd_color_manager_init (GsdColorManager *color_manager);
69
static void gsd_color_manager_finalize (GObject *object);
71
G_DEFINE_TYPE (GsdColorManager, gsd_color_manager, G_TYPE_OBJECT)
73
static gpointer manager_object = NULL;
75
/* see http://www.oyranos.org/wiki/index.php?title=ICC_Profiles_in_X_Specification_0.3 */
76
#define GCM_ICC_PROFILE_IN_X_VERSION_MAJOR 0
77
#define GCM_ICC_PROFILE_IN_X_VERSION_MINOR 3
83
} GnomeRROutputClutItem;
86
gsd_color_manager_error_quark (void)
88
static GQuark quark = 0;
90
quark = g_quark_from_static_string ("gsd_color_manager_error");
95
gcm_session_get_output_edid (GsdColorManager *manager, GnomeRROutput *output, GError **error)
102
/* can we find it in the cache */
103
edid = g_hash_table_lookup (manager->priv->edid_cache,
104
gnome_rr_output_get_name (output));
111
data = gnome_rr_output_get_edid_data (output, &size);
112
if (data == NULL || size == 0) {
113
g_set_error_literal (error,
115
GNOME_RR_ERROR_UNKNOWN,
116
"unable to get EDID for output");
119
edid = gcm_edid_new ();
120
ret = gcm_edid_parse (edid, data, size, error);
122
g_object_unref (edid);
128
g_hash_table_insert (manager->priv->edid_cache,
129
g_strdup (gnome_rr_output_get_name (output)),
130
g_object_ref (edid));
136
gcm_session_screen_set_icc_profile (GsdColorManager *manager,
137
const gchar *filename,
144
GsdColorManagerPrivate *priv = manager->priv;
146
g_return_val_if_fail (filename != NULL, FALSE);
148
g_debug ("setting root window ICC profile atom from %s", filename);
150
/* get contents of file */
151
ret = g_file_get_contents (filename, &data, &length, error);
155
/* set profile property */
156
gdk_property_change (priv->gdk_window,
157
gdk_atom_intern_static_string ("_ICC_PROFILE"),
158
gdk_atom_intern_static_string ("CARDINAL"),
160
GDK_PROP_MODE_REPLACE,
161
(const guchar *) data, length);
163
/* set version property */
164
version_data = GCM_ICC_PROFILE_IN_X_VERSION_MAJOR * 100 +
165
GCM_ICC_PROFILE_IN_X_VERSION_MINOR * 1;
166
gdk_property_change (priv->gdk_window,
167
gdk_atom_intern_static_string ("_ICC_PROFILE_IN_X_VERSION"),
168
gdk_atom_intern_static_string ("CARDINAL"),
170
GDK_PROP_MODE_REPLACE,
171
(const guchar *) &version_data, 1);
178
gcm_session_get_output_id (GsdColorManager *manager, GnomeRROutput *output)
183
GcmEdid *edid = NULL;
185
GError *error = NULL;
187
/* all output devices are prefixed with this */
188
device_id = g_string_new ("xrandr");
190
/* get the output EDID if possible */
191
edid = gcm_session_get_output_edid (manager, output, &error);
193
g_debug ("no edid for %s [%s], falling back to connection name",
194
gnome_rr_output_get_name (output),
196
g_error_free (error);
197
g_string_append_printf (device_id,
199
gnome_rr_output_get_name (output));
203
/* check EDID data is okay to use */
204
vendor = gcm_edid_get_vendor_name (edid);
205
name = gcm_edid_get_monitor_name (edid);
206
serial = gcm_edid_get_serial_number (edid);
207
if (vendor == NULL && name == NULL && serial == NULL) {
208
g_debug ("edid invalid for %s, falling back to connection name",
209
gnome_rr_output_get_name (output));
210
g_string_append_printf (device_id,
212
gnome_rr_output_get_name (output));
218
g_string_append_printf (device_id, "-%s", vendor);
220
g_string_append_printf (device_id, "-%s", name);
222
g_string_append_printf (device_id, "-%s", serial);
225
g_object_unref (edid);
226
return g_string_free (device_id, FALSE);
230
GsdColorManager *manager;
234
} GcmSessionAsyncHelper;
237
gcm_session_async_helper_free (GcmSessionAsyncHelper *helper)
239
if (helper->manager != NULL)
240
g_object_unref (helper->manager);
241
if (helper->profile != NULL)
242
g_object_unref (helper->profile);
243
if (helper->device != NULL)
244
g_object_unref (helper->device);
249
_cmsWriteTagTextAscii (cmsHPROFILE lcms_profile,
254
cmsMLU *mlu = cmsMLUalloc (0, 1);
255
cmsMLUsetASCII (mlu, "en", "US", text);
256
ret = cmsWriteTag (lcms_profile, sig, mlu);
262
gcm_utils_mkdir_for_filename (const gchar *filename, GError **error)
264
gboolean ret = FALSE;
266
GFile *parent_dir = NULL;
268
/* get parent directory */
269
file = g_file_new_for_path (filename);
270
parent_dir = g_file_get_parent (file);
271
if (parent_dir == NULL) {
273
GSD_COLOR_MANAGER_ERROR,
274
GSD_COLOR_MANAGER_ERROR_FAILED,
275
"could not get parent dir %s",
280
/* ensure desination does not already exist */
281
ret = g_file_query_exists (parent_dir, NULL);
284
ret = g_file_make_directory_with_parents (parent_dir, NULL, error);
289
g_object_unref (file);
290
if (parent_dir != NULL)
291
g_object_unref (parent_dir);
297
utf8_to_wchar_t (const char *src)
303
len = mbstowcs (NULL, src, 0);
304
if (len == (size_t) -1) {
305
g_warning ("Invalid UTF-8 in string %s", src);
309
buf = g_malloc (sizeof (wchar_t) * len);
310
converted = mbstowcs (buf, src, len - 1);
311
g_assert (converted != -1);
312
buf[converted] = '\0';
318
_cmsDictAddEntryAscii (cmsHANDLE dict,
323
wchar_t *mb_key = NULL;
324
wchar_t *mb_value = NULL;
326
mb_key = utf8_to_wchar_t (key);
329
mb_value = utf8_to_wchar_t (value);
330
if (mb_value == NULL)
332
ret = cmsDictAddEntry (dict, mb_key, mb_value, NULL, NULL);
338
#endif /* HAVE_NEW_LCMS */
341
gcm_apply_create_icc_profile_for_edid (GsdColorManager *manager,
344
const gchar *filename,
347
const CdColorYxy *tmp;
348
cmsCIExyYTRIPLE chroma;
349
cmsCIExyY white_point;
350
cmsHPROFILE lcms_profile = NULL;
351
cmsToneCurve *transfer_curve[3] = { NULL, NULL, NULL };
353
gboolean ret = FALSE;
358
cmsHANDLE dict = NULL;
360
GsdColorManagerPrivate *priv = manager->priv;
362
/* ensure the per-user directory exists */
363
ret = gcm_utils_mkdir_for_filename (filename, error);
367
/* copy color data from our structures */
368
tmp = gcm_edid_get_red (edid);
369
chroma.Red.x = tmp->x;
370
chroma.Red.y = tmp->y;
371
tmp = gcm_edid_get_green (edid);
372
chroma.Green.x = tmp->x;
373
chroma.Green.y = tmp->y;
374
tmp = gcm_edid_get_blue (edid);
375
chroma.Blue.x = tmp->x;
376
chroma.Blue.y = tmp->y;
377
tmp = gcm_edid_get_white (edid);
378
white_point.x = tmp->x;
379
white_point.y = tmp->y;
382
/* estimate the transfer function for the gamma */
383
localgamma = gcm_edid_get_gamma (edid);
384
transfer_curve[0] = transfer_curve[1] = transfer_curve[2] = cmsBuildGamma (NULL, localgamma);
386
/* create our generated profile */
387
lcms_profile = cmsCreateRGBProfile (&white_point, &chroma, transfer_curve);
388
if (lcms_profile == NULL) {
390
GSD_COLOR_MANAGER_ERROR,
391
GSD_COLOR_MANAGER_ERROR_FAILED,
392
"failed to create profile");
396
cmsSetColorSpace (lcms_profile, cmsSigRgbData);
397
cmsSetPCS (lcms_profile, cmsSigXYZData);
398
cmsSetHeaderRenderingIntent (lcms_profile, INTENT_PERCEPTUAL);
399
cmsSetDeviceClass (lcms_profile, cmsSigDisplayClass);
402
ret = _cmsWriteTagTextAscii (lcms_profile,
404
/* deliberately not translated */
405
"This profile is free of known copyright restrictions.");
407
g_set_error_literal (error,
408
GSD_COLOR_MANAGER_ERROR,
409
GSD_COLOR_MANAGER_ERROR_FAILED,
410
"failed to write copyright");
415
data = gcm_edid_get_monitor_name (edid);
417
data = gcm_dmi_get_name (priv->dmi);
419
data = "Unknown monitor";
420
ret = _cmsWriteTagTextAscii (lcms_profile,
421
cmsSigDeviceModelDescTag,
424
g_set_error_literal (error,
425
GSD_COLOR_MANAGER_ERROR,
426
GSD_COLOR_MANAGER_ERROR_FAILED,
427
"failed to write model");
432
ret = _cmsWriteTagTextAscii (lcms_profile,
433
cmsSigProfileDescriptionTag,
436
g_set_error_literal (error, GSD_COLOR_MANAGER_ERROR, GSD_COLOR_MANAGER_ERROR_FAILED, "failed to write description");
440
/* get manufacturer */
441
data = gcm_edid_get_vendor_name (edid);
443
data = gcm_dmi_get_vendor (priv->dmi);
445
data = "Unknown vendor";
446
ret = _cmsWriteTagTextAscii (lcms_profile,
447
cmsSigDeviceMfgDescTag,
450
g_set_error_literal (error,
451
GSD_COLOR_MANAGER_ERROR,
452
GSD_COLOR_MANAGER_ERROR_FAILED,
453
"failed to write manufacturer");
458
/* just create a new dict */
459
dict = cmsDictAlloc (NULL);
461
/* set the framework creator metadata */
462
_cmsDictAddEntryAscii (dict,
463
CD_PROFILE_METADATA_CMF_PRODUCT,
465
_cmsDictAddEntryAscii (dict,
466
CD_PROFILE_METADATA_CMF_BINARY,
468
_cmsDictAddEntryAscii (dict,
469
CD_PROFILE_METADATA_CMF_VERSION,
471
_cmsDictAddEntryAscii (dict,
472
CD_PROFILE_METADATA_MAPPING_DEVICE_ID,
473
cd_device_get_id (device));
475
/* set the data source so we don't ever prompt the user to
476
* recalibrate (as the EDID data won't have changed) */
477
_cmsDictAddEntryAscii (dict,
478
CD_PROFILE_METADATA_DATA_SOURCE,
479
CD_PROFILE_METADATA_DATA_SOURCE_EDID);
481
/* set 'ICC meta Tag for Monitor Profiles' data */
482
_cmsDictAddEntryAscii (dict, "EDID_md5", gcm_edid_get_checksum (edid));
483
data = gcm_edid_get_monitor_name (edid);
485
_cmsDictAddEntryAscii (dict, "EDID_model", data);
486
data = gcm_edid_get_serial_number (edid);
488
_cmsDictAddEntryAscii (dict, "EDID_serial", data);
489
data = gcm_edid_get_pnp_id (edid);
491
_cmsDictAddEntryAscii (dict, "EDID_mnft", data);
492
data = gcm_edid_get_vendor_name (edid);
494
_cmsDictAddEntryAscii (dict, "EDID_manufacturer", data);
495
edid_gamma = gcm_edid_get_gamma (edid);
496
if (edid_gamma > 0.0 && edid_gamma < 10.0) {
497
str = g_strdup_printf ("%f", edid_gamma);
498
_cmsDictAddEntryAscii (dict, "EDID_gamma", str);
502
/* also add the primaries */
503
str = g_strdup_printf ("%f", chroma.Red.x);
504
_cmsDictAddEntryAscii (dict, "EDID_red_x", str);
506
str = g_strdup_printf ("%f", chroma.Red.y);
507
_cmsDictAddEntryAscii (dict, "EDID_red_y", str);
509
str = g_strdup_printf ("%f", chroma.Green.x);
510
_cmsDictAddEntryAscii (dict, "EDID_green_x", str);
512
str = g_strdup_printf ("%f", chroma.Green.y);
513
_cmsDictAddEntryAscii (dict, "EDID_green_y", str);
515
str = g_strdup_printf ("%f", chroma.Blue.x);
516
_cmsDictAddEntryAscii (dict, "EDID_blue_x", str);
518
str = g_strdup_printf ("%f", chroma.Blue.y);
519
_cmsDictAddEntryAscii (dict, "EDID_blue_y", str);
523
ret = cmsWriteTag (lcms_profile, cmsSigMetaTag, dict);
525
g_set_error_literal (error,
526
GSD_COLOR_MANAGER_ERROR,
527
GSD_COLOR_MANAGER_ERROR_FAILED,
528
"failed to write profile metadata");
531
#endif /* HAVE_NEW_LCMS */
533
/* write profile id */
534
ret = cmsMD5computeID (lcms_profile);
536
g_set_error_literal (error,
537
GSD_COLOR_MANAGER_ERROR,
538
GSD_COLOR_MANAGER_ERROR_FAILED,
539
"failed to write profile id");
543
/* save, TODO: get error */
544
cmsSaveProfileToFile (lcms_profile, filename);
551
if (*transfer_curve != NULL)
552
cmsFreeToneCurve (*transfer_curve);
557
gcm_session_generate_vcgt (CdProfile *profile, guint size)
559
GnomeRROutputClutItem *tmp;
560
GPtrArray *array = NULL;
561
const cmsToneCurve **vcgt;
564
const gchar *filename;
565
cmsHPROFILE lcms_profile = NULL;
571
/* not an actual profile */
572
filename = cd_profile_get_filename (profile);
573
if (filename == NULL)
577
lcms_profile = cmsOpenProfileFromFile (filename, "r");
578
if (lcms_profile == NULL)
581
/* get tone curves from profile */
582
vcgt = cmsReadTag (lcms_profile, cmsSigVcgtTag);
583
if (vcgt == NULL || vcgt[0] == NULL) {
584
g_debug ("profile does not have any VCGT data");
589
array = g_ptr_array_new_with_free_func (g_free);
590
for (i = 0; i < size; i++) {
591
in = (gdouble) i / (gdouble) (size - 1);
592
tmp = g_new0 (GnomeRROutputClutItem, 1);
593
tmp->red = cmsEvalToneCurveFloat(vcgt[0], in) * (gdouble) 0xffff;
594
tmp->green = cmsEvalToneCurveFloat(vcgt[1], in) * (gdouble) 0xffff;
595
tmp->blue = cmsEvalToneCurveFloat(vcgt[2], in) * (gdouble) 0xffff;
596
g_ptr_array_add (array, tmp);
599
if (lcms_profile != NULL)
600
cmsCloseProfile (lcms_profile);
605
gnome_rr_output_get_gamma_size (GnomeRROutput *output)
610
crtc = gnome_rr_output_get_crtc (output);
613
gnome_rr_crtc_get_gamma (crtc,
620
gcm_session_output_set_gamma (GnomeRROutput *output,
626
guint16 *green = NULL;
627
guint16 *blue = NULL;
629
GnomeRROutputClutItem *data;
633
if (array->len == 0) {
635
g_set_error_literal (error,
636
GSD_COLOR_MANAGER_ERROR,
637
GSD_COLOR_MANAGER_ERROR_FAILED,
638
"no data in the CLUT array");
642
/* convert to a type X understands */
643
red = g_new (guint16, array->len);
644
green = g_new (guint16, array->len);
645
blue = g_new (guint16, array->len);
646
for (i = 0; i < array->len; i++) {
647
data = g_ptr_array_index (array, i);
649
green[i] = data->green;
650
blue[i] = data->blue;
654
crtc = gnome_rr_output_get_crtc (output);
658
GSD_COLOR_MANAGER_ERROR,
659
GSD_COLOR_MANAGER_ERROR_FAILED,
660
"failed to get ctrc for %s",
661
gnome_rr_output_get_name (output));
664
gnome_rr_crtc_set_gamma (crtc, array->len,
674
gcm_session_device_set_gamma (GnomeRROutput *output,
678
gboolean ret = FALSE;
680
GPtrArray *clut = NULL;
682
/* create a lookup table */
683
size = gnome_rr_output_get_gamma_size (output);
688
clut = gcm_session_generate_vcgt (profile, size);
690
g_set_error_literal (error,
691
GSD_COLOR_MANAGER_ERROR,
692
GSD_COLOR_MANAGER_ERROR_FAILED,
693
"failed to generate vcgt");
697
/* apply the vcgt to this output */
698
ret = gcm_session_output_set_gamma (output, clut, error);
703
g_ptr_array_unref (clut);
708
gcm_session_device_reset_gamma (GnomeRROutput *output,
716
GnomeRROutputClutItem *data;
718
/* create a linear ramp */
719
g_debug ("falling back to dummy ramp");
720
clut = g_ptr_array_new_with_free_func (g_free);
721
size = gnome_rr_output_get_gamma_size (output);
726
for (i = 0; i < size; i++) {
727
value = (i * 0xffff) / (size - 1);
728
data = g_new0 (GnomeRROutputClutItem, 1);
732
g_ptr_array_add (clut, data);
735
/* apply the vcgt to this output */
736
ret = gcm_session_output_set_gamma (output, clut, error);
740
g_ptr_array_unref (clut);
744
static GnomeRROutput *
745
gcm_session_get_x11_output_by_id (GsdColorManager *manager,
746
const gchar *device_id,
750
GnomeRROutput *output = NULL;
751
GnomeRROutput **outputs = NULL;
753
GsdColorManagerPrivate *priv = manager->priv;
755
/* search all X11 outputs for the device id */
756
outputs = gnome_rr_screen_list_outputs (priv->x11_screen);
757
if (outputs == NULL) {
758
g_set_error_literal (error,
759
GSD_COLOR_MANAGER_ERROR,
760
GSD_COLOR_MANAGER_ERROR_FAILED,
761
"Failed to get outputs");
764
for (i = 0; outputs[i] != NULL && output == NULL; i++) {
765
if (!gnome_rr_output_is_connected (outputs[i]))
767
output_id = gcm_session_get_output_id (manager, outputs[i]);
768
if (g_strcmp0 (output_id, device_id) == 0)
772
if (output == NULL) {
774
GSD_COLOR_MANAGER_ERROR,
775
GSD_COLOR_MANAGER_ERROR_FAILED,
776
"Failed to find output %s",
783
/* this function is more complicated than it should be, due to the
784
* fact that XOrg sometimes assigns no primary devices when using
785
* "xrandr --auto" or when the version of RANDR is < 1.3 */
787
gcm_session_use_output_profile_for_screen (GsdColorManager *manager,
788
GnomeRROutput *output)
790
gboolean has_laptop = FALSE;
791
gboolean has_primary = FALSE;
792
GnomeRROutput **outputs;
793
GnomeRROutput *connected = NULL;
796
/* do we have any screens marked as primary */
797
outputs = gnome_rr_screen_list_outputs (manager->priv->x11_screen);
798
if (outputs == NULL || outputs[0] == NULL) {
799
g_warning ("failed to get outputs");
802
for (i = 0; outputs[i] != NULL; i++) {
803
if (!gnome_rr_output_is_connected (outputs[i]))
805
if (connected == NULL)
806
connected = outputs[i];
807
if (gnome_rr_output_get_is_primary (outputs[i]))
809
if (gnome_rr_output_is_laptop (outputs[i]))
813
/* we have an assigned primary device, are we that? */
815
return gnome_rr_output_get_is_primary (output);
817
/* choosing the internal panel is probably sane */
819
return gnome_rr_output_is_laptop (output);
821
/* we have to choose one, so go for the first connected device */
822
if (connected != NULL)
823
return gnome_rr_output_get_id (connected) == gnome_rr_output_get_id (output);
828
/* TODO: remove when we can dep on a released version of colord */
829
#ifndef CD_PROFILE_METADATA_SCREEN_BRIGHTNESS
830
#define CD_PROFILE_METADATA_SCREEN_BRIGHTNESS "SCREEN_brightness"
833
#define GSD_DBUS_NAME_POWER GSD_DBUS_NAME ".Power"
834
#define GSD_DBUS_INTERFACE_POWER_SCREEN GSD_DBUS_BASE_INTERFACE ".Power.Screen"
835
#define GSD_DBUS_PATH_POWER GSD_DBUS_PATH "/Power"
838
gcm_session_set_output_percentage_cb (GObject *source_object,
842
GDBusConnection *connection = G_DBUS_CONNECTION (source_object);
843
GError *error = NULL;
845
retval = g_dbus_connection_call_finish (connection,
848
if (retval == NULL) {
849
g_warning ("failed to set output brightness: %s",
851
g_error_free (error);
854
g_variant_unref (retval);
858
gcm_session_set_output_percentage (guint percentage)
860
GDBusConnection *connection;
862
/* get a ref to the existing bus connection */
863
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
864
if (connection == NULL)
866
g_dbus_connection_call (connection,
869
GSD_DBUS_INTERFACE_POWER_SCREEN,
871
g_variant_new ("(u)", percentage),
873
G_DBUS_CALL_FLAGS_NONE,
875
gcm_session_set_output_percentage_cb, NULL);
876
g_object_unref (connection);
880
gcm_session_device_assign_profile_connect_cb (GObject *object,
884
CdProfile *profile = CD_PROFILE (object);
885
const gchar *brightness_profile;
886
const gchar *filename;
888
GError *error = NULL;
889
GnomeRROutput *output;
890
guint brightness_percentage;
891
GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data;
892
GsdColorManager *manager = GSD_COLOR_MANAGER (helper->manager);
895
ret = cd_profile_connect_finish (profile, res, &error);
897
g_warning ("failed to connect to profile: %s",
899
g_error_free (error);
903
/* get the filename */
904
filename = cd_profile_get_filename (profile);
905
g_assert (filename != NULL);
907
/* get the output (can't save in helper as GnomeRROutput isn't
908
* a GObject, just a pointer */
909
output = gnome_rr_screen_get_output_by_id (manager->priv->x11_screen,
914
/* if output is a laptop screen and the profile has a
915
* calibration brightness then set this new brightness */
916
brightness_profile = cd_profile_get_metadata_item (profile,
917
CD_PROFILE_METADATA_SCREEN_BRIGHTNESS);
918
if (gnome_rr_output_is_laptop (output) &&
919
brightness_profile != NULL) {
920
/* the percentage is stored in the profile metadata as
921
* a string, not ideal, but it's all we have... */
922
brightness_percentage = atoi (brightness_profile);
923
gcm_session_set_output_percentage (brightness_percentage);
926
/* set the _ICC_PROFILE atom */
927
ret = gcm_session_use_output_profile_for_screen (manager, output);
929
ret = gcm_session_screen_set_icc_profile (manager,
933
g_warning ("failed to set screen _ICC_PROFILE: %s",
935
g_clear_error (&error);
939
/* create a vcgt for this icc file */
940
ret = cd_profile_get_has_vcgt (profile);
942
ret = gcm_session_device_set_gamma (output,
946
g_warning ("failed to set %s gamma tables: %s",
947
cd_device_get_id (helper->device),
949
g_error_free (error);
953
ret = gcm_session_device_reset_gamma (output,
956
g_warning ("failed to reset %s gamma tables: %s",
957
cd_device_get_id (helper->device),
959
g_error_free (error);
964
gcm_session_async_helper_free (helper);
968
* Check to see if the on-disk profile has the MAPPING_device_id
969
* metadata, and if not, we should delete the profile and re-create it
970
* so that it gets mapped by the daemon.
973
gcm_session_check_profile_device_md (const gchar *filename)
976
cmsHPROFILE lcms_profile;
977
const cmsDICTentry *entry;
978
gboolean ret = FALSE;
979
gchar ascii_name[1024];
982
/* parse the ICC file */
983
lcms_profile = cmsOpenProfileFromFile (filename, "r");
984
if (lcms_profile == NULL)
987
/* does profile have metadata? */
988
dict = cmsReadTag (lcms_profile, cmsSigMetaTag);
990
g_debug ("auto-edid profile is old, and contains no metadata");
993
for (entry = cmsDictGetEntryList (dict);
995
entry = cmsDictNextEntry (entry)) {
996
if (entry->Name == NULL)
998
len = wcstombs (ascii_name, entry->Name, sizeof (ascii_name));
999
if (len == (gsize) -1)
1001
if (g_strcmp0 (ascii_name,
1002
CD_PROFILE_METADATA_MAPPING_DEVICE_ID) == 0) {
1007
g_debug ("auto-edid profile is old, and contains no %s data",
1008
CD_PROFILE_METADATA_MAPPING_DEVICE_ID);
1010
if (lcms_profile != NULL)
1011
cmsCloseProfile (lcms_profile);
1016
gcm_session_device_assign_connect_cb (GObject *object,
1021
CdProfile *profile = NULL;
1023
gchar *autogen_filename = NULL;
1024
gchar *autogen_path = NULL;
1025
GcmEdid *edid = NULL;
1026
GnomeRROutput *output = NULL;
1027
GError *error = NULL;
1028
const gchar *xrandr_id;
1029
GcmSessionAsyncHelper *helper;
1030
CdDevice *device = CD_DEVICE (object);
1031
GsdColorManager *manager = GSD_COLOR_MANAGER (user_data);
1032
GsdColorManagerPrivate *priv = manager->priv;
1034
/* remove from assign array */
1035
g_hash_table_remove (manager->priv->device_assign_hash,
1036
cd_device_get_object_path (device));
1038
/* get properties */
1039
ret = cd_device_connect_finish (device, res, &error);
1041
g_warning ("failed to connect to device: %s",
1043
g_error_free (error);
1048
kind = cd_device_get_kind (device);
1049
if (kind != CD_DEVICE_KIND_DISPLAY)
1052
g_debug ("need to assign display device %s",
1053
cd_device_get_id (device));
1055
/* get the GnomeRROutput for the device id */
1056
xrandr_id = cd_device_get_id (device);
1057
output = gcm_session_get_x11_output_by_id (manager,
1060
if (output == NULL) {
1061
g_warning ("no %s device found: %s",
1062
cd_device_get_id (device),
1064
g_error_free (error);
1068
/* create profile from device edid if it exists */
1069
edid = gcm_session_get_output_edid (manager, output, &error);
1071
g_warning ("unable to get EDID for %s: %s",
1072
cd_device_get_id (device),
1074
g_clear_error (&error);
1077
autogen_filename = g_strdup_printf ("edid-%s.icc",
1078
gcm_edid_get_checksum (edid));
1079
autogen_path = g_build_filename (g_get_user_data_dir (),
1080
"icc", autogen_filename, NULL);
1082
/* check if auto-profile has up-to-date metadata */
1083
if (gcm_session_check_profile_device_md (autogen_path)) {
1084
g_debug ("auto-profile edid %s exists with md", autogen_path);
1086
g_debug ("auto-profile edid does not exist, creating as %s",
1088
ret = gcm_apply_create_icc_profile_for_edid (manager,
1094
g_warning ("failed to create profile from EDID data: %s",
1096
g_clear_error (&error);
1101
/* get the default profile for the device */
1102
profile = cd_device_get_default_profile (device);
1103
if (profile == NULL) {
1104
g_debug ("%s has no default profile to set",
1105
cd_device_get_id (device));
1107
/* the default output? */
1108
if (gnome_rr_output_get_is_primary (output)) {
1109
gdk_property_delete (priv->gdk_window,
1110
gdk_atom_intern_static_string ("_ICC_PROFILE"));
1111
gdk_property_delete (priv->gdk_window,
1112
gdk_atom_intern_static_string ("_ICC_PROFILE_IN_X_VERSION"));
1115
/* reset, as we want linear profiles for profiling */
1116
ret = gcm_session_device_reset_gamma (output,
1119
g_warning ("failed to reset %s gamma tables: %s",
1120
cd_device_get_id (device),
1122
g_error_free (error);
1128
/* get properties */
1129
helper = g_new0 (GcmSessionAsyncHelper, 1);
1130
helper->output_id = gnome_rr_output_get_id (output);
1131
helper->manager = g_object_ref (manager);
1132
helper->device = g_object_ref (device);
1133
cd_profile_connect (profile,
1135
gcm_session_device_assign_profile_connect_cb,
1138
g_free (autogen_filename);
1139
g_free (autogen_path);
1141
g_object_unref (edid);
1142
if (profile != NULL)
1143
g_object_unref (profile);
1147
gcm_session_device_assign (GsdColorManager *manager, CdDevice *device)
1152
/* are we already assigning this device */
1153
key = cd_device_get_object_path (device);
1154
found = g_hash_table_lookup (manager->priv->device_assign_hash, key);
1155
if (found != NULL) {
1156
g_debug ("assign for %s already in progress", key);
1159
g_hash_table_insert (manager->priv->device_assign_hash,
1161
GINT_TO_POINTER (TRUE));
1162
cd_device_connect (device,
1164
gcm_session_device_assign_connect_cb,
1169
gcm_session_device_added_assign_cb (CdClient *client,
1171
GsdColorManager *manager)
1173
gcm_session_device_assign (manager, device);
1177
gcm_session_device_changed_assign_cb (CdClient *client,
1179
GsdColorManager *manager)
1181
g_debug ("%s changed", cd_device_get_object_path (device));
1182
gcm_session_device_assign (manager, device);
1186
gcm_session_create_device_cb (GObject *object,
1191
GError *error = NULL;
1193
device = cd_client_create_device_finish (CD_CLIENT (object),
1196
if (device == NULL) {
1197
if (error->domain != CD_CLIENT_ERROR ||
1198
error->code != CD_CLIENT_ERROR_ALREADY_EXISTS) {
1199
g_warning ("failed to create device: %s",
1202
g_error_free (error);
1205
g_object_unref (device);
1209
gcm_session_add_x11_output (GsdColorManager *manager, GnomeRROutput *output)
1211
const gchar *edid_checksum = NULL;
1212
const gchar *model = NULL;
1213
const gchar *serial = NULL;
1214
const gchar *vendor = NULL;
1216
gchar *device_id = NULL;
1218
GError *error = NULL;
1219
GHashTable *device_props = NULL;
1220
GsdColorManagerPrivate *priv = manager->priv;
1222
/* try to get edid */
1223
edid = gcm_session_get_output_edid (manager, output, &error);
1225
g_warning ("failed to get edid: %s",
1227
g_clear_error (&error);
1230
/* prefer DMI data for the internal output */
1231
ret = gnome_rr_output_is_laptop (output);
1233
model = gcm_dmi_get_name (priv->dmi);
1234
vendor = gcm_dmi_get_vendor (priv->dmi);
1237
/* use EDID data if we have it */
1239
edid_checksum = gcm_edid_get_checksum (edid);
1241
model = gcm_edid_get_monitor_name (edid);
1243
vendor = gcm_edid_get_vendor_name (edid);
1245
serial = gcm_edid_get_serial_number (edid);
1248
/* ensure mandatory fields are set */
1250
model = gnome_rr_output_get_name (output);
1256
device_id = gcm_session_get_output_id (manager, output);
1257
g_debug ("output %s added", device_id);
1258
device_props = g_hash_table_new_full (g_str_hash, g_str_equal,
1260
g_hash_table_insert (device_props,
1261
(gpointer) CD_DEVICE_PROPERTY_KIND,
1262
(gpointer) cd_device_kind_to_string (CD_DEVICE_KIND_DISPLAY));
1263
g_hash_table_insert (device_props,
1264
(gpointer) CD_DEVICE_PROPERTY_MODE,
1265
(gpointer) cd_device_mode_to_string (CD_DEVICE_MODE_PHYSICAL));
1266
g_hash_table_insert (device_props,
1267
(gpointer) CD_DEVICE_PROPERTY_COLORSPACE,
1268
(gpointer) cd_colorspace_to_string (CD_COLORSPACE_RGB));
1269
g_hash_table_insert (device_props,
1270
(gpointer) CD_DEVICE_PROPERTY_VENDOR,
1272
g_hash_table_insert (device_props,
1273
(gpointer) CD_DEVICE_PROPERTY_MODEL,
1275
g_hash_table_insert (device_props,
1276
(gpointer) CD_DEVICE_PROPERTY_SERIAL,
1278
g_hash_table_insert (device_props,
1279
(gpointer) CD_DEVICE_METADATA_XRANDR_NAME,
1280
(gpointer) gnome_rr_output_get_name (output));
1281
#if CD_CHECK_VERSION(0,1,25)
1282
g_hash_table_insert (device_props,
1283
(gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY,
1284
gnome_rr_output_get_is_primary (output) ?
1285
(gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY_PRIMARY :
1286
(gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY_SECONDARY);
1288
#if CD_CHECK_VERSION(0,1,34)
1289
if (edid_checksum != NULL) {
1290
g_hash_table_insert (device_props,
1291
(gpointer) CD_DEVICE_METADATA_OUTPUT_EDID_MD5,
1292
(gpointer) edid_checksum);
1295
#if CD_CHECK_VERSION(0,1,27)
1296
/* set this so we can call the device a 'Laptop Screen' in the
1297
* control center main panel */
1298
if (gnome_rr_output_is_laptop (output)) {
1299
g_hash_table_insert (device_props,
1300
(gpointer) CD_DEVICE_PROPERTY_EMBEDDED,
1304
cd_client_create_device (priv->client,
1306
CD_OBJECT_SCOPE_TEMP,
1309
gcm_session_create_device_cb,
1312
if (device_props != NULL)
1313
g_hash_table_unref (device_props);
1315
g_object_unref (edid);
1320
gnome_rr_screen_output_added_cb (GnomeRRScreen *screen,
1321
GnomeRROutput *output,
1322
GsdColorManager *manager)
1324
gcm_session_add_x11_output (manager, output);
1328
gcm_session_screen_removed_delete_device_cb (GObject *object, GAsyncResult *res, gpointer user_data)
1331
GError *error = NULL;
1333
/* deleted device */
1334
ret = cd_client_delete_device_finish (CD_CLIENT (object),
1338
g_warning ("failed to delete device: %s",
1340
g_error_free (error);
1345
gcm_session_screen_removed_find_device_cb (GObject *object, GAsyncResult *res, gpointer user_data)
1347
GError *error = NULL;
1349
GsdColorManager *manager = GSD_COLOR_MANAGER (user_data);
1351
device = cd_client_find_device_finish (manager->priv->client,
1354
if (device == NULL) {
1355
g_warning ("failed to find device: %s",
1357
g_error_free (error);
1360
g_debug ("output %s found, and will be removed",
1361
cd_device_get_object_path (device));
1362
cd_client_delete_device (manager->priv->client,
1365
gcm_session_screen_removed_delete_device_cb,
1367
g_object_unref (device);
1371
gnome_rr_screen_output_removed_cb (GnomeRRScreen *screen,
1372
GnomeRROutput *output,
1373
GsdColorManager *manager)
1375
g_debug ("output %s removed",
1376
gnome_rr_output_get_name (output));
1377
g_hash_table_remove (manager->priv->edid_cache,
1378
gnome_rr_output_get_name (output));
1379
cd_client_find_device_by_property (manager->priv->client,
1380
CD_DEVICE_METADATA_XRANDR_NAME,
1381
gnome_rr_output_get_name (output),
1383
gcm_session_screen_removed_find_device_cb,
1388
gcm_session_get_devices_cb (GObject *object, GAsyncResult *res, gpointer user_data)
1391
GError *error = NULL;
1394
GsdColorManager *manager = GSD_COLOR_MANAGER (user_data);
1396
array = cd_client_get_devices_finish (CD_CLIENT (object), res, &error);
1397
if (array == NULL) {
1398
g_warning ("failed to get devices: %s",
1400
g_error_free (error);
1403
for (i = 0; i < array->len; i++) {
1404
device = g_ptr_array_index (array, i);
1405
gcm_session_device_assign (manager, device);
1409
g_ptr_array_unref (array);
1413
gcm_session_profile_gamma_find_device_cb (GObject *object,
1417
CdClient *client = CD_CLIENT (object);
1418
CdDevice *device = NULL;
1419
GError *error = NULL;
1420
GsdColorManager *manager = GSD_COLOR_MANAGER (user_data);
1422
device = cd_client_find_device_by_property_finish (client,
1425
if (device == NULL) {
1426
g_warning ("could not find device: %s",
1428
g_error_free (error);
1432
/* get properties */
1433
cd_device_connect (device,
1435
gcm_session_device_assign_connect_cb,
1439
g_object_unref (device);
1442
/* We have to reset the gamma tables each time as if the primary output
1443
* has changed then different crtcs are going to be used.
1444
* See https://bugzilla.gnome.org/show_bug.cgi?id=660164 for an example */
1446
gnome_rr_screen_output_changed_cb (GnomeRRScreen *screen,
1447
GsdColorManager *manager)
1449
GnomeRROutput **outputs;
1450
GsdColorManagerPrivate *priv = manager->priv;
1453
/* get X11 outputs */
1454
outputs = gnome_rr_screen_list_outputs (priv->x11_screen);
1455
if (outputs == NULL) {
1456
g_warning ("failed to get outputs");
1459
for (i = 0; outputs[i] != NULL; i++) {
1460
if (!gnome_rr_output_is_connected (outputs[i]))
1463
/* get CdDevice for this output */
1464
cd_client_find_device_by_property (manager->priv->client,
1465
CD_DEVICE_METADATA_XRANDR_NAME,
1466
gnome_rr_output_get_name (outputs[i]),
1468
gcm_session_profile_gamma_find_device_cb,
1475
gcm_session_client_connect_cb (GObject *source_object,
1480
GError *error = NULL;
1481
GnomeRROutput **outputs;
1483
GsdColorManager *manager = GSD_COLOR_MANAGER (user_data);
1484
GsdColorManagerPrivate *priv = manager->priv;
1487
g_debug ("connected to colord");
1488
ret = cd_client_connect_finish (manager->priv->client, res, &error);
1490
g_warning ("failed to connect to colord: %s", error->message);
1491
g_error_free (error);
1495
#if CD_CHECK_VERSION(0,1,12)
1496
/* is there an available colord instance? */
1497
ret = cd_client_get_has_server (manager->priv->client);
1499
g_warning ("There is no colord server available");
1505
gcm_profile_store_search (priv->profile_store);
1508
gnome_rr_screen_refresh (priv->x11_screen, &error);
1509
if (error != NULL) {
1510
g_warning ("failed to refresh: %s", error->message);
1511
g_error_free (error);
1515
/* get X11 outputs */
1516
outputs = gnome_rr_screen_list_outputs (priv->x11_screen);
1517
if (outputs == NULL) {
1518
g_warning ("failed to get outputs");
1521
for (i = 0; outputs[i] != NULL; i++) {
1522
if (gnome_rr_output_is_connected (outputs[i]))
1523
gcm_session_add_x11_output (manager, outputs[i]);
1526
/* only connect when colord is awake */
1527
g_signal_connect (priv->x11_screen, "output-connected",
1528
G_CALLBACK (gnome_rr_screen_output_added_cb),
1530
g_signal_connect (priv->x11_screen, "output-disconnected",
1531
G_CALLBACK (gnome_rr_screen_output_removed_cb),
1533
g_signal_connect (priv->x11_screen, "changed",
1534
G_CALLBACK (gnome_rr_screen_output_changed_cb),
1537
g_signal_connect (priv->client, "device-added",
1538
G_CALLBACK (gcm_session_device_added_assign_cb),
1540
g_signal_connect (priv->client, "device-changed",
1541
G_CALLBACK (gcm_session_device_changed_assign_cb),
1544
/* set for each device that already exist */
1545
cd_client_get_devices (priv->client, NULL,
1546
gcm_session_get_devices_cb,
1553
gsd_color_manager_start (GsdColorManager *manager,
1556
GsdColorManagerPrivate *priv = manager->priv;
1557
gboolean ret = FALSE;
1559
g_debug ("Starting color manager");
1560
gnome_settings_profile_start (NULL);
1562
/* coldplug the list of screens */
1563
priv->x11_screen = gnome_rr_screen_new (gdk_screen_get_default (), error);
1564
if (priv->x11_screen == NULL)
1567
cd_client_connect (priv->client,
1569
gcm_session_client_connect_cb,
1575
gnome_settings_profile_end (NULL);
1580
gsd_color_manager_stop (GsdColorManager *manager)
1582
g_debug ("Stopping color manager");
1584
g_clear_object (&manager->priv->settings);
1585
g_clear_object (&manager->priv->client);
1586
g_clear_object (&manager->priv->profile_store);
1587
g_clear_object (&manager->priv->dmi);
1588
g_clear_object (&manager->priv->session);
1589
g_clear_pointer (&manager->priv->edid_cache, g_hash_table_destroy);
1590
g_clear_pointer (&manager->priv->device_assign_hash, g_hash_table_destroy);
1591
g_clear_object (&manager->priv->x11_screen);
1595
gcm_session_exec_control_center (GsdColorManager *manager)
1598
GError *error = NULL;
1600
GdkAppLaunchContext *launch_context;
1602
/* setup the launch context so the startup notification is correct */
1603
launch_context = gdk_display_get_app_launch_context (gdk_display_get_default ());
1604
app_info = g_app_info_create_from_commandline (BINDIR "/gnome-control-center color",
1605
"gnome-control-center",
1606
G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION,
1608
if (app_info == NULL) {
1609
g_warning ("failed to create application info: %s",
1611
g_error_free (error);
1615
/* launch gnome-control-center */
1616
ret = g_app_info_launch (app_info,
1618
G_APP_LAUNCH_CONTEXT (launch_context),
1621
g_warning ("failed to launch gnome-control-center: %s",
1623
g_error_free (error);
1627
g_object_unref (launch_context);
1628
if (app_info != NULL)
1629
g_object_unref (app_info);
1633
gcm_session_notify_cb (NotifyNotification *notification,
1637
GsdColorManager *manager = GSD_COLOR_MANAGER (user_data);
1639
if (g_strcmp0 (action, "recalibrate") == 0) {
1640
notify_notification_close (notification, NULL);
1641
gcm_session_exec_control_center (manager);
1646
closed_cb (NotifyNotification *notification, gpointer data)
1648
g_object_unref (notification);
1652
gcm_session_notify_recalibrate (GsdColorManager *manager,
1654
const gchar *message,
1658
GError *error = NULL;
1659
NotifyNotification *notification;
1660
GsdColorManagerPrivate *priv = manager->priv;
1663
notification = notify_notification_new (title, message, "preferences-color");
1664
notify_notification_set_timeout (notification, GCM_SESSION_NOTIFY_TIMEOUT);
1665
notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW);
1666
notify_notification_set_app_name (notification, _("Color"));
1668
/* TRANSLATORS: button: this is to open GCM */
1669
notify_notification_add_action (notification,
1671
_("Recalibrate now"),
1672
gcm_session_notify_cb,
1675
g_signal_connect (notification, "closed", G_CALLBACK (closed_cb), NULL);
1676
ret = notify_notification_show (notification, &error);
1678
g_warning ("failed to show notification: %s",
1680
g_error_free (error);
1686
gcm_session_device_get_title (CdDevice *device)
1688
const gchar *vendor;
1691
model = cd_device_get_model (device);
1692
vendor = cd_device_get_vendor (device);
1693
if (model != NULL && vendor != NULL)
1694
return g_strdup_printf ("%s - %s", vendor, model);
1696
return g_strdup (vendor);
1698
return g_strdup (model);
1699
return g_strdup (cd_device_get_id (device));
1703
gcm_session_notify_device (GsdColorManager *manager, CdDevice *device)
1707
gchar *device_title = NULL;
1711
GsdColorManagerPrivate *priv = manager->priv;
1713
/* TRANSLATORS: this is when the device has not been recalibrated in a while */
1714
title = _("Recalibration required");
1715
device_title = gcm_session_device_get_title (device);
1718
kind = cd_device_get_kind (device);
1719
if (kind == CD_DEVICE_KIND_DISPLAY) {
1721
/* get from GSettings */
1722
threshold = g_settings_get_uint (priv->settings,
1723
GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD);
1725
/* TRANSLATORS: this is when the display has not been recalibrated in a while */
1726
message = g_strdup_printf (_("The display '%s' should be recalibrated soon."),
1730
/* get from GSettings */
1731
threshold = g_settings_get_uint (priv->settings,
1732
GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD);
1734
/* TRANSLATORS: this is when the printer has not been recalibrated in a while */
1735
message = g_strdup_printf (_("The printer '%s' should be recalibrated soon."),
1739
/* check if we need to notify */
1740
since = (g_get_real_time () - cd_device_get_modified (device)) / G_USEC_PER_SEC;
1741
if (threshold > since)
1742
gcm_session_notify_recalibrate (manager, title, message, kind);
1743
g_free (device_title);
1748
gcm_session_profile_connect_cb (GObject *object,
1752
const gchar *filename;
1754
gchar *basename = NULL;
1755
const gchar *data_source;
1756
GError *error = NULL;
1757
CdProfile *profile = CD_PROFILE (object);
1758
GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data;
1759
GsdColorManager *manager = GSD_COLOR_MANAGER (helper->manager);
1761
ret = cd_profile_connect_finish (profile,
1765
g_warning ("failed to connect to profile: %s",
1767
g_error_free (error);
1771
/* ensure it's a profile generated by us */
1772
data_source = cd_profile_get_metadata_item (profile,
1773
CD_PROFILE_METADATA_DATA_SOURCE);
1774
if (data_source == NULL) {
1776
/* existing profiles from gnome-color-manager < 3.1
1777
* won't have the extra metadata values added */
1778
filename = cd_profile_get_filename (profile);
1779
if (filename == NULL)
1781
basename = g_path_get_basename (filename);
1782
if (!g_str_has_prefix (basename, "GCM")) {
1783
g_debug ("not a GCM profile for %s: %s",
1784
cd_device_get_id (helper->device), filename);
1788
/* ensure it's been created from a calibration, rather than from
1790
} else if (g_strcmp0 (data_source,
1791
CD_PROFILE_METADATA_DATA_SOURCE_CALIB) != 0) {
1792
g_debug ("not a calib profile for %s",
1793
cd_device_get_id (helper->device));
1798
gcm_session_notify_device (manager, helper->device);
1800
gcm_session_async_helper_free (helper);
1805
gcm_session_device_connect_cb (GObject *object,
1810
GError *error = NULL;
1812
CdProfile *profile = NULL;
1813
CdDevice *device = CD_DEVICE (object);
1814
GsdColorManager *manager = GSD_COLOR_MANAGER (user_data);
1815
GcmSessionAsyncHelper *helper;
1817
ret = cd_device_connect_finish (device,
1821
g_warning ("failed to connect to device: %s",
1823
g_error_free (error);
1828
kind = cd_device_get_kind (device);
1829
if (kind != CD_DEVICE_KIND_DISPLAY &&
1830
kind != CD_DEVICE_KIND_PRINTER)
1833
/* ensure we have a profile */
1834
profile = cd_device_get_default_profile (device);
1835
if (profile == NULL) {
1836
g_debug ("no profile set for %s", cd_device_get_id (device));
1840
/* connect to the profile */
1841
helper = g_new0 (GcmSessionAsyncHelper, 1);
1842
helper->manager = g_object_ref (manager);
1843
helper->device = g_object_ref (device);
1844
cd_profile_connect (profile,
1846
gcm_session_profile_connect_cb,
1849
if (profile != NULL)
1850
g_object_unref (profile);
1854
gcm_session_device_added_notify_cb (CdClient *client,
1856
GsdColorManager *manager)
1858
/* connect to the device to get properties */
1859
cd_device_connect (device,
1861
gcm_session_device_connect_cb,
1866
gcm_session_get_precooked_md5 (cmsHPROFILE lcms_profile)
1868
cmsUInt8Number profile_id[16];
1869
gboolean md5_precooked = FALSE;
1873
/* check to see if we have a pre-cooked MD5 */
1874
cmsGetHeaderProfileID (lcms_profile, profile_id);
1875
for (i = 0; i < 16; i++) {
1876
if (profile_id[i] != 0) {
1877
md5_precooked = TRUE;
1884
/* convert to a hex string */
1885
md5 = g_new0 (gchar, 32 + 1);
1886
for (i = 0; i < 16; i++)
1887
g_snprintf (md5 + i*2, 3, "%02x", profile_id[i]);
1893
gcm_session_get_md5_for_filename (const gchar *filename,
1897
gchar *checksum = NULL;
1900
cmsHPROFILE lcms_profile = NULL;
1902
/* get the internal profile id, if it exists */
1903
lcms_profile = cmsOpenProfileFromFile (filename, "r");
1904
if (lcms_profile == NULL) {
1905
g_set_error_literal (error,
1906
GSD_COLOR_MANAGER_ERROR,
1907
GSD_COLOR_MANAGER_ERROR_FAILED,
1908
"failed to load: not an ICC profile");
1911
checksum = gcm_session_get_precooked_md5 (lcms_profile);
1912
if (checksum != NULL)
1915
/* generate checksum */
1916
ret = g_file_get_contents (filename, &data, &length, error);
1919
checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
1920
(const guchar *) data,
1924
if (lcms_profile != NULL)
1925
cmsCloseProfile (lcms_profile);
1930
gcm_session_create_profile_cb (GObject *object,
1935
GError *error = NULL;
1936
CdClient *client = CD_CLIENT (object);
1938
profile = cd_client_create_profile_finish (client, res, &error);
1939
if (profile == NULL) {
1940
if (error->domain != CD_CLIENT_ERROR ||
1941
error->code != CD_CLIENT_ERROR_ALREADY_EXISTS)
1942
g_warning ("%s", error->message);
1943
g_error_free (error);
1946
g_object_unref (profile);
1950
gcm_session_profile_store_added_cb (GcmProfileStore *profile_store,
1951
const gchar *filename,
1952
GsdColorManager *manager)
1954
gchar *checksum = NULL;
1955
gchar *profile_id = NULL;
1956
GError *error = NULL;
1957
GHashTable *profile_props = NULL;
1958
GsdColorManagerPrivate *priv = manager->priv;
1960
g_debug ("profile %s added", filename);
1963
checksum = gcm_session_get_md5_for_filename (filename, &error);
1964
if (checksum == NULL) {
1965
g_debug ("failed to get profile checksum for %s: %s",
1966
filename, error->message);
1967
g_error_free (error);
1970
profile_id = g_strdup_printf ("icc-%s", checksum);
1971
profile_props = g_hash_table_new_full (g_str_hash, g_str_equal,
1973
g_hash_table_insert (profile_props,
1974
CD_PROFILE_PROPERTY_FILENAME,
1975
(gpointer) filename);
1976
g_hash_table_insert (profile_props,
1977
CD_PROFILE_METADATA_FILE_CHECKSUM,
1978
(gpointer) checksum);
1979
cd_client_create_profile (priv->client,
1981
CD_OBJECT_SCOPE_TEMP,
1984
gcm_session_create_profile_cb,
1988
g_free (profile_id);
1989
if (profile_props != NULL)
1990
g_hash_table_unref (profile_props);
1994
gcm_session_delete_profile_cb (GObject *object,
1999
GError *error = NULL;
2000
CdClient *client = CD_CLIENT (object);
2002
ret = cd_client_delete_profile_finish (client, res, &error);
2004
g_warning ("%s", error->message);
2005
g_error_free (error);
2010
gcm_session_find_profile_by_filename_cb (GObject *object,
2014
GError *error = NULL;
2016
CdClient *client = CD_CLIENT (object);
2017
GsdColorManager *manager = GSD_COLOR_MANAGER (user_data);
2019
profile = cd_client_find_profile_by_filename_finish (client, res, &error);
2020
if (profile == NULL) {
2021
g_warning ("%s", error->message);
2022
g_error_free (error);
2026
/* remove it from colord */
2027
cd_client_delete_profile (manager->priv->client,
2030
gcm_session_delete_profile_cb,
2033
if (profile != NULL)
2034
g_object_unref (profile);
2038
gcm_session_profile_store_removed_cb (GcmProfileStore *profile_store,
2039
const gchar *filename,
2040
GsdColorManager *manager)
2042
/* find the ID for the filename */
2043
g_debug ("filename %s removed", filename);
2044
cd_client_find_profile_by_filename (manager->priv->client,
2047
gcm_session_find_profile_by_filename_cb,
2052
gcm_session_sensor_added_cb (CdClient *client,
2054
GsdColorManager *manager)
2056
ca_context_play (ca_gtk_context_get (), 0,
2057
CA_PROP_EVENT_ID, "device-added",
2058
/* TRANSLATORS: this is the application name */
2059
CA_PROP_APPLICATION_NAME, _("GNOME Settings Daemon Color Plugin"),
2060
/* TRANSLATORS: this is a sound description */
2061
CA_PROP_EVENT_DESCRIPTION, _("Color calibration device added"), NULL);
2063
/* open up the color prefs window */
2064
gcm_session_exec_control_center (manager);
2068
gcm_session_sensor_removed_cb (CdClient *client,
2070
GsdColorManager *manager)
2072
ca_context_play (ca_gtk_context_get (), 0,
2073
CA_PROP_EVENT_ID, "device-removed",
2074
/* TRANSLATORS: this is the application name */
2075
CA_PROP_APPLICATION_NAME, _("GNOME Settings Daemon Color Plugin"),
2076
/* TRANSLATORS: this is a sound description */
2077
CA_PROP_EVENT_DESCRIPTION, _("Color calibration device removed"), NULL);
2081
has_changed (char **strv,
2085
for (i = 0; strv[i] != NULL; i++) {
2086
if (g_str_equal (str, strv[i]))
2093
gcm_session_active_changed_cb (GDBusProxy *session,
2096
GsdColorManager *manager)
2098
GsdColorManagerPrivate *priv = manager->priv;
2099
GVariant *active_v = NULL;
2102
if (has_changed (invalidated, "SessionIsActive"))
2105
/* not yet connected to the daemon */
2106
if (!cd_client_get_connected (priv->client))
2109
active_v = g_dbus_proxy_get_cached_property (session, "SessionIsActive");
2110
g_return_if_fail (active_v != NULL);
2111
is_active = g_variant_get_boolean (active_v);
2112
g_variant_unref (active_v);
2114
/* When doing the fast-user-switch into a new account, load the
2115
* new users chosen profiles.
2117
* If this is the first time the GnomeSettingsSession has been
2118
* loaded, then we'll get a change from unknown to active
2119
* and we want to avoid reprobing the devices for that.
2121
if (is_active && !priv->session_is_active) {
2122
g_debug ("Done switch to new account, reload devices");
2123
cd_client_get_devices (manager->priv->client, NULL,
2124
gcm_session_get_devices_cb,
2127
priv->session_is_active = is_active;
2131
gsd_color_manager_class_init (GsdColorManagerClass *klass)
2133
GObjectClass *object_class = G_OBJECT_CLASS (klass);
2135
object_class->finalize = gsd_color_manager_finalize;
2137
g_type_class_add_private (klass, sizeof (GsdColorManagerPrivate));
2141
gsd_color_manager_init (GsdColorManager *manager)
2143
GsdColorManagerPrivate *priv;
2144
priv = manager->priv = GSD_COLOR_MANAGER_GET_PRIVATE (manager);
2146
/* track the active session */
2147
priv->session = gnome_settings_session_get_session_proxy ();
2148
g_signal_connect (priv->session, "g-properties-changed",
2149
G_CALLBACK (gcm_session_active_changed_cb), manager);
2151
/* set the _ICC_PROFILE atoms on the root screen */
2152
priv->gdk_window = gdk_screen_get_root_window (gdk_screen_get_default ());
2154
/* parsing the EDID is expensive */
2155
priv->edid_cache = g_hash_table_new_full (g_str_hash,
2160
/* we don't want to assign devices multiple times at startup */
2161
priv->device_assign_hash = g_hash_table_new_full (g_str_hash,
2166
/* use DMI data for internal panels */
2167
priv->dmi = gcm_dmi_new ();
2169
priv->settings = g_settings_new ("org.gnome.settings-daemon.plugins.color");
2170
priv->client = cd_client_new ();
2171
g_signal_connect (priv->client, "device-added",
2172
G_CALLBACK (gcm_session_device_added_notify_cb),
2174
g_signal_connect (priv->client, "sensor-added",
2175
G_CALLBACK (gcm_session_sensor_added_cb),
2177
g_signal_connect (priv->client, "sensor-removed",
2178
G_CALLBACK (gcm_session_sensor_removed_cb),
2181
/* have access to all user profiles */
2182
priv->profile_store = gcm_profile_store_new ();
2183
g_signal_connect (priv->profile_store, "added",
2184
G_CALLBACK (gcm_session_profile_store_added_cb),
2186
g_signal_connect (priv->profile_store, "removed",
2187
G_CALLBACK (gcm_session_profile_store_removed_cb),
2192
gsd_color_manager_finalize (GObject *object)
2194
GsdColorManager *manager;
2196
g_return_if_fail (object != NULL);
2197
g_return_if_fail (GSD_IS_COLOR_MANAGER (object));
2199
manager = GSD_COLOR_MANAGER (object);
2201
g_clear_object (&manager->priv->settings);
2202
g_clear_object (&manager->priv->client);
2203
g_clear_object (&manager->priv->profile_store);
2204
g_clear_object (&manager->priv->dmi);
2205
g_clear_object (&manager->priv->session);
2206
g_clear_pointer (&manager->priv->edid_cache, g_hash_table_destroy);
2207
g_clear_pointer (&manager->priv->device_assign_hash, g_hash_table_destroy);
2208
g_clear_object (&manager->priv->x11_screen);
2210
G_OBJECT_CLASS (gsd_color_manager_parent_class)->finalize (object);
2214
gsd_color_manager_new (void)
2216
if (manager_object != NULL) {
2217
g_object_ref (manager_object);
2219
manager_object = g_object_new (GSD_TYPE_COLOR_MANAGER, NULL);
2220
g_object_add_weak_pointer (manager_object,
2221
(gpointer *) &manager_object);
2224
return GSD_COLOR_MANAGER (manager_object);