// Get the display ICC profile of the monitor associated with the widget. // For X display, uses the ICC profile specifications version 0.2 from // http://burtonini.com/blog/computers/xicc // Based on code from Gimp's modules/cdisplay_lcms.c void dt_ctl_set_display_profile() { if(!dt_control_running()) return; // make sure that no one gets a broken profile // FIXME: benchmark if the try is really needed when moving/resizing the window. Maybe we can just lock it and block if(pthread_rwlock_trywrlock(&darktable.control->xprofile_lock)) return; // we are already updating the profile. Or someone is reading right now. Too bad we can't distinguish that. Whatever ... GtkWidget *widget = dt_ui_center(darktable.gui->ui); guint8 *buffer = NULL; gint buffer_size = 0; gchar *profile_source = NULL; #if defined GDK_WINDOWING_X11 // we will use the xatom no matter what configured when compiled without colord gboolean use_xatom = TRUE; #if defined USE_COLORDGTK gboolean use_colord = TRUE; gchar *display_profile_source = dt_conf_get_string("ui_last/display_profile_source"); if(display_profile_source) { if(!strcmp(display_profile_source, "xatom")) use_colord = FALSE; else if(!strcmp(display_profile_source, "colord")) use_xatom = FALSE; g_free(display_profile_source); } #endif /* let's have a look at the xatom, just in case ... */ if(use_xatom) { GdkScreen *screen = gtk_widget_get_screen(widget); if ( screen==NULL ) screen = gdk_screen_get_default(); int monitor = gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window(widget)); char *atom_name; if (monitor > 0) atom_name = g_strdup_printf("_ICC_PROFILE_%d", monitor); else atom_name = g_strdup("_ICC_PROFILE"); profile_source = g_strdup_printf("xatom %s", atom_name); GdkAtom type = GDK_NONE; gint format = 0; gdk_property_get(gdk_screen_get_root_window(screen), gdk_atom_intern(atom_name, FALSE), GDK_NONE, 0, 64 * 1024 * 1024, FALSE, &type, &format, &buffer_size, &buffer); g_free(atom_name); } #ifdef USE_COLORDGTK /* also try to get the profile from colord. this will set the value asynchronously! */ if(use_colord) { CdWindow *window = cd_window_new(); GtkWidget *center_widget = dt_ui_center(darktable.gui->ui); cd_window_get_profile(window, center_widget, NULL, dt_ctl_get_display_profile_colord_callback, NULL); } #endif #elif defined GDK_WINDOWING_QUARTZ GdkScreen *screen = gtk_widget_get_screen(widget); if ( screen==NULL ) screen = gdk_screen_get_default(); int monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(widget)); CGDirectDisplayID ids[monitor + 1]; uint32_t total_ids; CMProfileRef prof = NULL; if(CGGetOnlineDisplayList(monitor + 1, &ids[0], &total_ids) == kCGErrorSuccess && total_ids == monitor + 1) CMGetProfileByAVID(ids[monitor], &prof); if ( prof!=NULL ) { CFDataRef data; data = CMProfileCopyICCData(NULL, prof); CMCloseProfile(prof); UInt8 *tmp_buffer = (UInt8 *) g_malloc(CFDataGetLength(data)); CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), tmp_buffer); buffer = (guint8 *) tmp_buffer; buffer_size = CFDataGetLength(data); CFRelease(data); } profile_source = g_strdup("osx color profile api"); #elif defined G_OS_WIN32 (void)widget; HDC hdc = GetDC (NULL); if ( hdc!=NULL ) { DWORD len = 0; GetICMProfile (hdc, &len, NULL); gchar *path = g_new (gchar, len); if (GetICMProfile (hdc, &len, path)) { gsize size; g_file_get_contents(path, (gchar**)&buffer, &size, NULL); buffer_size = size; } g_free (path); ReleaseDC (NULL, hdc); } profile_source = g_strdup("windows color profile api"); #endif int profile_changed = buffer_size > 0 && (darktable.control->xprofile_size != buffer_size || memcmp(darktable.control->xprofile_data, buffer, buffer_size) != 0); if(profile_changed) { cmsHPROFILE profile = NULL; char name[512]; // thanks to ufraw for this! g_free(darktable.control->xprofile_data); darktable.control->xprofile_data = buffer; darktable.control->xprofile_size = buffer_size; profile = cmsOpenProfileFromMem(buffer, buffer_size); if(profile) { dt_colorspaces_get_profile_name(profile, "en", "US", name, sizeof(name)); cmsCloseProfile(profile); } dt_print(DT_DEBUG_CONTROL, "[color profile] we got a new screen profile `%s' from the %s (size: %d)\n", *name?name:"(unknown)", profile_source, buffer_size); } pthread_rwlock_unlock(&darktable.control->xprofile_lock); if(profile_changed) dt_control_signal_raise(darktable.signals, DT_SIGNAL_CONTROL_PROFILE_CHANGED); g_free(profile_source); }
GimpColorProfile * gimp_widget_get_color_profile (GtkWidget *widget) { GimpColorProfile *profile = NULL; GdkScreen *screen; gint monitor; g_return_val_if_fail (widget == NULL || GTK_IS_WIDGET (widget), NULL); if (widget) { screen = gtk_widget_get_screen (widget); monitor = gimp_widget_get_monitor (widget); } else { screen = gdk_screen_get_default (); monitor = 0; } #if defined GDK_WINDOWING_X11 { GdkAtom type = GDK_NONE; gint format = 0; gint nitems = 0; gchar *atom_name; guchar *data = NULL; if (monitor > 0) atom_name = g_strdup_printf ("_ICC_PROFILE_%d", monitor); else atom_name = g_strdup ("_ICC_PROFILE"); if (gdk_property_get (gdk_screen_get_root_window (screen), gdk_atom_intern (atom_name, FALSE), GDK_NONE, 0, 64 * 1024 * 1024, FALSE, &type, &format, &nitems, &data) && nitems > 0) { profile = gimp_color_profile_new_from_icc_profile (data, nitems, NULL); g_free (data); } g_free (atom_name); } #elif defined GDK_WINDOWING_QUARTZ { CMProfileRef prof = NULL; CMGetProfileByAVID (monitor, &prof); if (prof) { CFDataRef data; data = CMProfileCopyICCData (NULL, prof); CMCloseProfile (prof); if (data) { UInt8 *buffer = g_malloc (CFDataGetLength (data)); /* We cannot use CFDataGetBytesPtr(), because that returns * a const pointer where cmsOpenProfileFromMem wants a * non-const pointer. */ CFDataGetBytes (data, CFRangeMake (0, CFDataGetLength (data)), buffer); profile = gimp_color_profile_new_from_icc_profile (data, CFDataGetLength (data), NULL); g_free (buffer); CFRelease (data); } } } #elif defined G_OS_WIN32 { HDC hdc = GetDC (NULL); if (hdc) { gchar *path; gint32 len = 0; GetICMProfile (hdc, &len, NULL); path = g_new (gchar, len); if (GetICMProfile (hdc, &len, path)) { GFile *file = g_file_new_for_path (path); profile = gimp_color_profile_new_from_file (file, NULL); g_object_unref (file); } g_free (path); ReleaseDC (NULL, hdc); } } #endif return profile; }
static cmsHPROFILE cdisplay_lcms_get_display_profile (CdisplayLcms *lcms) { GimpColorConfig *config; cmsHPROFILE profile = NULL; config = gimp_color_display_get_config (GIMP_COLOR_DISPLAY (lcms)); #if defined GDK_WINDOWING_X11 if (config->display_profile_from_gdk) { GdkScreen *screen; GdkAtom type = GDK_NONE; gint format = 0; gint nitems = 0; gint monitor = 0; gchar *atom_name; guchar *data = NULL; screen = cdisplay_lcms_get_screen (lcms, &monitor); if (monitor > 0) atom_name = g_strdup_printf ("_ICC_PROFILE_%d", monitor); else atom_name = g_strdup ("_ICC_PROFILE"); if (gdk_property_get (gdk_screen_get_root_window (screen), gdk_atom_intern (atom_name, FALSE), GDK_NONE, 0, 64 * 1024 * 1024, FALSE, &type, &format, &nitems, &data) && nitems > 0) { profile = cmsOpenProfileFromMem (data, nitems); g_free (data); } g_free (atom_name); } #elif defined GDK_WINDOWING_QUARTZ if (config->display_profile_from_gdk) { CMProfileRef prof = NULL; gint monitor = 0; cdisplay_lcms_get_screen (lcms, &monitor); CMGetProfileByAVID (monitor, &prof); if (prof) { CFDataRef data; data = CMProfileCopyICCData (NULL, prof); CMCloseProfile (prof); if (data) { UInt8 *buffer = g_malloc (CFDataGetLength (data)); /* We cannot use CFDataGetBytesPtr(), because that returns * a const pointer where cmsOpenProfileFromMem wants a * non-const pointer. */ CFDataGetBytes (data, CFRangeMake (0, CFDataGetLength (data)), buffer); profile = cmsOpenProfileFromMem (buffer, CFDataGetLength (data)); g_free (buffer); CFRelease (data); } } } #elif defined G_OS_WIN32 if (config->display_profile_from_gdk) { HDC hdc = GetDC (NULL); if (hdc) { gchar *path; gint32 len = 0; GetICMProfile (hdc, &len, NULL); path = g_new (gchar, len); if (GetICMProfile (hdc, &len, path)) profile = cmsOpenProfileFromFile (path, "r"); g_free (path); ReleaseDC (NULL, hdc); } } #endif if (! profile && config->display_profile) profile = cmsOpenProfileFromFile (config->display_profile, "r"); return profile; }