CGError CGGetDisplayTransferByTable(CGDirectDisplayID display, uint32_t gamma_size, CGGammaValue* red, CGGammaValue* green, CGGammaValue* blue, uint32_t* gamma_size_out) { xcb_randr_get_crtc_gamma_cookie_t gamma_cookie; xcb_randr_get_crtc_gamma_reply_t* gamma_reply; xcb_generic_error_t* error; uint16_t* r_int; uint16_t* g_int; uint16_t* b_int; long i; if (gamma_size != 256) { fprintf(stderr, "Gamma size should be 256, got %u\n", gamma_size); abort(); } *gamma_size_out = 256; gamma_cookie = xcb_randr_get_crtc_gamma(conn, crtcs[display]); gamma_reply = xcb_randr_get_crtc_gamma_reply(conn, gamma_cookie, &error); if (error) { fprintf(stderr, "Failed to write gamma ramps\n"); return ~kCGErrorSuccess; } r_int = xcb_randr_get_crtc_gamma_red(gamma_reply); g_int = xcb_randr_get_crtc_gamma_green(gamma_reply); b_int = xcb_randr_get_crtc_gamma_blue(gamma_reply); for (i = 0; i < 256; i++) { red[i] = (CGGammaValue)(r_int[i]) / UINT16_MAX; green[i] = (CGGammaValue)(g_int[i]) / UINT16_MAX; blue[i] = (CGGammaValue)(b_int[i]) / UINT16_MAX; } free(gamma_reply); return kCGErrorSuccess; }
int randr_start(randr_state_t *state) { xcb_generic_error_t *error; int screen_num = state->screen_num; if (screen_num < 0) screen_num = state->preferred_screen; /* Get screen */ const xcb_setup_t *setup = xcb_get_setup(state->conn); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); state->screen = NULL; for (int i = 0; iter.rem > 0; i++) { if (i == screen_num) { state->screen = iter.data; break; } xcb_screen_next(&iter); } if (state->screen == NULL) { fprintf(stderr, _("Screen %i could not be found.\n"), screen_num); return -1; } /* Get list of CRTCs for the screen */ xcb_randr_get_screen_resources_current_cookie_t res_cookie = xcb_randr_get_screen_resources_current(state->conn, state->screen->root); xcb_randr_get_screen_resources_current_reply_t *res_reply = xcb_randr_get_screen_resources_current_reply(state->conn, res_cookie, &error); if (error) { fprintf(stderr, _("`%s' returned error %d\n"), "RANDR Get Screen Resources Current", error->error_code); return -1; } state->crtc_count = res_reply->num_crtcs; state->crtcs = calloc(state->crtc_count, sizeof(randr_crtc_state_t)); if (state->crtcs == NULL) { perror("malloc"); state->crtc_count = 0; return -1; } xcb_randr_crtc_t *crtcs = xcb_randr_get_screen_resources_current_crtcs(res_reply); /* Save CRTC identifier in state */ for (int i = 0; i < state->crtc_count; i++) { state->crtcs[i].crtc = crtcs[i]; } free(res_reply); /* Save size and gamma ramps of all CRTCs. Current gamma ramps are saved so we can restore them at program exit. */ for (int i = 0; i < state->crtc_count; i++) { xcb_randr_crtc_t crtc = state->crtcs[i].crtc; /* Request size of gamma ramps */ xcb_randr_get_crtc_gamma_size_cookie_t gamma_size_cookie = xcb_randr_get_crtc_gamma_size(state->conn, crtc); xcb_randr_get_crtc_gamma_size_reply_t *gamma_size_reply = xcb_randr_get_crtc_gamma_size_reply(state->conn, gamma_size_cookie, &error); if (error) { fprintf(stderr, _("`%s' returned error %d\n"), "RANDR Get CRTC Gamma Size", error->error_code); return -1; } unsigned int ramp_size = gamma_size_reply->size; state->crtcs[i].ramp_size = ramp_size; free(gamma_size_reply); if (ramp_size == 0) { fprintf(stderr, _("Gamma ramp size too small: %i\n"), ramp_size); return -1; } /* Request current gamma ramps */ xcb_randr_get_crtc_gamma_cookie_t gamma_get_cookie = xcb_randr_get_crtc_gamma(state->conn, crtc); xcb_randr_get_crtc_gamma_reply_t *gamma_get_reply = xcb_randr_get_crtc_gamma_reply(state->conn, gamma_get_cookie, &error); if (error) { fprintf(stderr, _("`%s' returned error %d\n"), "RANDR Get CRTC Gamma", error->error_code); return -1; } uint16_t *gamma_r = xcb_randr_get_crtc_gamma_red(gamma_get_reply); uint16_t *gamma_g = xcb_randr_get_crtc_gamma_green(gamma_get_reply); uint16_t *gamma_b = xcb_randr_get_crtc_gamma_blue(gamma_get_reply); /* Allocate space for saved gamma ramps */ state->crtcs[i].saved_ramps = malloc(3*ramp_size*sizeof(uint16_t)); if (state->crtcs[i].saved_ramps == NULL) { perror("malloc"); free(gamma_get_reply); return -1; } /* Copy gamma ramps into CRTC state */ memcpy(&state->crtcs[i].saved_ramps[0*ramp_size], gamma_r, ramp_size*sizeof(uint16_t)); memcpy(&state->crtcs[i].saved_ramps[1*ramp_size], gamma_g, ramp_size*sizeof(uint16_t)); memcpy(&state->crtcs[i].saved_ramps[2*ramp_size], gamma_b, ramp_size*sizeof(uint16_t)); free(gamma_get_reply); } return 0; }
CGError CGGetOnlineDisplayList(uint32_t max_size, CGDirectDisplayID* displays_out, uint32_t* count_out) { uint32_t i; if (conn == NULL) { xcb_generic_error_t* error; xcb_screen_iterator_t iter; xcb_randr_get_screen_resources_current_cookie_t res_cookie; xcb_randr_get_crtc_gamma_cookie_t gamma_cookie; xcb_randr_get_crtc_gamma_reply_t* gamma_reply; conn = xcb_connect(NULL, NULL); iter = xcb_setup_roots_iterator(xcb_get_setup(conn)); res_cookie = xcb_randr_get_screen_resources_current(conn, iter.data->root); res_reply = xcb_randr_get_screen_resources_current_reply(conn, res_cookie, &error); if (error) { fprintf(stderr, "Failed to open X connection\n"); xcb_disconnect(conn); crtc_count = 0; return ~kCGErrorSuccess; } crtc_count = (uint32_t)(res_reply->num_crtcs); crtcs = xcb_randr_get_screen_resources_current_crtcs(res_reply); original_ramps = malloc(crtc_count * 3 * 256 * sizeof(uint16_t)); if (original_ramps == NULL) { perror("malloc"); xcb_disconnect(conn); crtc_count = 0; return ~kCGErrorSuccess; } for (i = 0; i < crtc_count; i++) { gamma_cookie = xcb_randr_get_crtc_gamma(conn, crtcs[i]); gamma_reply = xcb_randr_get_crtc_gamma_reply(conn, gamma_cookie, &error); if (error) { fprintf(stderr, "Failed to read gamma ramps\n"); xcb_disconnect(conn); crtc_count = 0; return ~kCGErrorSuccess; } #define __DEST(C) original_ramps + (C + 3 * i) * 256 #define __SRC(C) xcb_randr_get_crtc_gamma_##C(gamma_reply) memcpy(__DEST(0), __SRC(red), 256 * sizeof(uint16_t)); memcpy(__DEST(1), __SRC(green), 256 * sizeof(uint16_t)); memcpy(__DEST(2), __SRC(blue), 256 * sizeof(uint16_t)); #undef __SRC #undef __DEST free(gamma_reply); } } for (i = 0; (i < max_size) && (i < crtc_count); i++) *(displays_out + i) = (CGDirectDisplayID)i; *count_out = i; return kCGErrorSuccess; }