147 printf(
"this executable doesn't do anything for non-X11 systems currently\n");
152 printf(
"this executable was built with colord support enabled\n");
154 printf(
"this executable was built without colord support\n");
158 printf(
"ansel itself was built with colord support enabled\n");
160 printf(
"ansel itself was built without colord support\n");
166 GList *monitor_list = NULL;
167 const char *disp_name_env;
171 if((disp_name_env = g_getenv(
"DISPLAY")) != NULL)
174 g_strlcpy(disp_name, disp_name_env,
sizeof(disp_name));
175 if((pp = g_strrstr(disp_name,
":")) != NULL)
177 if((pp = g_strstr_len(pp, -1,
".")) == NULL)
178 g_strlcat(disp_name,
".0",
sizeof(disp_name));
181 g_strlcat(disp_name,
"0",
sizeof(disp_name));
191 g_strlcpy(disp_name,
":0.0",
sizeof(disp_name));
193 Display *display = XOpenDisplay(disp_name);
196 fprintf(stderr,
"can't open display `%s'\n", XDisplayName(disp_name));
200 int max_screen = ScreenCount(display);
201 for(
int screen = 0; screen < max_screen; ++screen)
205 Window root = RootWindow(display, screen);
206 XRRScreenResources *rsrc = XRRGetScreenResources(display, root);
209 XID primary = XRRGetOutputPrimary(display, root);
210 gboolean have_primary =
FALSE;
214 for(
int crtc = 0; crtc < rsrc->ncrtc; crtc++)
216 XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(display, rsrc, rsrc->crtcs[crtc]);
220 if(crtc_info->mode != None && crtc_info->noutput > 0)
222 for(
int output = 0; output < crtc_info->noutput; output++)
224 if(crtc_info->outputs[output] == primary)
232 XRRFreeCrtcInfo(crtc_info);
235 if (primary_id == -1)
236 printf(
"couldn't locate primary CRTC!\n");
239 printf(
"primary CRTC is at CRTC %d\n", primary_id);
246 for(
int crtc = 0; crtc < rsrc->ncrtc; ++crtc)
248 XRROutputInfo *output_info = NULL;
249 XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(display, rsrc, rsrc->crtcs[crtc]);
252 printf(
"can't get CRTC info for screen %d CRTC %d\n", screen, crtc);
256 if(crtc_info->mode == None || crtc_info->noutput <= 0)
258 printf(
"CRTC for screen %d CRTC %d has no mode or no output, skipping\n", screen, crtc);
264 gboolean is_primary =
FALSE;
268 for(
int j = 0; j < crtc_info->noutput; j++)
270 if(crtc_info->outputs[j] == primary)
279 output_info = XRRGetOutputInfo(display, rsrc, crtc_info->outputs[output]);
282 printf(
"can't get output info for screen %d CRTC %d output %d\n", screen, crtc, output);
286 if(output_info->connection == RR_Disconnected)
288 printf(
"screen %d CRTC %d output %d is disconnected, skipping\n", screen, crtc, output);
292 monitor_t *monitor = (monitor_t *)calloc(1,
sizeof(monitor_t));
295 Atom edid_atom = XInternAtom(display,
"EDID", False), actual_type;
297 unsigned long nitems, bytes_after;
299 int res = XRRGetOutputProperty(display, rsrc->outputs[output], edid_atom, 0, G_MAXLONG,
FALSE,
300 FALSE, XA_INTEGER, &actual_type, &actual_format, &nitems, &bytes_after, &prop);
301 if(res == Success && actual_type == XA_INTEGER && actual_format == 8 && nitems != 0)
303 printf(
"EDID for %s has size %lu\n", output_info->name, nitems);
310 monitor->root = root;
311 monitor->screen = screen;
312 monitor->crtc = crtc;
313 monitor->is_primary = is_primary;
314 monitor->atom_id = atom_id++;
315 monitor->name = g_strdup(output_info->name);
316 monitor_list = g_list_prepend(monitor_list, monitor);
319 XRRFreeCrtcInfo(crtc_info);
320 XRRFreeOutputInfo(output_info);
323 XRRFreeScreenResources(rsrc);
327 monitor_list = g_list_sort(monitor_list, sort_monitor_list);
329 int last_screen = -1;
330 for(GList *iter = monitor_list; iter; iter = g_list_next(iter))
332 monitor_t *monitor = (monitor_t *)iter->data;
333 if(monitor->screen != last_screen) atom_id = 0;
334 last_screen = monitor->screen;
335 monitor->atom_id = atom_id++;
339 for(GList *iter = monitor_list; iter; iter = g_list_next(iter))
341 monitor_t *monitor = (monitor_t *)iter->data;
342 if(monitor->atom_id == 0)
343 monitor->x_atom_name = g_strdup(
"_ICC_PROFILE");
345 monitor->x_atom_name = g_strdup_printf(
"_ICC_PROFILE_%d", monitor->atom_id);
347 Atom atom = XInternAtom(display, monitor->x_atom_name,
FALSE), actual_type;
349 unsigned long nitems, bytes_after;
352 int res = XGetWindowProperty(display, monitor->root, atom, 0, G_MAXLONG,
FALSE, XA_CARDINAL, &actual_type,
353 &actual_format, &nitems, &bytes_after, &prop);
355 if(res == Success && actual_type == XA_CARDINAL && actual_format == 8)
357 monitor->x_atom_length = nitems;
358 monitor->x_atom_data = prop;
367 CdClient *client = cd_client_new();
368 if(
IS_NULL_PTR(client) || !cd_client_connect_sync(client, NULL, NULL))
370 fprintf(stderr,
"error connecting to colord\n");
373 for(GList *iter = monitor_list; iter; iter = g_list_next(iter))
375 monitor_t *monitor = (monitor_t *)iter->data;
377 CdDevice *device = cd_client_find_device_by_property_sync(client, CD_DEVICE_METADATA_XRANDR_NAME,
378 monitor->name, NULL, NULL);
379 if(device && cd_device_connect_sync(device, NULL, NULL))
381 CdProfile *profile = cd_device_get_default_profile(device);
384 if(cd_profile_connect_sync(profile, NULL, NULL))
386 CdIcc *icc = cd_profile_load_icc(profile, CD_ICC_LOAD_FLAGS_FALLBACK_MD5, NULL, NULL);
389 monitor->colord_filename = g_strdup(cd_icc_get_filename(icc));
393 g_object_unref(profile);
396 if(device) g_object_unref(device);
398 if(client) g_object_unref(client);
403 gboolean any_profile_mismatch =
FALSE, any_unprofiled_monitor =
FALSE;
404 for(GList *iter = monitor_list; iter; iter = g_list_next(iter))
406 monitor_t *monitor = (monitor_t *)iter->data;
407 char *message = NULL;
409 char *monitor_name = monitor->name ? monitor->name :
"(unknown)";
410 char *x_atom_name = monitor->x_atom_name ? monitor->x_atom_name :
"(not found)";
411 char *tmp = get_profile_description(monitor->x_atom_data, monitor->x_atom_length);
412 char *x_atom_description = tmp ? tmp : g_strdup(
"(none)");
415 if(monitor->x_atom_length == 0)
417 message =
"the X atom seems to be missing";
418 any_unprofiled_monitor =
TRUE;
421 char *colord_filename = monitor->colord_filename ? monitor->colord_filename :
"(none)",
424 || g_file_test(monitor->colord_filename, G_FILE_TEST_IS_REGULAR) ==
FALSE)
426 colord_description = g_strdup(
"(file not found)");
427 if(monitor->x_atom_length > 0)
429 any_profile_mismatch =
TRUE;
430 message =
"the X atom and colord returned different profiles";
434 any_unprofiled_monitor =
TRUE;
435 message =
"the X atom and colord returned the same profile";
440 unsigned char *tmp_data = NULL;
442 g_file_get_contents(monitor->colord_filename, (gchar **)&tmp_data, &
size, NULL);
443 gboolean profiles_equal = (
size == monitor->x_atom_length
444 && (
size == 0 || memcmp(monitor->x_atom_data, tmp_data,
size) == 0));
445 if(!profiles_equal) any_profile_mismatch =
TRUE;
446 if(
size == 0 && monitor->x_atom_length == 0) any_unprofiled_monitor =
TRUE;
447 message = profiles_equal ?
"the X atom and colord returned the same profile"
448 :
"the X atom and colord returned different profiles";
449 tmp = get_profile_description(tmp_data,
size);
450 colord_description = tmp ? tmp : g_strdup(
"(none)");
457 printf(
"\n%s", monitor_name);
458 if(message) printf(
"\t%s", message);
459 printf(
"\n\tX atom:\t%s (%" G_GSIZE_FORMAT
" bytes)\n\t\tdescription: %s\n", x_atom_name, monitor->x_atom_length,
462 printf(
"\tcolord:\t\"%s\"\n\t\tdescription: %s\n", colord_filename, colord_description);
474 if(any_profile_mismatch || any_unprofiled_monitor)
476 printf(
"\nBetter check your system setup\n");
477 if(any_profile_mismatch) printf(
" - some monitors reported different profiles\n");
478 if(any_unprofiled_monitor) printf(
" - some monitors lacked a profile\n");
479 printf(
"You may experience inconsistent color rendition between color managed applications\n");
482 printf(
"\nYour system seems to be correctly configured\n");
486 XCloseDisplay(display);
487 for(GList *iter = monitor_list; iter; iter = g_list_next(iter))
489 monitor_t *monitor = (monitor_t *)iter->data;
492 XFree(monitor->x_atom_data);
494 dt_free(monitor->colord_filename);