/* * Initialize RandR and obtain current monitors */ static int ya_init_randr() { xcb_randr_get_screen_resources_current_reply_t *res_reply; res_reply = xcb_randr_get_screen_resources_current_reply(ya.c, xcb_randr_get_screen_resources_current(ya.c, ya.scr->root), NULL); if (!res_reply) { return -1; //just report error } int mon_num = xcb_randr_get_screen_resources_current_outputs_length(res_reply); xcb_randr_output_t *ops = xcb_randr_get_screen_resources_current_outputs(res_reply); xcb_randr_get_output_info_reply_t *op_reply; xcb_randr_get_crtc_info_reply_t *crtc_reply; ya_monitor_t *tmpmon; char *tname; int tname_len; for (int i=0; i < mon_num; i++) { op_reply = xcb_randr_get_output_info_reply(ya.c, xcb_randr_get_output_info(ya.c, ops[i], XCB_CURRENT_TIME), NULL); if (op_reply->crtc == XCB_NONE) continue; crtc_reply = xcb_randr_get_crtc_info_reply(ya.c, xcb_randr_get_crtc_info(ya.c, op_reply->crtc, XCB_CURRENT_TIME), NULL); if(!crtc_reply) continue; tmpmon = calloc(1, sizeof(ya_monitor_t)); tmpmon->pos = (xcb_rectangle_t){crtc_reply->x, crtc_reply->y, crtc_reply->width, crtc_reply->height}; tname = (char *)xcb_randr_get_output_info_name(op_reply); tname_len = xcb_randr_get_output_info_name_length(op_reply); strncpy(tmpmon->name, tname, tname_len); tmpmon->name[CMONLEN-1] = '\0'; if (ya.curmon) { ya.curmon->next_mon = tmpmon; tmpmon->prev_mon = ya.curmon; } ya.curmon = tmpmon; //printf("%s %d %d %d %d %d\n", tmpmon->name, tname_len, tmpmon->pos.x, // tmpmon->pos.y, tmpmon->pos.width, tmpmon->pos.height); } return 0; }
/* * Get RANDR resources and figure out how many outputs there are. */ void randr_get(xcb_connection_t * conn,xcb_screen_t * screen) { xcb_randr_get_screen_resources_current_cookie_t rcookie; xcb_randr_get_screen_resources_current_reply_t *res; xcb_randr_output_t *outputs; int len; xcb_timestamp_t timestamp; rcookie = xcb_randr_get_screen_resources_current(conn, screen->root); res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL); if (NULL == res) { printf("No RANDR extension available.\n"); return; } timestamp = res->config_timestamp; len = xcb_randr_get_screen_resources_current_outputs_length(res); outputs = xcb_randr_get_screen_resources_current_outputs(res); free(res); PDEBUG("Found %d outputs.\n", len); /* Request information for all outputs. */ char *name; xcb_randr_get_crtc_info_cookie_t icookie; xcb_randr_get_crtc_info_reply_t *crtc = NULL; xcb_randr_get_output_info_reply_t *output; struct monitor *mon; struct monitor *clonemon; xcb_randr_get_output_info_cookie_t ocookie[len]; int i; for (i = 0; i < len; i++) { ocookie[i] = xcb_randr_get_output_info(conn, outputs[i], timestamp); } /* Loop through all outputs. */ for (i = 0; i < len; i ++) { output = xcb_randr_get_output_info_reply(conn, ocookie[i], NULL); if (output == NULL) { continue; } asprintf(&name, "%.*s", xcb_randr_get_output_info_name_length(output), xcb_randr_get_output_info_name(output)); PDEBUG("Name: %s\n", name); PDEBUG("id: %d\n" , outputs[i]); PDEBUG("Size: %d x %d mm.\n", output->mm_width, output->mm_height); if (XCB_NONE != output->crtc) { icookie = xcb_randr_get_crtc_info(conn, output->crtc, timestamp); crtc = xcb_randr_get_crtc_info_reply(conn, icookie, NULL); if (NULL == crtc) { return; } PDEBUG("CRTC: at %d, %d, size: %d x %d.\n", crtc->x, crtc->y, crtc->width, crtc->height); /* Check if it's a clone. */ clonemon = findclones(outputs[i], crtc->x, crtc->y); if (NULL != clonemon) { PDEBUG("Monitor %s, id %d is a clone of %s, id %d. Skipping.\n", name, outputs[i], clonemon->name, clonemon->id); continue; } /* Do we know this monitor already? */ if (NULL == (mon = findmonitor(outputs[i]))) { PDEBUG("Monitor not known, adding to list.\n"); addmonitor(outputs[i], name, crtc->x, crtc->y, crtc->width, crtc->height); } else { bool changed = false; /* * We know this monitor. Update information. If it's * smaller than before, rearrange windows. */ PDEBUG("Known monitor. Updating info.\n"); if (crtc->x != mon->x) { mon->x = crtc->x; changed = true; } if (crtc->y != mon->y) { mon->y = crtc->y; changed = true; } if (crtc->width != mon->width) { mon->width = crtc->width; changed = true; } if (crtc->height != mon->height) { mon->height = crtc->height; changed = true; } if (changed) { arrbymon(mon); } } free(crtc); } else { PDEBUG("Monitor not used at the moment.\n"); /* * Check if it was used before. If it was, do something. */ if ((mon = findmonitor(outputs[i]))) { struct item *item; struct client *client; /* Check all windows on this monitor and move them to * the next or to the first monitor if there is no * next. * * FIXME: Use per monitor workspace list instead of * global window list. */ for (item = winlist; item != NULL; item = item->next) { client = item->data; if (client->monitor == mon) { if (NULL == client->monitor->item->next) { if (NULL == monlist) { client->monitor = NULL; } else { client->monitor = monlist->data; } } else { client->monitor = client->monitor->item->next->data; } fitonscreen(client); } } /* for */ /* It's not active anymore. Forget about it. */ delmonitor(mon); } } free(output); } /* for */ }
int x11_find_all_outputs(char*** out_outputs, size_t* out_outputs_count) { xcb_generic_error_t* error = NULL; xcb_randr_query_version_cookie_t version_cookie; xcb_randr_query_version_reply_t* version_reply = NULL; const xcb_setup_t* setup; xcb_screen_iterator_t iter; xcb_screen_t* screen; xcb_randr_get_screen_resources_current_cookie_t screen_cookie; xcb_randr_get_output_info_cookie_t output_cookie; xcb_randr_output_t* outputs = NULL; *out_outputs_count = 0; *out_outputs = NULL; connection = xcb_connect(NULL, NULL); if (connection == NULL) goto pfail; version_cookie = xcb_randr_query_version(connection, RANDR_VERSION_MAJOR, RANDR_VERSION_MINOR); version_reply = xcb_randr_query_version_reply(connection, version_cookie, &error); if ((error != NULL) || (version_reply == NULL)) { if ((error == NULL) && (version_reply == NULL)) connection = NULL; goto pfail; } if ((version_reply->major_version != RANDR_VERSION_MAJOR) || (version_reply->minor_version < RANDR_VERSION_MINOR)) { fprintf(stderr, "%s: wrong RandR version\n", argv0); goto fail; } free(version_reply), version_reply = NULL; setup = xcb_get_setup(connection); if (setup == NULL) goto pfail; iter = xcb_setup_roots_iterator(setup); for (; iter.rem > 0; xcb_screen_next(&iter)) { size_t i, n; screen = iter.data; if (screen == NULL) abort(); screen_cookie = xcb_randr_get_screen_resources_current(connection, screen->root); screen_reply = xcb_randr_get_screen_resources_current_reply(connection, screen_cookie, &error); if (error != NULL) goto pfail; outputs = xcb_randr_get_screen_resources_current_outputs(screen_reply); if (outputs == NULL) goto pfail; for (i = 0, n = (size_t)(screen_reply->num_outputs); i < n; i++) { uint8_t* name; uint16_t length; char* namez; char** old; output_cookie = xcb_randr_get_output_info(connection, outputs[i], screen_reply->config_timestamp); output_reply = xcb_randr_get_output_info_reply(connection, output_cookie, &error); if (error != NULL) goto pfail; if (output_reply->connection != XCB_RANDR_CONNECTION_CONNECTED) goto next_output; name = xcb_randr_get_output_info_name(output_reply); length = output_reply->name_len; if (name == NULL) goto pfail; *out_outputs = realloc(old = *out_outputs, (*out_outputs_count + 1) * sizeof(char*)); if (*out_outputs == NULL) { *out_outputs = old; goto pfail; } namez = malloc(((size_t)length + 1) * sizeof(char)); if (namez == NULL) goto pfail; namez[length] = '\0'; while (length--) namez[length] = (char)(name[length]); (*out_outputs)[(*out_outputs_count)++] = namez; next_output: free(output_reply), output_reply = NULL; } free(screen_reply), screen_reply = NULL; } xcb_disconnect(connection); return 0; pfail: perror(argv0); fail: free(version_reply); free(screen_reply); free(output_reply); if (connection != NULL) xcb_disconnect(connection); return -1; }
int x11_initialise_animation(int coarse_fine, double duration, double degrees, const char* output) { xcb_generic_error_t* error = NULL; xcb_randr_query_version_cookie_t version_cookie; xcb_randr_query_version_reply_t* version_reply = NULL; const xcb_setup_t* setup; xcb_screen_iterator_t iter; xcb_screen_t* screen; xcb_randr_get_screen_resources_current_cookie_t screen_cookie; xcb_randr_get_output_info_cookie_t output_cookie; xcb_randr_crtc_t* crtcs = NULL; xcb_randr_output_t* outputs = NULL; int found_output = 0; size_t i, n; xcb_randr_get_crtc_transform_cookie_t transform_cookie; xcb_randr_get_crtc_transform_reply_t* transform_reply = NULL; fine = coarse_fine ? (coarse_fine == 1) : 1; connection = NULL; screen_reply = NULL; output_reply = NULL; connection = xcb_connect(NULL, NULL); if (connection == NULL) goto pfail; version_cookie = xcb_randr_query_version(connection, RANDR_VERSION_MAJOR, RANDR_VERSION_MINOR); version_reply = xcb_randr_query_version_reply(connection, version_cookie, &error); if ((error != NULL) || (version_reply == NULL)) { if ((error == NULL) && (version_reply == NULL)) connection = NULL; goto pfail; } if ((version_reply->major_version != RANDR_VERSION_MAJOR) || (version_reply->minor_version < RANDR_VERSION_MINOR)) { fprintf(stderr, "%s: wrong RandR version\n", argv0); goto fail; } free(version_reply), version_reply = NULL; setup = xcb_get_setup(connection); if (setup == NULL) goto pfail; iter = xcb_setup_roots_iterator(setup); for (; (iter.rem > 0) && !found_output; xcb_screen_next(&iter)) { screen = iter.data; if (screen == NULL) abort(); screen_cookie = xcb_randr_get_screen_resources_current(connection, screen->root); screen_reply = xcb_randr_get_screen_resources_current_reply(connection, screen_cookie, &error); if (error != NULL) goto pfail; crtcs = xcb_randr_get_screen_resources_current_crtcs(screen_reply); outputs = xcb_randr_get_screen_resources_current_outputs(screen_reply); if (outputs == NULL) goto pfail; for (i = 0, n = (size_t)(screen_reply->num_outputs); (i < n) && !found_output; i++) { uint8_t* name; uint16_t length; char* namez = NULL; uint16_t j; output_cookie = xcb_randr_get_output_info(connection, outputs[i], screen_reply->config_timestamp); output_reply = xcb_randr_get_output_info_reply(connection, output_cookie, &error); if (error != NULL) goto pfail; if (output_reply->connection != XCB_RANDR_CONNECTION_CONNECTED) goto next_output; name = xcb_randr_get_output_info_name(output_reply); length = output_reply->name_len; if (name == NULL) goto pfail; namez = malloc(((size_t)length + 1) * sizeof(char)); if (namez == NULL) goto pfail; namez[length] = '\0'; while (length--) namez[length] = (char)(name[length]); if (strcmp(namez, output)) goto next_output; found_output = 1; free(namez), namez = NULL; for (j = 0; j < screen_reply->num_crtcs; j++) if (crtcs[j] == output_reply->crtc) break; if (j == screen_reply->num_crtcs) { fprintf(stderr, "%s: could not find CRTC associated with output: %s\n", argv0, output); goto fail; } crtc = crtcs[j]; goto exit_search_loop; next_output: free(namez); free(output_reply), output_reply = NULL; } free(screen_reply), screen_reply = NULL; } exit_search_loop: if (!found_output) { fprintf(stderr, "%s: could not find output: %s\n", argv0, output); goto fail; } transform_cookie = xcb_randr_get_crtc_transform(connection, crtc); transform_reply = xcb_randr_get_crtc_transform_reply(connection, transform_cookie, &error); if (error != NULL) goto pfail; original_transform = transform_reply->pending_transform; free(transform_reply); return 0; pfail: perror(argv0); fail: free(version_reply); free(screen_reply); free(output_reply); free(transform_reply); if (connection != NULL) xcb_disconnect(connection); return -1; return (void)duration, (void)degrees, -1; /* TODO */ }
bool import_monitors(void) { PUTS("import monitors"); xcb_randr_get_screen_resources_current_reply_t *sres = xcb_randr_get_screen_resources_current_reply(dpy, xcb_randr_get_screen_resources_current(dpy, root), NULL); if (sres == NULL) return false; monitor_t *m, *mm = NULL; int len = xcb_randr_get_screen_resources_current_outputs_length(sres); xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(sres); xcb_randr_get_output_info_cookie_t cookies[len]; for (int i = 0; i < len; i++) cookies[i] = xcb_randr_get_output_info(dpy, outputs[i], XCB_CURRENT_TIME); for (m = mon_head; m != NULL; m = m->next) m->wired = false; for (int i = 0; i < len; i++) { xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(dpy, cookies[i], NULL); if (info != NULL) { if (info->crtc != XCB_NONE) { xcb_randr_get_crtc_info_reply_t *cir = xcb_randr_get_crtc_info_reply(dpy, xcb_randr_get_crtc_info(dpy, info->crtc, XCB_CURRENT_TIME), NULL); if (cir != NULL) { xcb_rectangle_t rect = (xcb_rectangle_t) {cir->x, cir->y, cir->width, cir->height}; mm = get_monitor_by_id(outputs[i]); if (mm != NULL) { mm->rectangle = rect; update_root(mm); for (desktop_t *d = mm->desk_head; d != NULL; d = d->next) for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) translate_client(mm, mm, n->client); arrange(mm, mm->desk); mm->wired = true; PRINTF("update monitor %s (0x%X)\n", mm->name, mm->id); } else { mm = add_monitor(rect); char *name = (char *)xcb_randr_get_output_info_name(info); size_t name_len = MIN(sizeof(mm->name), (size_t)xcb_randr_get_output_info_name_length(info) + 1); snprintf(mm->name, name_len, "%s", name); mm->id = outputs[i]; PRINTF("add monitor %s (0x%X)\n", mm->name, mm->id); } } free(cir); } else if (!remove_disabled_monitor && info->connection != XCB_RANDR_CONNECTION_DISCONNECTED) { m = get_monitor_by_id(outputs[i]); if (m != NULL) m->wired = true; } } free(info); } /* initially focus the primary monitor and add the first desktop to it */ xcb_randr_get_output_primary_reply_t *gpo = xcb_randr_get_output_primary_reply(dpy, xcb_randr_get_output_primary(dpy, root), NULL); if (gpo != NULL) { pri_mon = get_monitor_by_id(gpo->output); if (!running && pri_mon != NULL) { if (mon != pri_mon) mon = pri_mon; add_desktop(pri_mon, make_desktop(NULL)); ewmh_update_current_desktop(); } } free(gpo); /* handle overlapping monitors */ m = mon_head; while (m != NULL) { monitor_t *next = m->next; if (m->wired) { for (monitor_t *mb = mon_head; mb != NULL; mb = mb->next) if (mb != m && mb->wired && (m->desk == NULL || mb->desk == NULL) && contains(mb->rectangle, m->rectangle)) { if (mm == m) mm = mb; merge_monitors(m, mb); remove_monitor(m); break; } } m = next; } /* merge and remove disconnected monitors */ m = mon_head; while (m != NULL) { monitor_t *next = m->next; if (!m->wired) { merge_monitors(m, mm); remove_monitor(m); } m = next; } /* add one desktop to each new monitor */ for (m = mon_head; m != NULL; m = m->next) if (m->desk == NULL && (running || pri_mon == NULL || m != pri_mon)) add_desktop(m, make_desktop(NULL)); free(sres); update_motion_recorder(); return (num_monitors > 0); }
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; }
/* @brief Attempts to find secondary displays and updates settings.screen_* data * with the dimensions of the found screens. * * Note: failure is somewhat expected and is handled by simply using the default * xcb screen's dimension parameters. * * @param connection A connection to the Xorg server. * @param screen A screen created by xcb's xcb_setup_roots function. * @return 0 on success and 1 on failure. */ static int32_t get_multiscreen_settings(xcb_connection_t *connection, xcb_screen_t *screen) { /* First check randr. */ const xcb_query_extension_reply_t *extension_reply = xcb_get_extension_data(connection, &xcb_randr_id); if (extension_reply && extension_reply->present) { debug("Found randr support, searching for displays.\n"); /* Find x, y and width, height. */ xcb_randr_get_screen_resources_current_reply_t *randr_reply = xcb_randr_get_screen_resources_current_reply(connection, xcb_randr_get_screen_resources_current(connection, screen->root), NULL); if (!randr_reply) { fprintf(stderr, "Failed to get randr set up.\n"); } else { int32_t num_outputs = xcb_randr_get_screen_resources_current_outputs_length(randr_reply); if (num_outputs < settings.screen) { fprintf(stderr, "Screen selected not found.\n"); /* Default back to the first screen. */ settings.screen = 0; } xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(randr_reply); uint32_t output_index = settings.screen; xcb_randr_get_output_info_reply_t *randr_output = NULL; do { if (randr_output) { free(randr_output); } randr_output = xcb_randr_get_output_info_reply(connection, xcb_randr_get_output_info(connection, outputs[output_index], XCB_CURRENT_TIME), NULL); output_index++; } while ((randr_output->connection != XCB_RANDR_CONNECTION_CONNECTED) && (output_index < num_outputs)); if (randr_output) { xcb_randr_get_crtc_info_reply_t *randr_crtc = xcb_randr_get_crtc_info_reply(connection, xcb_randr_get_crtc_info(connection, randr_output->crtc, XCB_CURRENT_TIME), NULL); if (!randr_crtc) { fprintf(stderr, "Unable to connect to randr crtc\n"); free(randr_output); free(randr_reply); goto xinerama; } settings.screen_width = randr_crtc->width; settings.screen_height = randr_crtc->height; settings.screen_x = randr_crtc->x; settings.screen_y = randr_crtc->y; debug("randr screen initialization successful, x: %u y: %u w: %u h: %u.\n", settings.screen_x, settings.screen_y, settings.screen_width, settings.screen_height); free(randr_crtc); free(randr_output); free(randr_reply); return 0; } free(randr_output); free(randr_reply); } } xinerama: debug("Did not find randr support, attempting xinerama\n"); /* Still here? Let's try xinerama! */ extension_reply = xcb_get_extension_data(connection, &xcb_xinerama_id); if (extension_reply && extension_reply->present) { debug("Found xinerama support, searching for displays.\n"); xcb_xinerama_is_active_reply_t *xinerama_is_active_reply = xcb_xinerama_is_active_reply(connection, xcb_xinerama_is_active(connection), NULL); if (xinerama_is_active_reply && xinerama_is_active_reply->state) { free(xinerama_is_active_reply); /* Find x, y and width, height. */ xcb_xinerama_query_screens_reply_t *screen_reply = xcb_xinerama_query_screens_reply(connection, xcb_xinerama_query_screens_unchecked(connection), NULL); xcb_xinerama_screen_info_iterator_t iter = xcb_xinerama_query_screens_screen_info_iterator(screen_reply); free(screen_reply); if (iter.rem < settings.screen) { fprintf(stderr, "Screen selected not found.\n"); /* Default back to the first screen. */ settings.screen = 0; } /* Jump to the appropriate screen. */ int32_t i = 0; while (i < settings.screen) { xcb_xinerama_screen_info_next(&iter); i++; } settings.screen_width = iter.data->width; settings.screen_height = iter.data->height; settings.screen_x = iter.data->x_org; settings.screen_y = iter.data->y_org; debug("xinerama screen initialization successful, x: %u y: %u w: %u h: %u.\n", settings.screen_x, settings.screen_y, settings.screen_width, settings.screen_height); return 0; } } debug("Multiscreen search failed.\n"); return 1; }
static gboolean _eventd_nd_xcb_randr_check_outputs(EventdNdBackendContext *self) { if ( ( self->follow_focus == EVENTD_ND_XCB_FOLLOW_FOCUS_NONE ) && ( self->outputs == NULL ) ) return FALSE; xcb_randr_get_screen_resources_current_cookie_t rcookie; xcb_randr_get_screen_resources_current_reply_t *ressources; rcookie = xcb_randr_get_screen_resources_current(self->xcb_connection, self->screen->root); if ( ( ressources = xcb_randr_get_screen_resources_current_reply(self->xcb_connection, rcookie, NULL) ) == NULL ) { g_warning("Couldn't get RandR screen ressources"); return FALSE; } xcb_timestamp_t cts; xcb_randr_output_t *randr_outputs; gint i, length; cts = ressources->config_timestamp; length = xcb_randr_get_screen_resources_current_outputs_length(ressources); randr_outputs = xcb_randr_get_screen_resources_current_outputs(ressources); EventdNdXcbRandrOutput outputs[length + 1]; EventdNdXcbRandrOutput *output; output = outputs; for ( i = 0 ; i < length ; ++i ) { xcb_randr_get_output_info_cookie_t ocookie; ocookie = xcb_randr_get_output_info(self->xcb_connection, randr_outputs[i], cts); if ( ( output->output = xcb_randr_get_output_info_reply(self->xcb_connection, ocookie, NULL) ) == NULL ) continue; xcb_randr_get_crtc_info_cookie_t ccookie; ccookie = xcb_randr_get_crtc_info(self->xcb_connection, output->output->crtc, cts); if ( ( output->crtc = xcb_randr_get_crtc_info_reply(self->xcb_connection, ccookie, NULL) ) == NULL ) free(output->output); else ++output; } output->output = NULL; gboolean found; if ( self->follow_focus != EVENTD_ND_XCB_FOLLOW_FOCUS_NONE ) found = _eventd_nd_xcb_randr_check_focused(self, outputs); else found = _eventd_nd_xcb_randr_check_config_outputs(self, outputs); for ( output = outputs ; output->output != NULL ; ++output ) { free(output->crtc); free(output->output); } return found; }
bool ScreenManager::scanRandR(xcb_connection_t *conn) { if (!configureRandR(conn)) { LOG_ERROR("RandR extension not found."); return false; } xcb_randr_get_screen_resources_current_reply_t *res = xcb_randr_get_screen_resources_current_reply(conn, xcb_randr_get_screen_resources_current(conn, _rootWindow), NULL); if (!res) { LOG_ERROR("Failed to retrieve screen resources by RandR."); return false; } int length = xcb_randr_get_screen_resources_current_outputs_length(res); xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(res); std::vector<xcb_randr_get_output_info_cookie_t> cookies; xcb_randr_get_output_info_reply_t *output_info; xcb_randr_get_crtc_info_reply_t *crtc; char *output_name; if (length == 0) { LOG_ERROR("No screen found using RandR."); return false; } else { LOG_INFO("Found %d screen(s).", length); } for (int i = 0; i < length; i++) { cookies.push_back(xcb_randr_get_output_info(conn, outputs[i], res->config_timestamp)); } for (auto iter = cookies.begin(); iter != cookies.end(); ++iter) { output_info = xcb_randr_get_output_info_reply(conn, *iter, NULL); if (output_info == NULL) { continue; } asprintf(&output_name, "%.*s", xcb_randr_get_output_info_name_length(output_info), xcb_randr_get_output_info_name(output_info)); Screen s; s.setName(output_name); free(output_name); if (output_info->crtc == XCB_NONE) { LOG_INFO(" Screen %s is disabled.", s.getName().c_str()); continue; } crtc = xcb_randr_get_crtc_info_reply(conn, xcb_randr_get_crtc_info( conn, output_info->crtc, res->config_timestamp), NULL); if (!crtc) { LOG_ERROR("Failed to retrieve CRTC on screen %s.", s.getName().c_str()); return 0; } s.setX(crtc->x); s.setY(crtc->y); s.setWidth(crtc->width); s.setHeight(crtc->height); updateScreen(s); free(crtc); free(output_info); } free(res); return true; }
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; }
static void add_screen(xcb_randr_get_screen_info_reply_t *reply) { const gchar *title = "Display"; GtkWidget *item = gtk_menu_item_new_with_label(title); GtkMenuShell *menu = GTK_MENU_SHELL(app_menu); struct screen_info *info = g_malloc(sizeof *info); xcb_randr_rotation_t rotation = normalize_rotation(reply->rotation); xcb_randr_rotation_t rotations = reply->rotations; info->label_menu_item = item; info->rotation_menu_group = NULL; info->rotation = rotation; info->config_timestamp = reply->config_timestamp; info->root = reply->root; info->sizeID = reply->sizeID; info->rate = reply->rate; screens_info = g_slist_append(screens_info, info); gtk_widget_set_sensitive(item, FALSE); gtk_menu_shell_append(menu, item); #define R(rot, title) \ if (rotations & XCB_RANDR_ROTATION_##rot) \ add_screen_rotation(info, XCB_RANDR_ROTATION_##rot, title, \ XCB_RANDR_ROTATION_##rot & rotation) R(ROTATE_0, "Landscape"); R(ROTATE_90, "Portrait"); R(ROTATE_180, "Landscape Flipped"); R(ROTATE_270, "Portrait Flipped"); if (rotations & xcb_rotations_mask && rotations & xcb_reflections_mask) gtk_menu_shell_append(menu, gtk_separator_menu_item_new()); R(REFLECT_X, "Reflected X"); R(REFLECT_Y, "Reflected Y"); #undef R gtk_menu_shell_append(menu, gtk_separator_menu_item_new()); gtk_widget_show_all(app_menu); /* Get screen resources */ xcb_randr_get_screen_resources_current_cookie_t resources_cookie; xcb_randr_get_screen_resources_current_reply_t *resources_reply; xcb_generic_error_t *err = NULL; resources_cookie = xcb_randr_get_screen_resources_current(conn, info->root); resources_reply = xcb_randr_get_screen_resources_current_reply(conn, resources_cookie, &err); if (err) { g_warning("Get Screen Resources returned error %u\n", err->error_code); return; } /* Get screen outputs */ xcb_randr_output_t *outputs; guint i; gchar *output_name; outputs = xcb_randr_get_screen_resources_current_outputs(resources_reply); for (i = 0; i < resources_reply->num_outputs; i++) { xcb_randr_get_output_info_reply_t *output_info_reply; xcb_randr_get_output_info_cookie_t output_info_cookie = xcb_randr_get_output_info_unchecked(conn, outputs[i], resources_reply->config_timestamp); output_info_reply = xcb_randr_get_output_info_reply(conn, output_info_cookie, NULL); /* Show only if connected */ switch (output_info_reply->connection) { case XCB_RANDR_CONNECTION_DISCONNECTED: case XCB_RANDR_CONNECTION_UNKNOWN: continue; case XCB_RANDR_CONNECTION_CONNECTED: break; } output_name = get_output_name(output_info_reply); /* Put output names on the menu */ gtk_menu_item_set_label(GTK_MENU_ITEM(item), output_name); g_free(output_name); /* TODO: concatenate multiple names or pick them intelligently */ } }