Code

Implemented per-monitor display adjustment via XICC
authorjoncruz <joncruz@users.sourceforge.net>
Sat, 24 Nov 2007 09:41:35 +0000 (09:41 +0000)
committerjoncruz <joncruz@users.sourceforge.net>
Sat, 24 Nov 2007 09:41:35 +0000 (09:41 +0000)
src/color-profile-fns.h
src/color-profile.cpp
src/display/sp-canvas.cpp
src/ege-color-prof-tracker.cpp
src/ege-color-prof-tracker.h
src/preferences-skeleton.h
src/ui/dialog/inkscape-preferences.cpp
src/ui/dialog/inkscape-preferences.h
src/widgets/desktop-widget.cpp

index 24044ddce27dc4d23b688cedebf796d9393e25e8..c8c51b5510f4ae5c69e90bcb7f62f2478f1da6c7 100644 (file)
@@ -30,6 +30,10 @@ GType colorprofile_get_type();
 cmsHPROFILE colorprofile_get_handle( SPDocument* document, guint* intent, gchar const* name );
 cmsHTRANSFORM colorprofile_get_display_transform();
 
+Glib::ustring colorprofile_get_display_id( int screen, int monitor );
+Glib::ustring colorprofile_set_display_per( gpointer buf, guint bufLen, int screen, int monitor );
+cmsHTRANSFORM colorprofile_get_display_per( Glib::ustring const& id );
+
 std::vector<Glib::ustring> colorprofile_get_display_names();
 std::vector<Glib::ustring> colorprofile_get_softproof_names();
 
index 2a17f698b98b1b82ad5209177cce256510ccc5c5..a9503992810587049b87027e292f28ff73c5b128 100644 (file)
@@ -1,15 +1,5 @@
 
 
-#include "xml/repr.h"
-#include "color-profile.h"
-#include "color-profile-fns.h"
-#include "attributes.h"
-#include "inkscape.h"
-#include "document.h"
-#include "prefs-utils.h"
-
-#include "dom/uri.h"
-
 //#define DEBUG_LCMS
 
 #include <glib/gstdio.h>
 #include <gtk/gtkmessagedialog.h>
 #endif // DEBUG_LCMS
 
+#include "xml/repr.h"
+#include "color-profile.h"
+#include "color-profile-fns.h"
+#include "attributes.h"
+#include "inkscape.h"
+#include "document.h"
+#include "prefs-utils.h"
+
+#include "dom/uri.h"
+#include "dom/util/digest.h"
+
 using Inkscape::ColorProfile;
 using Inkscape::ColorProfileClass;
 
@@ -789,8 +790,19 @@ cmsHPROFILE Inkscape::colorprofile_get_proof_profile_handle()
     return theOne;
 }
 
+static void free_transforms();
+
 cmsHTRANSFORM Inkscape::colorprofile_get_display_transform()
 {
+    long long int fromDisplay = prefs_get_int_attribute_limited( "options.displayprofile", "from_display", 0, 0, 1 );
+    if ( fromDisplay ) {
+        if ( transf ) {
+            cmsDeleteTransform(transf);
+            transf = 0;
+        }
+        return 0;
+    }
+
     bool warn = prefs_get_int_attribute_limited( "options.softproof", "gamutwarn", 0, 0, 1 );
     int intent = prefs_get_int_attribute_limited( "options.displayprofile", "intent", 0, 0, 3 );
     int proofIntent = prefs_get_int_attribute_limited( "options.softproof", "intent", 0, 0, 3 );
@@ -811,10 +823,7 @@ cmsHTRANSFORM Inkscape::colorprofile_get_display_transform()
          || (gamutColor != lastGamutColor)
         ) {
         gamutWarn = warn;
-        if ( transf ) {
-            cmsDeleteTransform(transf);
-            transf = 0;
-        }
+        free_transforms();
         lastIntent = intent;
         lastProofIntent = proofIntent;
         lastBPC = bpc;
@@ -852,6 +861,176 @@ cmsHTRANSFORM Inkscape::colorprofile_get_display_transform()
     return transf;
 }
 
+
+class MemProfile {
+public:
+    MemProfile();
+    ~MemProfile();
+
+    std::string id;
+    cmsHPROFILE hprof;
+    cmsHTRANSFORM transf;
+};
+
+MemProfile::MemProfile() :
+    id(),
+    hprof(0),
+    transf(0)
+{
+}
+
+MemProfile::~MemProfile()
+{
+}
+
+static std::vector< std::vector<MemProfile> > perMonitorProfiles;
+
+void free_transforms()
+{
+    if ( transf ) {
+        cmsDeleteTransform(transf);
+        transf = 0;
+    }
+
+    for ( std::vector< std::vector<MemProfile> >::iterator it = perMonitorProfiles.begin(); it != perMonitorProfiles.end(); ++it ) {
+        for ( std::vector<MemProfile>::iterator it2 = it->begin(); it2 != it->end(); ++it2 ) {
+            if ( it2->transf ) {
+                cmsDeleteTransform(it2->transf);
+                it2->transf = 0;
+            }
+        }
+    }
+}
+
+Glib::ustring Inkscape::colorprofile_get_display_id( int screen, int monitor )
+{
+    Glib::ustring id;
+
+    if ( screen >= 0 && screen < static_cast<int>(perMonitorProfiles.size()) ) {
+        std::vector<MemProfile>& row = perMonitorProfiles[screen];
+        if ( monitor >= 0 && monitor < static_cast<int>(row.size()) ) {
+            MemProfile& item = row[monitor];
+            id = item.id;
+        }
+    }
+
+    return id;
+}
+
+Glib::ustring Inkscape::colorprofile_set_display_per( gpointer buf, guint bufLen, int screen, int monitor )
+{
+    Glib::ustring id;
+
+    while ( static_cast<int>(perMonitorProfiles.size()) <= screen ) {
+        std::vector<MemProfile> tmp;
+        perMonitorProfiles.push_back(tmp);
+    }
+    std::vector<MemProfile>& row = perMonitorProfiles[screen];
+    while ( static_cast<int>(row.size()) <= monitor ) {
+        MemProfile tmp;
+        row.push_back(tmp);
+    }
+    MemProfile& item = row[monitor];
+
+    if ( item.hprof ) {
+        cmsCloseProfile( item.hprof );
+        item.hprof = 0;
+    }
+    id.clear();
+
+    if ( buf && bufLen ) {
+        Md5Digest digest;
+        if ( buf && bufLen ) {
+            digest.append(reinterpret_cast<unsigned char*>(buf), bufLen);
+        }
+        id = digest.finishHex();
+
+        // Note: if this is not a valid profile, item.hprof will be set to null.
+        item.hprof = cmsOpenProfileFromMem(buf, bufLen);
+    }
+    item.id = id;
+
+    return id;
+}
+
+cmsHTRANSFORM Inkscape::colorprofile_get_display_per( Glib::ustring const& id )
+{
+    cmsHTRANSFORM result = 0;
+    if ( id.empty() ) {
+        return 0;
+    }
+
+    bool found = false;
+    for ( std::vector< std::vector<MemProfile> >::iterator it = perMonitorProfiles.begin(); it != perMonitorProfiles.end() && !found; ++it ) {
+        for ( std::vector<MemProfile>::iterator it2 = it->begin(); it2 != it->end() && !found; ++it2 ) {
+            if ( id == it2->id ) {
+                MemProfile& item = *it2;
+
+                bool warn = prefs_get_int_attribute_limited( "options.softproof", "gamutwarn", 0, 0, 1 );
+                int intent = prefs_get_int_attribute_limited( "options.displayprofile", "intent", 0, 0, 3 );
+                int proofIntent = prefs_get_int_attribute_limited( "options.softproof", "intent", 0, 0, 3 );
+                bool bpc = prefs_get_int_attribute_limited( "options.softproof", "bpc", 0, 0, 1 );
+#if defined(cmsFLAGS_PRESERVEBLACK)
+                bool preserveBlack = prefs_get_int_attribute_limited( "options.softproof", "preserveblack", 0, 0, 1 );
+#endif //defined(cmsFLAGS_PRESERVEBLACK)
+                gchar const* colorStr = prefs_get_string_attribute("options.softproof", "gamutcolor");
+                Gdk::Color gamutColor( (colorStr && colorStr[0]) ? colorStr : "#808080");
+
+                if ( (warn != gamutWarn)
+                     || (lastIntent != intent)
+                     || (lastProofIntent != proofIntent)
+                     || (bpc != lastBPC)
+#if defined(cmsFLAGS_PRESERVEBLACK)
+                     || (preserveBlack != lastPreserveBlack)
+#endif // defined(cmsFLAGS_PRESERVEBLACK)
+                     || (gamutColor != lastGamutColor)
+                    ) {
+                    gamutWarn = warn;
+                    free_transforms();
+                    lastIntent = intent;
+                    lastProofIntent = proofIntent;
+                    lastBPC = bpc;
+#if defined(cmsFLAGS_PRESERVEBLACK)
+                    lastPreserveBlack = preserveBlack;
+#endif // defined(cmsFLAGS_PRESERVEBLACK)
+                    lastGamutColor = gamutColor;
+                }
+
+                // Fetch these now, as they might clear the transform as a side effect.
+                cmsHPROFILE proofProf = item.hprof ? Inkscape::colorprofile_get_proof_profile_handle() : 0;
+
+                if ( !item.transf ) {
+                    if ( item.hprof && proofProf ) {
+                        DWORD dwFlags = cmsFLAGS_SOFTPROOFING;
+                        if ( gamutWarn ) {
+                            dwFlags |= cmsFLAGS_GAMUTCHECK;
+                            cmsSetAlarmCodes(gamutColor.get_red() >> 8, gamutColor.get_green() >> 8, gamutColor.get_blue() >> 8);
+                        }
+                        if ( bpc ) {
+                            dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
+                        }
+#if defined(cmsFLAGS_PRESERVEBLACK)
+                        if ( preserveBlack ) {
+                            dwFlags |= cmsFLAGS_PRESERVEBLACK;
+                        }
+#endif // defined(cmsFLAGS_PRESERVEBLACK)
+                        item.transf = cmsCreateProofingTransform( ColorProfile::getSRGBProfile(), TYPE_RGB_8, item.hprof, TYPE_RGB_8, proofProf, intent, proofIntent, dwFlags );
+                    } else if ( item.hprof ) {
+                        item.transf = cmsCreateTransform( ColorProfile::getSRGBProfile(), TYPE_RGB_8, item.hprof, TYPE_RGB_8, intent, 0 );
+                    }
+                }
+
+                result = item.transf;
+                found = true;
+            }
+        }
+    }
+
+    return result;
+}
+
+
+
 #endif // ENABLE_LCMS
 
 /*
index 80b9103eb97cf217e3134791290fc8c07383dad4..2af12b6c373525cc91c233c742630b613b8b269a 100644 (file)
@@ -1593,7 +1593,13 @@ sp_canvas_paint_single_buffer (SPCanvas *canvas, int x0, int y0, int x1, int y1,
     }
 
 #if ENABLE_LCMS
-    cmsHTRANSFORM transf = Inkscape::colorprofile_get_display_transform();
+    cmsHTRANSFORM transf = 0;
+    long long int fromDisplay = prefs_get_int_attribute_limited( "options.displayprofile", "from_display", 0, 0, 1 );
+    if ( fromDisplay ) {
+        transf = Inkscape::colorprofile_get_display_per( canvas->cms_key ? *(canvas->cms_key) : "" );
+    } else {
+        transf = Inkscape::colorprofile_get_display_transform();
+    }
 #endif // ENABLE_LCMS
 
     if (buf.is_empty) {
index 2496b8dd622f34eb8080b4942d0936e42920e372..7e51db9334b7d41996dc2144bf241786df189aa1 100644 (file)
@@ -43,6 +43,7 @@
 
 #include <gtk/gtkwidget.h>
 #include <gtk/gtkwindow.h>
+#include <gtk/gtkmarshal.h>
 
 #ifdef GDK_WINDOWING_X11
 #include <X11/Xlib.h>
@@ -87,6 +88,9 @@ const gchar*        gdk_x11_get_xatom_name_for_display  (GdkDisplay *display,
 
 enum {
     CHANGED = 0,
+    ADDED,
+    REMOVED,
+    MODIFIED,
     LAST_SIGNAL};
 
 
@@ -115,7 +119,7 @@ static GObjectClass* gParentClass = 0;
 static guint signals[LAST_SIGNAL] = {0};
 
 static GSList* tracked_screens = 0;
-
+static GSList* abstract_trackers = 0;
 
 struct _EgeColorProfTrackerPrivate
 {
@@ -135,6 +139,7 @@ static void screen_size_changed_cb(GdkScreen* screen, gpointer user_data);
 static void fire(GdkScreen* screen, gint monitor);
 static void clear_profile( GdkScreen* screen, guint monitor );
 static void set_profile( GdkScreen* screen, guint monitor, const guint8* data, guint len );
+static void track_screen( GdkScreen* screen, EgeColorProfTracker* tracker );
 
 GType ege_color_prof_tracker_get_type( void )
 {
@@ -167,6 +172,7 @@ void ege_color_prof_tracker_class_init( EgeColorProfTrackerClass* klass )
 
         objClass->get_property = ege_color_prof_tracker_get_property;
         objClass->set_property = ege_color_prof_tracker_set_property;
+        klass->changed = 0;
 
         signals[CHANGED] = g_signal_new( "changed",
                                          G_TYPE_FROM_CLASS(klass),
@@ -174,7 +180,37 @@ void ege_color_prof_tracker_class_init( EgeColorProfTrackerClass* klass )
                                          G_STRUCT_OFFSET(EgeColorProfTrackerClass, changed),
                                          NULL, NULL,
                                          g_cclosure_marshal_VOID__VOID,
-                                         G_TYPE_NONE, 0);
+                                         G_TYPE_NONE, 0 );
+
+        signals[ADDED] = g_signal_new( "added",
+                                       G_TYPE_FROM_CLASS(klass),
+                                       G_SIGNAL_RUN_FIRST,
+                                       NULL,
+                                       NULL, NULL,
+                                       gtk_marshal_VOID__INT_INT,
+                                       G_TYPE_NONE, 2,
+                                       G_TYPE_INT,
+                                       G_TYPE_INT);
+
+        signals[REMOVED] = g_signal_new( "removed",
+                                         G_TYPE_FROM_CLASS(klass),
+                                         G_SIGNAL_RUN_FIRST,
+                                         NULL,
+                                         NULL, NULL,
+                                         gtk_marshal_VOID__INT_INT,
+                                         G_TYPE_NONE, 2,
+                                         G_TYPE_INT,
+                                         G_TYPE_INT);
+
+        signals[MODIFIED] = g_signal_new( "modified",
+                                          G_TYPE_FROM_CLASS(klass),
+                                          G_SIGNAL_RUN_FIRST,
+                                          NULL,
+                                          NULL, NULL,
+                                          gtk_marshal_VOID__INT_INT,
+                                          G_TYPE_NONE, 2,
+                                          G_TYPE_INT,
+                                          G_TYPE_INT);
 
         g_type_class_add_private( klass, sizeof(EgeColorProfTrackerClass) );
     }
@@ -196,13 +232,30 @@ EgeColorProfTracker* ege_color_prof_tracker_new( GtkWidget* target )
     EgeColorProfTracker* tracker = EGE_COLOR_PROF_TRACKER( obj );
     tracker->private_data->_target = target;
 
-    g_object_weak_ref( G_OBJECT(target), target_finalized, obj );
-    g_signal_connect( G_OBJECT(target), "hierarchy-changed", G_CALLBACK( target_hierarchy_changed_cb ), obj );
-    g_signal_connect( G_OBJECT(target), "screen-changed", G_CALLBACK( target_screen_changed_cb ), obj );
+    if ( target ) {
+        g_object_weak_ref( G_OBJECT(target), target_finalized, obj );
+        g_signal_connect( G_OBJECT(target), "hierarchy-changed", G_CALLBACK( target_hierarchy_changed_cb ), obj );
+        g_signal_connect( G_OBJECT(target), "screen-changed", G_CALLBACK( target_screen_changed_cb ), obj );
 
-    /* invoke the callbacks now to connect if the widget is already visible */
-    target_hierarchy_changed_cb( target, 0, obj );
-    target_screen_changed_cb( target, 0, obj );
+        /* invoke the callbacks now to connect if the widget is already visible */
+        target_hierarchy_changed_cb( target, 0, obj );
+        target_screen_changed_cb( target, 0, obj );
+    } else {
+        abstract_trackers = g_slist_append( abstract_trackers, obj );
+
+        GSList* curr = tracked_screens;
+        while ( curr ) {
+            ScreenTrack* track = (ScreenTrack*)curr->data;
+            gint screenNum = gdk_screen_get_number(track->screen);
+            gint monitor = 0;
+            for ( monitor = 0; monitor < (gint)track->profiles->len; monitor++ ) {
+                g_signal_emit( G_OBJECT(tracker), signals[MODIFIED], 0, screenNum, monitor );
+            }
+
+            curr = g_slist_next(curr);
+        }
+
+    }
 
     return tracker;
 }
@@ -240,6 +293,43 @@ void ege_color_prof_tracker_get_profile( EgeColorProfTracker const * tracker, gp
     }
 }
 
+void ege_color_prof_tracker_get_profile_for( guint screenNum, guint monitor, gpointer* ptr, guint* len )
+{
+    gpointer dataPos = 0;
+    guint dataLen = 0;
+    GdkDisplay* display = gdk_display_get_default();
+    gint numScreens = gdk_display_get_n_screens(display);
+    GdkScreen* screen = (screenNum < (guint)numScreens) ? gdk_display_get_screen(display, screenNum) : 0;
+
+    if ( screen ) {
+        GSList* curr = tracked_screens;
+        while ( curr ) {
+            ScreenTrack* screenTrack = (ScreenTrack*)curr->data;
+            if ( screenTrack->screen == screen ) {
+                if ( monitor < screenTrack->profiles->len ) {
+                    GByteArray* gba = (GByteArray*)g_ptr_array_index( screenTrack->profiles, monitor );
+                    if ( gba ) {
+                        dataPos = gba->data;
+                        dataLen = gba->len;
+                    }
+                } else {
+                    g_warning("No profile data tracked for the specified item.");
+                }
+                break;
+            }
+
+            curr = g_slist_next(curr);
+        }
+    }
+
+    if ( ptr ) {
+        *ptr = dataPos;
+    }
+    if ( len ) {
+        *len = dataLen;
+    }
+}
+
 void ege_color_prof_tracker_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec )
 {
     EgeColorProfTracker* tracker = EGE_COLOR_PROF_TRACKER( obj );
@@ -264,7 +354,7 @@ void ege_color_prof_tracker_set_property( GObject* obj, guint propId, const GVal
 }
 
 
-static void track_screen( GdkScreen* screen, EgeColorProfTracker* tracker )
+void track_screen( GdkScreen* screen, EgeColorProfTracker* tracker )
 {
     GSList* curr = tracked_screens;
     /* First remove the tracker from different screens */
@@ -457,9 +547,13 @@ static void set_profile( GdkScreen* screen, guint monitor, const guint8* data, g
         curr = g_slist_next(curr);
     }
     if ( curr ) {
+        /* Something happened to a screen being tracked. */
         ScreenTrack* track = (ScreenTrack*)curr->data;
+        gint screenNum = gdk_screen_get_number(screen);
         guint i = 0;
         GByteArray* previous = 0;
+        GSList* abstracts = 0;
+
         for ( i = track->profiles->len; i <= monitor; i++ ) {
             g_ptr_array_add( track->profiles, 0 );
         }
@@ -475,6 +569,10 @@ static void set_profile( GdkScreen* screen, guint monitor, const guint8* data, g
         } else {
             track->profiles->pdata[monitor] = 0;
         }
+
+        for ( abstracts = abstract_trackers; abstracts; abstracts = g_slist_next(abstracts) ) {
+            g_signal_emit( G_OBJECT(abstracts->data), signals[MODIFIED], 0, screenNum, monitor );
+        }
     }
 }
 
@@ -548,6 +646,10 @@ void handle_property_change(GdkScreen* screen, const gchar* name)
                 size = nitems + bytesAfter;
                 bytesAfter = 0;
                 nitems = 0;
+                if ( prop ) {
+                    XFree(prop);
+                    prop = 0;
+                }
                 if ( XGetWindowProperty( xdisplay, GDK_WINDOW_XID(gdk_screen_get_root_window(screen)),
                                          atom, 0, size, False, AnyPropertyType,
                                          &actualType, &actualFormat, &nitems, &bytesAfter, &prop ) == Success ) {
@@ -562,7 +664,7 @@ void handle_property_change(GdkScreen* screen, const gchar* name)
                 set_profile( screen, monitor, 0, 0 );
             }
         } else {
-            g_message("error loading profile property");
+            g_warning("error loading profile property");
         }
     }
     fire(screen, monitor);
index 69a3112fb8bc29b5958fae08f656a17a03e8416a..09aeae97038f7d304bfcf9518fb5cdd3bd219c0c 100644 (file)
@@ -98,6 +98,7 @@ GType ege_color_prof_tracker_get_type( void );
 EgeColorProfTracker* ege_color_prof_tracker_new( GtkWidget* target );
 
 void ege_color_prof_tracker_get_profile( EgeColorProfTracker const * tracker, gpointer* ptr, guint* len );
+void ege_color_prof_tracker_get_profile_for( guint screen, guint monitor, gpointer* ptr, guint* len );
 
 G_END_DECLS
 
index ca9988494e56cf85c97707dc54527b24079ea95a..d7381974615d08f83f56dcd3ef1abb1642f8024d 100644 (file)
@@ -184,6 +184,7 @@ static char const preferences_skeleton[] =
 "    <group\n"
 "       id=\"displayprofile\"\n"
 "       enable=\"0\"\n"
+"       from_display=\"0\"\n"
 "       intent=\"0\"\n"
 "       uri=\"\" />\n"
 "    <group\n"
index df2952f20c41d90373c7ab632ba88b2327d2e118..b950ed03b26ba26c8056ebd75eaa25e9a5735d61 100644 (file)
@@ -673,11 +673,20 @@ void InkscapePreferences::initPageCMS()
     _page_cms.add_line( false, "", *lbl, "", "", true);
 #endif // !ENABLE_LCMS
 
-    _page_cms.add_group_header( _("Display Calibration"));
+    _page_cms.add_group_header( _("Display Adjustment"));
 
     _page_cms.add_line( false, _("Display profile:"), _cms_display_profile, "",
                         _("The ICC profile to use to calibrate display output."), false);
 
+    _cms_from_display.init( _("Retrieve profile from display"), "options.displayprofile", "from_display", false);
+    _page_cms.add_line( false, "", _cms_from_display, "",
+#ifdef GDK_WINDOWING_X11
+                        _("Retrieve profiles from those attached to displays via XICC."), false);
+#else
+                        _("Retrieve profiles from those attached to displays."), false);
+#endif // GDK_WINDOWING_X11
+
+
     _cms_intent.init("options.displayprofile", "intent", intentLabels, intentValues, numIntents, 0);
     _page_cms.add_line( false, _("Display intent:"), _cms_intent, "",
                         _("The rendering intent to use to calibrate display output."), false);
@@ -765,6 +774,7 @@ void InkscapePreferences::initPageCMS()
     // disable it, but leave it visible
     _cms_intent.set_sensitive( false );
     _cms_display_profile.set_sensitive( false );
+    _cms_from_display.set_sensitive( false );
     _cms_softproof.set_sensitive( false );
     _cms_gamutwarn.set_sensitive( false );
     _cms_gamutcolor.set_sensitive( false );
index f5853c38ba44ee6bc55e4c7e65326de2a21cb411..0fe9a9bcc6cb54bb3e48df0907966e0f27ae0fb7 100644 (file)
@@ -163,6 +163,7 @@ protected:
     PrefCombo       _misc_overs_bitmap;
 
     Gtk::ComboBoxText   _cms_display_profile;
+    PrefCheckButton     _cms_from_display;
     PrefCombo           _cms_intent;
 
     PrefCheckButton     _cms_softproof;
index d7b8ac1702390150476d0249a7ef0e009cc54218..580274dc4e4b64cc8fb14ef456799ca97ea88716 100644 (file)
@@ -57,7 +57,7 @@
 #include "conn-avoid-ref.h"
 #include "ege-select-one-action.h"
 #include "ege-color-prof-tracker.h"
-#include "dom/util/digest.h"
+#include "color-profile-fns.h"
 #include "xml/node-observer.h"
 
 #if defined (SOLARIS_2_8)
@@ -116,12 +116,7 @@ using Inkscape::XML::Node;
 
 class PrefWatcher : public Inkscape::XML::NodeObserver {
 public:
-    PrefWatcher() :
-        NodeObserver(),
-        dtws()
-    {
-    }
-
+    PrefWatcher();
     virtual ~PrefWatcher();
 
 
@@ -139,13 +134,34 @@ public:
     void remove( SPDesktopWidget* dtw );
 
 private:
+    static void hook(EgeColorProfTracker *tracker, gint a, gint b, PrefWatcher *watcher);
+
     std::list<SPDesktopWidget*> dtws;
+    EgeColorProfTracker *_tracker;
 };
 
+PrefWatcher::PrefWatcher() :
+    NodeObserver(),
+    dtws(),
+    _tracker(0)
+{
+    _tracker = ege_color_prof_tracker_new(0);
+    g_signal_connect( G_OBJECT(_tracker), "modified", G_CALLBACK(hook), this );
+}
+
 PrefWatcher::~PrefWatcher()
 {
 }
 
+void PrefWatcher::hook(EgeColorProfTracker */*tracker*/, gint screen, gint monitor, PrefWatcher */*watcher*/)
+{
+    unsigned char* buf = 0;
+    guint len = 0;
+
+    ege_color_prof_tracker_get_profile_for( screen, monitor, reinterpret_cast<gpointer*>(&buf), &len );
+    Glib::ustring id = Inkscape::colorprofile_set_display_per( buf, len, screen, monitor );
+}
+
 void PrefWatcher::add( SPDesktopWidget* dtw )
 {
     dtws.push_back(dtw);
@@ -501,6 +517,15 @@ sp_desktop_widget_init (SPDesktopWidget *dtw)
     gtk_box_pack_start(GTK_BOX(dtw->statusbar), GTK_WIDGET(dtw->layer_selector->gobj()), FALSE, FALSE, 1);
 
     dtw->_tracker = ege_color_prof_tracker_new(GTK_WIDGET(dtw->layer_selector->gobj()));
+    {
+        Glib::ustring id = Inkscape::colorprofile_get_display_id( 0, 0 );
+        bool enabled = false;
+        if ( dtw->canvas->cms_key ) {
+            *(dtw->canvas->cms_key) = id;
+            enabled = !dtw->canvas->cms_key->empty();
+        }
+        gtk_widget_set_sensitive( dtw->cms_adjust, enabled );
+    }
     g_signal_connect( G_OBJECT(dtw->_tracker), "changed", G_CALLBACK(sp_dtw_color_profile_event), dtw );
 
     dtw->select_status_eventbox = gtk_event_box_new ();
@@ -707,18 +732,20 @@ sp_desktop_widget_event (GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dt
     return FALSE;
 }
 
-void sp_dtw_color_profile_event(EgeColorProfTracker *tracker, SPDesktopWidget */*dtw*/)
+void sp_dtw_color_profile_event(EgeColorProfTracker */*tracker*/, SPDesktopWidget *dtw)
 {
     // Handle profile changes
-    Md5Digest digest;
-    unsigned char* buf = 0;
-    guint len = 0;
-    ege_color_prof_tracker_get_profile( tracker, reinterpret_cast<gpointer*>(&buf), &len );
-    if ( buf && len ) {
-        digest.append(buf, len);
+    GdkScreen* screen = gtk_widget_get_screen(GTK_WIDGET(dtw));
+    gint screenNum = gdk_screen_get_number(screen);
+    gint monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_toplevel(GTK_WIDGET(dtw))->window);
+    Glib::ustring id = Inkscape::colorprofile_get_display_id( screenNum, monitor );
+    bool enabled = false;
+    if ( dtw->canvas->cms_key ) {
+        *(dtw->canvas->cms_key) = id;
+        dtw->requestCanvasUpdate();
+        enabled = !dtw->canvas->cms_key->empty();
     }
-    std::string hash = digest.finishHex();
-    //g_message("ICC profile %d bytes at %p is [%s]", len, buf, hash.c_str() );
+    gtk_widget_set_sensitive( dtw->cms_adjust, enabled );
 }
 
 void cms_adjust_toggled( GtkWidget */*button*/, gpointer data )