X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Frandr.c;h=1d3330145dfb7fe62c1d3db041fa9514614214cd;hb=aa0b1f599f25cfe858ebbc7fa80d459bcdb2ae02;hp=8496fd0338a935b5b32e06ba54773a18ce343f2a;hpb=f99727b518968659ca71750a8d19ee5dbca483e3;p=i3%2Fi3 diff --git a/src/randr.c b/src/randr.c index 8496fd03..1d333014 100644 --- a/src/randr.c +++ b/src/randr.c @@ -5,7 +5,7 @@ * © 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 + * https://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt * (take your time to read it completely, it answers all questions). * */ @@ -40,17 +40,26 @@ static Output *get_output_by_id(xcb_randr_output_t id) { } /* - * Returns the output with the given name if it is active (!) or NULL. + * Returns the output with the given name or NULL. + * If require_active is true, only active outputs are considered. * */ -Output *get_output_by_name(const char *name) { +Output *get_output_by_name(const char *name, const bool require_active) { Output *output; bool get_primary = (strcasecmp("primary", name) == 0); TAILQ_FOREACH(output, &outputs, outputs) { - if ((output->primary && get_primary) || - (output->active && strcasecmp(output->name, name) == 0)) { + if (output->primary && get_primary) { return output; } + if (require_active && !output->active) { + continue; + } + struct output_name *output_name; + SLIST_FOREACH(output_name, &output->names_head, names) { + if (strcasecmp(output_name->name, name) == 0) { + return output; + } + } } return NULL; @@ -177,7 +186,7 @@ Output *get_output_next_wrap(direction_t direction, Output *current) { } if (!best) best = current; - DLOG("current = %s, best = %s\n", current->name, best->name); + DLOG("current = %s, best = %s\n", output_primary_name(current), output_primary_name(best)); return best; } @@ -249,7 +258,7 @@ Output *get_output_next(direction_t direction, Output *current, output_close_far } } - DLOG("current = %s, best = %s\n", current->name, (best ? best->name : "NULL")); + DLOG("current = %s, best = %s\n", output_primary_name(current), (best ? output_primary_name(best) : "NULL")); return best; } @@ -265,7 +274,11 @@ Output *create_root_output(xcb_connection_t *conn) { s->rect.y = 0; s->rect.width = root_screen->width_in_pixels; s->rect.height = root_screen->height_in_pixels; - s->name = "xroot-0"; + + struct output_name *output_name = scalloc(1, sizeof(struct output_name)); + output_name->name = "xroot-0"; + SLIST_INIT(&s->names_head); + SLIST_INSERT_HEAD(&s->names_head, output_name, names); return s; } @@ -279,12 +292,12 @@ void output_init_con(Output *output) { Con *con = NULL, *current; bool reused = false; - DLOG("init_con for output %s\n", output->name); + DLOG("init_con for output %s\n", output_primary_name(output)); /* Search for a Con with that name directly below the root node. There * might be one from a restored layout. */ TAILQ_FOREACH(current, &(croot->nodes_head), nodes) { - if (strcmp(current->name, output->name) != 0) + if (strcmp(current->name, output_primary_name(output)) != 0) continue; con = current; @@ -296,7 +309,7 @@ void output_init_con(Output *output) { if (con == NULL) { con = con_new(croot, NULL); FREE(con->name); - con->name = sstrdup(output->name); + con->name = sstrdup(output_primary_name(output)); con->type = CT_OUTPUT; con->layout = L_OUTPUT; con_fix_percent(croot); @@ -367,6 +380,10 @@ void output_init_con(Output *output) { FREE(name); DLOG("attaching\n"); con_attach(bottomdock, con, false); + + /* Change focus to the content container */ + TAILQ_REMOVE(&(con->focus_head), content, focused); + TAILQ_INSERT_HEAD(&(con->focus_head), content, focused); } /* @@ -383,7 +400,7 @@ void init_ws_for_output(Output *output, Con *content) { /* go through all assignments and move the existing workspaces to this output */ struct Workspace_Assignment *assignment; TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) { - if (strcmp(assignment->output, output->name) != 0) + if (strcmp(assignment->output, output_primary_name(output)) != 0) continue; /* check if this workspace actually exists */ @@ -401,13 +418,13 @@ void init_ws_for_output(Output *output, Con *content) { LOG("Workspace \"%s\" assigned to output \"%s\", but it is already " "there. Do you have two assignment directives for the same " "workspace in your configuration file?\n", - workspace->name, output->name); + workspace->name, output_primary_name(output)); continue; } /* if so, move it over */ LOG("Moving workspace \"%s\" from output \"%s\" to \"%s\" due to assignment\n", - workspace->name, workspace_out->name, output->name); + workspace->name, workspace_out->name, output_primary_name(output)); /* if the workspace is currently visible on that output, we need to * switch to a different workspace - otherwise the output would end up @@ -442,9 +459,9 @@ void init_ws_for_output(Output *output, Con *content) { if (visible && previous == NULL) { LOG("There is no workspace left on \"%s\", re-initializing\n", workspace_out->name); - init_ws_for_output(get_output_by_name(workspace_out->name), + init_ws_for_output(get_output_by_name(workspace_out->name, true), output_get_content(workspace_out)); - DLOG("Done re-initializing, continuing with \"%s\"\n", output->name); + DLOG("Done re-initializing, continuing with \"%s\"\n", output_primary_name(output)); } } @@ -464,7 +481,7 @@ void init_ws_for_output(Output *output, Con *content) { /* otherwise, we create the first assigned ws for this output */ TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) { - if (strcmp(assignment->output, output->name) != 0) + if (strcmp(assignment->output, output_primary_name(output)) != 0) continue; LOG("Initializing first assigned workspace \"%s\" for output \"%s\"\n", @@ -590,10 +607,45 @@ static bool randr_query_outputs_15(void) { xcb_get_atom_name_name(atom_reply)); free(atom_reply); - Output *new = get_output_by_name(name); + Output *new = get_output_by_name(name, false); if (new == NULL) { new = scalloc(1, sizeof(Output)); - new->name = sstrdup(name); + + SLIST_INIT(&new->names_head); + + /* Register associated output names in addition to the monitor name */ + xcb_randr_output_t *randr_outputs = xcb_randr_monitor_info_outputs(monitor_info); + int randr_output_len = xcb_randr_monitor_info_outputs_length(monitor_info); + for (int i = 0; i < randr_output_len; i++) { + xcb_randr_output_t randr_output = randr_outputs[i]; + + xcb_randr_get_output_info_reply_t *info = + xcb_randr_get_output_info_reply(conn, + xcb_randr_get_output_info(conn, randr_output, monitors->timestamp), + NULL); + + if (info != NULL && info->crtc != XCB_NONE) { + char *oname; + sasprintf(&oname, "%.*s", + xcb_randr_get_output_info_name_length(info), + xcb_randr_get_output_info_name(info)); + + if (strcmp(name, oname) != 0) { + struct output_name *output_name = scalloc(1, sizeof(struct output_name)); + output_name->name = sstrdup(oname); + SLIST_INSERT_HEAD(&new->names_head, output_name, names); + } else { + free(oname); + } + } + FREE(info); + } + + /* Insert the monitor name last, so that it's used as the primary name */ + struct output_name *output_name = scalloc(1, sizeof(struct output_name)); + output_name->name = sstrdup(name); + SLIST_INSERT_HEAD(&new->names_head, output_name, names); + if (monitor_info->primary) { TAILQ_INSERT_HEAD(&outputs, new, outputs); } else { @@ -642,16 +694,25 @@ 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) + if (!existing) { new = scalloc(1, sizeof(Output)); + SLIST_INIT(&new->names_head); + } new->id = id; new->primary = (primary && primary->output == id); - FREE(new->name); - sasprintf(&new->name, "%.*s", + while (!SLIST_EMPTY(&new->names_head)) { + FREE(SLIST_FIRST(&new->names_head)->name); + struct output_name *old_head = SLIST_FIRST(&new->names_head); + SLIST_REMOVE_HEAD(&new->names_head, names); + FREE(old_head); + } + struct output_name *output_name = scalloc(1, sizeof(struct output_name)); + sasprintf(&output_name->name, "%.*s", xcb_randr_get_output_info_name_length(output), xcb_randr_get_output_info_name(output)); + SLIST_INSERT_HEAD(&new->names_head, output_name, names); - DLOG("found output with name %s\n", new->name); + DLOG("found output with name %s\n", output_primary_name(new)); /* Even if no CRTC is used at the moment, we store the output so that * we do not need to change the list ever again (we only update the @@ -671,7 +732,7 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, icookie = xcb_randr_get_crtc_info(conn, output->crtc, cts); if ((crtc = xcb_randr_get_crtc_info_reply(conn, icookie, NULL)) == NULL) { DLOG("Skipping output %s: could not get CRTC (%p)\n", - new->name, crtc); + output_primary_name(new), crtc); free(new); return; } @@ -788,7 +849,7 @@ void randr_query_outputs(void) { 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_primary_name(output), output->rect.x, output->rect.y); for (other = output; other != TAILQ_END(&outputs); @@ -812,7 +873,7 @@ void randr_query_outputs(void) { update_if_necessary(&(other->rect.width), width); update_if_necessary(&(other->rect.height), height); - DLOG("disabling output %p (%s)\n", other, other->name); + DLOG("disabling output %p (%s)\n", other, output_primary_name(other)); other->to_be_disabled = true; DLOG("new output mode %d x %d, other mode %d x %d\n", @@ -827,7 +888,7 @@ void randr_query_outputs(void) { * LVDS1 gets disabled. */ TAILQ_FOREACH(output, &outputs, outputs) { if (output->active && output->con == NULL) { - DLOG("Need to initialize a Con for output %s\n", output->name); + DLOG("Need to initialize a Con for output %s\n", output_primary_name(output)); output_init_con(output); output->changed = false; } @@ -853,7 +914,7 @@ void randr_query_outputs(void) { Con *content = output_get_content(output->con); if (!TAILQ_EMPTY(&(content->nodes_head))) continue; - DLOG("Should add ws for output %s\n", output->name); + DLOG("Should add ws for output %s\n", output_primary_name(output)); init_ws_for_output(output, content); } @@ -862,7 +923,7 @@ void randr_query_outputs(void) { if (!output->primary || !output->con) continue; - DLOG("Focusing primary output %s\n", output->name); + DLOG("Focusing primary output %s\n", output_primary_name(output)); con_focus(con_descend_focused(output->con)); } @@ -880,7 +941,7 @@ void randr_disable_output(Output *output) { assert(output->to_be_disabled); output->active = false; - DLOG("Output %s disabled, re-assigning workspaces/docks\n", output->name); + DLOG("Output %s disabled, re-assigning workspaces/docks\n", output_primary_name(output)); Output *first = get_first_output(); @@ -991,8 +1052,8 @@ void randr_init(int *event_base, const bool disable_randr15) { xcb_randr_query_version_reply( conn, xcb_randr_query_version(conn, XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION), &err); if (err != NULL) { - free(err); ELOG("Could not query RandR version: X11 error code %d\n", err->error_code); + free(err); fallback_to_root_output(); return; }