X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Frandr.c;h=23dd98d55c35f2e27a92aef32e03dc6587164349;hb=78decb565a465e1b07ab89a3e6b077a5fe49cf58;hp=53a9a1777d8f45d391187e19c0668c16bb24e058;hpb=c23db20cb56847305bd8b6b362b8623e9e81db69;p=i3%2Fi3 diff --git a/src/randr.c b/src/randr.c index 53a9a177..23dd98d5 100644 --- a/src/randr.c +++ b/src/randr.c @@ -4,7 +4,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) * * For more information on RandR, please see the X.org RandR specification at * http://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt @@ -27,7 +27,8 @@ xcb_randr_get_output_primary_reply_t *primary; /* Stores all outputs available in your current session. */ struct outputs_head outputs = TAILQ_HEAD_INITIALIZER(outputs); -static bool randr_disabled = false; +/* This is the output covering the root window */ +static Output *root_output; /* * Get a specific output by its internal X11 id. Used by randr_query_outputs @@ -38,8 +39,8 @@ static bool randr_disabled = false; static Output *get_output_by_id(xcb_randr_output_t id) { Output *output; TAILQ_FOREACH(output, &outputs, outputs) - if (output->id == id) - return output; + if (output->id == id) + return output; return NULL; } @@ -51,9 +52,9 @@ static Output *get_output_by_id(xcb_randr_output_t id) { Output *get_output_by_name(const char *name) { Output *output; TAILQ_FOREACH(output, &outputs, outputs) - if (output->active && - strcasecmp(output->name, name) == 0) - return output; + if (output->active && + strcasecmp(output->name, name) == 0) + return output; return NULL; } @@ -66,12 +67,27 @@ Output *get_first_output(void) { Output *output; TAILQ_FOREACH(output, &outputs, outputs) - if (output->active) - return output; + if (output->active) + return output; die("No usable outputs available.\n"); } +/* + * Check whether there are any active outputs (excluding the root output). + * + */ +static bool any_randr_output_active(void) { + Output *output; + + TAILQ_FOREACH(output, &outputs, outputs) { + if (output != root_output && !output->to_be_disabled && output->active) + return true; + } + + return false; +} + /* * Returns the active (!) output which contains the coordinates x, y or NULL * if there is no output which contains these coordinates. @@ -83,7 +99,7 @@ Output *get_output_containing(unsigned int x, unsigned int y) { if (!output->active) continue; DLOG("comparing x=%d y=%d with x=%d and y=%d width %d height %d\n", - x, y, output->rect.x, output->rect.y, output->rect.width, output->rect.height); + x, y, output->rect.x, output->rect.y, output->rect.width, output->rect.height); if (x >= output->rect.x && x < (output->rect.x + output->rect.width) && y >= output->rect.y && y < (output->rect.y + output->rect.height)) return output; @@ -100,7 +116,7 @@ Output *get_output_containing(unsigned int x, unsigned int y) { * be many), we just return true or false for convenience. * */ -bool contained_by_output(Rect rect){ +bool contained_by_output(Rect rect) { Output *output; int lx = rect.x, uy = rect.y; int rx = rect.x + rect.width, by = rect.y + rect.height; @@ -108,13 +124,12 @@ bool contained_by_output(Rect rect){ if (!output->active) continue; DLOG("comparing x=%d y=%d with x=%d and y=%d width %d height %d\n", - rect.x, rect.y, output->rect.x, output->rect.y, output->rect.width, output->rect.height); + rect.x, rect.y, output->rect.x, output->rect.y, output->rect.width, output->rect.height); if (rx >= (int)output->rect.x && lx <= (int)(output->rect.x + output->rect.width) && by >= (int)output->rect.y && uy <= (int)(output->rect.y + output->rect.height)) return true; } return false; - } /* @@ -163,7 +178,7 @@ Output *get_output_next(direction_t direction, Output *current, output_close_far Rect *cur = &(current->rect), *other; Output *output, - *best = NULL; + *best = NULL; TAILQ_FOREACH(output, &outputs, outputs) { if (!output->active) continue; @@ -171,18 +186,18 @@ Output *get_output_next(direction_t direction, Output *current, output_close_far other = &(output->rect); if ((direction == D_RIGHT && other->x > cur->x) || - (direction == D_LEFT && other->x < cur->x)) { + (direction == D_LEFT && other->x < cur->x)) { /* Skip the output when it doesn’t overlap the other one’s y * coordinate at all. */ if ((other->y + other->height) <= cur->y || - (cur->y + cur->height) <= other->y) + (cur->y + cur->height) <= other->y) continue; } else if ((direction == D_DOWN && other->y > cur->y) || - (direction == D_UP && other->y < cur->y)) { + (direction == D_UP && other->y < cur->y)) { /* Skip the output when it doesn’t overlap the other one’s x * coordinate at all. */ if ((other->x + other->width) <= cur->x || - (cur->x + cur->width) <= other->x) + (cur->x + cur->width) <= other->x) continue; } else continue; @@ -197,9 +212,9 @@ Output *get_output_next(direction_t direction, Output *current, output_close_far /* Is this output better (closer to the current output) than our * current best bet? */ if ((direction == D_RIGHT && other->x < best->rect.x) || - (direction == D_LEFT && other->x > best->rect.x) || - (direction == D_DOWN && other->y < best->rect.y) || - (direction == D_UP && other->y > best->rect.y)) { + (direction == D_LEFT && other->x > best->rect.x) || + (direction == D_DOWN && other->y < best->rect.y) || + (direction == D_UP && other->y > best->rect.y)) { best = output; continue; } @@ -207,9 +222,9 @@ Output *get_output_next(direction_t direction, Output *current, output_close_far /* Is this output better (farther to the current output) than our * current best bet? */ if ((direction == D_RIGHT && other->x > best->rect.x) || - (direction == D_LEFT && other->x < best->rect.x) || - (direction == D_DOWN && other->y > best->rect.y) || - (direction == D_UP && other->y < best->rect.y)) { + (direction == D_LEFT && other->x < best->rect.x) || + (direction == D_DOWN && other->y > best->rect.y) || + (direction == D_UP && other->y < best->rect.y)) { best = output; continue; } @@ -221,27 +236,22 @@ Output *get_output_next(direction_t direction, Output *current, output_close_far } /* - * Disables RandR support by creating exactly one output with the size of the - * X11 screen. + * Creates an output covering the root window. * */ -void disable_randr(xcb_connection_t *conn) { - DLOG("RandR extension unusable, disabling.\n"); - - Output *s = scalloc(sizeof(Output)); - - s->active = true; - s->rect.x = 0; - s->rect.y = 0; - s->rect.width = root_screen->width_in_pixels; - s->rect.height = root_screen->height_in_pixels; - s->name = "xroot-0"; - output_init_con(s); - init_ws_for_output(s, output_get_content(s->con)); - - TAILQ_INSERT_TAIL(&outputs, s, outputs); - - randr_disabled = true; +void create_root_output(xcb_connection_t *conn) { + root_output = scalloc(1, sizeof(Output)); + + root_output->active = true; + root_output->rect.x = 0; + root_output->rect.y = 0; + root_output->rect.width = root_screen->width_in_pixels; + root_output->rect.height = root_screen->height_in_pixels; + root_output->name = "xroot-0"; + output_init_con(root_output); + init_ws_for_output(root_output, output_get_content(root_output->con)); + + TAILQ_INSERT_TAIL(&outputs, root_output, outputs); } /* @@ -293,7 +303,7 @@ void output_init_con(Output *output) { topdock->type = CT_DOCKAREA; topdock->layout = L_DOCKAREA; /* this container swallows dock clients */ - Match *match = scalloc(sizeof(Match)); + Match *match = scalloc(1, sizeof(Match)); match_init(match); match->dock = M_DOCK_TOP; match->insert_where = M_BELOW; @@ -327,7 +337,7 @@ void output_init_con(Output *output) { bottomdock->type = CT_DOCKAREA; bottomdock->layout = L_DOCKAREA; /* this container swallows dock clients */ - match = scalloc(sizeof(Match)); + match = scalloc(1, sizeof(Match)); match_init(match); match->dock = M_DOCK_BOTTOM; match->insert_where = M_BELOW; @@ -363,8 +373,8 @@ void init_ws_for_output(Output *output, Con *content) { /* check if this workspace actually exists */ Con *workspace = NULL, *out; TAILQ_FOREACH(out, &(croot->nodes_head), nodes) - GREP_FIRST(workspace, output_get_content(out), - !strcasecmp(child->name, assignment->name)); + GREP_FIRST(workspace, output_get_content(out), + !strcasecmp(child->name, assignment->name)); if (workspace == NULL) continue; @@ -403,9 +413,9 @@ void init_ws_for_output(Output *output, Con *content) { Con *floating_con; TAILQ_FOREACH(floating_con, &(workspace->floating_head), floating_windows) - /* NB: We use output->con here because content is not yet rendered, + /* NB: We use output->con here because content is not yet rendered, * so it has a rect of {0, 0, 0, 0}. */ - floating_fix_coordinates(floating_con, &(ws_out_content->rect), &(output->con->rect)); + floating_fix_coordinates(floating_con, &(ws_out_content->rect), &(output->con->rect)); con_detach(workspace); con_attach(workspace, content, false); @@ -523,13 +533,13 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, Output *new = get_output_by_id(id); bool existing = (new != NULL); if (!existing) - new = scalloc(sizeof(Output)); + new = scalloc(1, sizeof(Output)); new->id = id; new->primary = (primary && primary->output == id); FREE(new->name); sasprintf(&new->name, "%.*s", - xcb_randr_get_output_info_name_length(output), - xcb_randr_get_output_info_name(output)); + xcb_randr_get_output_info_name_length(output), + xcb_randr_get_output_info_name(output)); DLOG("found output with name %s\n", new->name); @@ -540,7 +550,8 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, if (!existing) { if (new->primary) TAILQ_INSERT_HEAD(&outputs, new, outputs); - else TAILQ_INSERT_TAIL(&outputs, new, outputs); + else + TAILQ_INSERT_TAIL(&outputs, new, outputs); } else if (new->active) new->to_be_disabled = true; return; @@ -567,7 +578,7 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, } DLOG("mode: %dx%d+%d+%d\n", new->rect.width, new->rect.height, - new->rect.x, new->rect.y); + new->rect.x, new->rect.y); /* If we don’t need to change an existing output or if the output * does not exist in the first place, the case is simple: we either @@ -576,7 +587,8 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, if (!existing) { if (new->primary) TAILQ_INSERT_HEAD(&outputs, new, outputs); - else TAILQ_INSERT_TAIL(&outputs, new, outputs); + else + TAILQ_INSERT_TAIL(&outputs, new, outputs); } return; } @@ -587,6 +599,8 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, /* * (Re-)queries the outputs via RandR and stores them in the list of outputs. * + * If no outputs are found use the root window. + * */ void randr_query_outputs(void) { Output *output, *other, *first; @@ -601,20 +615,17 @@ void randr_query_outputs(void) { /* an output is VGA-1, LVDS-1, etc. (usually physical video outputs) */ xcb_randr_output_t *randr_outputs; - if (randr_disabled) - return; - /* Get screen resources (primary output, crtcs, outputs, modes) */ rcookie = xcb_randr_get_screen_resources_current(conn, root); pcookie = xcb_randr_get_output_primary(conn, root); if ((primary = xcb_randr_get_output_primary_reply(conn, pcookie, NULL)) == NULL) ELOG("Could not get RandR primary output\n"); - else DLOG("primary output is %08x\n", primary->output); - if ((res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL)) == NULL) { - disable_randr(conn); + else + DLOG("primary output is %08x\n", primary->output); + if ((res = xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL)) == NULL) return; - } + cts = res->config_timestamp; int len = xcb_randr_get_screen_resources_current_outputs_length(res); @@ -636,13 +647,23 @@ void randr_query_outputs(void) { free(output); } + /* If there's no randr output, enable the output covering the root window. */ + if (any_randr_output_active()) { + DLOG("Active RandR output found. Disabling root output.\n"); + if (root_output->active) + root_output->to_be_disabled = true; + } else { + DLOG("No active RandR output found. Enabling root output.\n"); + root_output->active = true; + } + /* Check for clones, disable the clones and reduce the mode to the * lowest common mode */ TAILQ_FOREACH(output, &outputs, outputs) { if (!output->active || output->to_be_disabled) continue; DLOG("output %p / %s, position (%d, %d), checking for clones\n", - output, output->name, output->rect.x, output->rect.y); + output, output->name, output->rect.x, output->rect.y); for (other = output; other != TAILQ_END(&outputs); @@ -655,7 +676,7 @@ void randr_query_outputs(void) { continue; DLOG("output %p has the same position, his mode = %d x %d\n", - other, other->rect.width, other->rect.height); + other, other->rect.width, other->rect.height); uint32_t width = min(other->rect.width, output->rect.width); uint32_t height = min(other->rect.height, output->rect.height); @@ -670,8 +691,8 @@ void randr_query_outputs(void) { other->to_be_disabled = true; DLOG("new output mode %d x %d, other mode %d x %d\n", - output->rect.width, output->rect.height, - other->rect.width, other->rect.height); + output->rect.width, output->rect.height, + other->rect.width, other->rect.height); } } @@ -730,7 +751,7 @@ void randr_query_outputs(void) { DLOG("Fixing the coordinates of floating containers\n"); Con *floating_con; TAILQ_FOREACH(floating_con, &(current->floating_head), floating_windows) - floating_fix_coordinates(floating_con, &(output->con->rect), &(first->con->rect)); + floating_fix_coordinates(floating_con, &(output->con->rect), &(first->con->rect)); DLOG("Done, next\n"); } DLOG("re-attached all workspaces\n"); @@ -777,14 +798,6 @@ void randr_query_outputs(void) { } } - if (TAILQ_EMPTY(&outputs)) { - ELOG("No outputs found via RandR, disabling\n"); - disable_randr(conn); - } - - /* Verifies that there is at least one active output as a side-effect. */ - get_first_output(); - /* Just go through each active output and assign one workspace */ TAILQ_FOREACH(output, &outputs, outputs) { if (!output->active) @@ -820,20 +833,22 @@ void randr_query_outputs(void) { void randr_init(int *event_base) { const xcb_query_extension_reply_t *extreply; + create_root_output(conn); + extreply = xcb_get_extension_data(conn, &xcb_randr_id); - if (!extreply->present) { - disable_randr(conn); + if (!extreply->present) return; - } else randr_query_outputs(); + + randr_query_outputs(); if (event_base != NULL) *event_base = extreply->first_event; xcb_randr_select_input(conn, root, - XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE | - XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE | - XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE | - XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY); + XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE | + XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE | + XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE | + XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY); xcb_flush(conn); }