X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Frandr.c;h=e117547313d801a8736425e236f4828d468763aa;hb=0e752070ac2bed02d0858bbc450ddcee36e3b9b5;hp=dd30925b9301c654132105bda8a23f325e452203;hpb=717ae819c55d2aca9f4bf2e1198e035ca64114ac;p=i3%2Fi3 diff --git a/src/randr.c b/src/randr.c index dd30925b..e1175473 100644 --- a/src/randr.c +++ b/src/randr.c @@ -1,27 +1,23 @@ +#line 2 "randr.c" /* * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * - * © 2009-2011 Michael Stapelberg and contributors - * - * See file LICENSE for license information. + * © 2009-2012 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 * (take your time to read it completely, it answers all questions). * */ -#include +#include "all.h" +#include #include -#include "all.h" - /* While a clean namespace is usually a pretty good thing, we really need * to use shorter names than the whole xcb_randr_* default names. */ typedef xcb_randr_get_crtc_info_reply_t crtc_info; -typedef xcb_randr_mode_info_t mode_info; typedef xcb_randr_get_screen_resources_current_reply_t resources_reply; /* Pointer to the result of the query for primary output */ @@ -65,7 +61,7 @@ Output *get_output_by_name(const char *name) { * Returns the first output which is active. * */ -Output *get_first_output() { +Output *get_first_output(void) { Output *output; TAILQ_FOREACH(output, &outputs, outputs) @@ -248,7 +244,7 @@ void output_init_con(Output *output) { output->con = con; char *name; - asprintf(&name, "[i3 con] output %s", con->name); + sasprintf(&name, "[i3 con] output %s", con->name); x_set_name(con, name); FREE(name); @@ -261,7 +257,6 @@ void output_init_con(Output *output) { Con *topdock = con_new(NULL, NULL); topdock->type = CT_DOCKAREA; topdock->layout = L_DOCKAREA; - topdock->orientation = VERT; /* this container swallows dock clients */ Match *match = scalloc(sizeof(Match)); match_init(match); @@ -272,7 +267,7 @@ void output_init_con(Output *output) { FREE(topdock->name); topdock->name = sstrdup("topdock"); - asprintf(&name, "[i3 con] top dockarea %s", con->name); + sasprintf(&name, "[i3 con] top dockarea %s", con->name); x_set_name(topdock, name); FREE(name); DLOG("attaching\n"); @@ -283,10 +278,11 @@ void output_init_con(Output *output) { DLOG("adding main content container\n"); Con *content = con_new(NULL, NULL); content->type = CT_CON; + content->layout = L_SPLITH; FREE(content->name); content->name = sstrdup("content"); - asprintf(&name, "[i3 con] content %s", con->name); + sasprintf(&name, "[i3 con] content %s", con->name); x_set_name(content, name); FREE(name); con_attach(content, con, false); @@ -295,7 +291,6 @@ void output_init_con(Output *output) { Con *bottomdock = con_new(NULL, NULL); bottomdock->type = CT_DOCKAREA; bottomdock->layout = L_DOCKAREA; - bottomdock->orientation = VERT; /* this container swallows dock clients */ match = scalloc(sizeof(Match)); match_init(match); @@ -306,7 +301,7 @@ void output_init_con(Output *output) { FREE(bottomdock->name); bottomdock->name = sstrdup("bottomdock"); - asprintf(&name, "[i3 con] bottom dockarea %s", con->name); + sasprintf(&name, "[i3 con] bottom dockarea %s", con->name); x_set_name(bottomdock, name); FREE(name); DLOG("attaching\n"); @@ -324,8 +319,6 @@ void output_init_con(Output *output) { * */ void init_ws_for_output(Output *output, Con *content) { - char *name; - /* go through all assignments and move the existing workspaces to this output */ struct Workspace_Assignment *assignment; TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) { @@ -363,9 +356,22 @@ void init_ws_for_output(Output *output, Con *content) { if (visible && (previous = TAILQ_NEXT(workspace, focused))) { LOG("Switching to previously used workspace \"%s\" on output \"%s\"\n", previous->name, workspace_out->name); - workspace_show(previous->name); + workspace_show(previous); } + /* Render the output on which the workspace was to get correct Rects. + * Then, we need to work with the "content" container, since we cannot + * be sure that the workspace itself was rendered at all (in case it’s + * invisible, it won’t be rendered). */ + render_con(workspace_out, false); + Con *ws_out_content = output_get_content(workspace_out); + + Con *floating_con; + TAILQ_FOREACH(floating_con, &(workspace->floating_head), floating_windows) + /* 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)); + con_detach(workspace); con_attach(workspace, content, false); @@ -390,7 +396,7 @@ void init_ws_for_output(Output *output, Con *content) { if (!visible) { visible = TAILQ_FIRST(&(content->nodes_head)); focused = content; - workspace_show(visible->name); + workspace_show(visible); } return; } @@ -403,101 +409,13 @@ void init_ws_for_output(Output *output, Con *content) { LOG("Initializing first assigned workspace \"%s\" for output \"%s\"\n", assignment->name, assignment->output); focused = content; - workspace_show(assignment->name); + workspace_show_by_name(assignment->name); return; } /* if there is still no workspace, we create the first free workspace */ DLOG("Now adding a workspace\n"); - - /* add a workspace to this output */ - Con *out, *current; - bool exists = true; - Con *ws = con_new(NULL, NULL); - ws->type = CT_WORKSPACE; - - /* try the configured workspace bindings first to find a free name */ - Binding *bind; - TAILQ_FOREACH(bind, bindings, bindings) { - DLOG("binding with command %s\n", bind->command); - if (strlen(bind->command) < strlen("workspace ") || - strncasecmp(bind->command, "workspace", strlen("workspace")) != 0) - continue; - DLOG("relevant command = %s\n", bind->command); - char *target = bind->command + strlen("workspace "); - /* We check if this is the workspace next/prev command. Beware: The - * workspace names "next" and "prev" are OK, so we check before - * stripping the double quotes */ - if (strncasecmp(target, "next", strlen("next")) == 0 || - strncasecmp(target, "prev", strlen("prev")) == 0) - continue; - if (*target == '"') - target++; - FREE(ws->name); - ws->name = strdup(target); - if (ws->name[strlen(ws->name)-1] == '"') - ws->name[strlen(ws->name)-1] = '\0'; - DLOG("trying name *%s*\n", ws->name); - - current = NULL; - TAILQ_FOREACH(out, &(croot->nodes_head), nodes) - GREP_FIRST(current, output_get_content(out), !strcasecmp(child->name, ws->name)); - - exists = (current != NULL); - if (!exists) { - /* Set ->num to the number of the workspace, if the name actually - * is a number or starts with a number */ - char *endptr = NULL; - long parsed_num = strtol(ws->name, &endptr, 10); - if (parsed_num == LONG_MIN || - parsed_num == LONG_MAX || - parsed_num < 0 || - endptr == ws->name) - ws->num = -1; - else ws->num = parsed_num; - LOG("Used number %d for workspace with name %s\n", ws->num, ws->name); - - break; - } - } - - if (exists) { - /* get the next unused workspace number */ - DLOG("Getting next unused workspace by number\n"); - int c = 0; - while (exists) { - c++; - - FREE(ws->name); - asprintf(&(ws->name), "%d", c); - - current = NULL; - TAILQ_FOREACH(out, &(croot->nodes_head), nodes) - GREP_FIRST(current, output_get_content(out), !strcasecmp(child->name, ws->name)); - exists = (current != NULL); - - DLOG("result for ws %s / %d: exists = %d\n", ws->name, c, exists); - } - ws->num = c; - } - con_attach(ws, content, false); - - asprintf(&name, "[i3 con] workspace %s", ws->name); - x_set_name(ws, name); - free(name); - - ws->fullscreen_mode = CF_OUTPUT; - - /* If default_orientation is set to NO_ORIENTATION we determine - * orientation depending on output resolution. */ - if (config.default_orientation == NO_ORIENTATION) { - ws->orientation = (output->rect.height > output->rect.width) ? VERT : HORIZ; - DLOG("Auto orientation. Workspace size set to (%d,%d), setting orientation to %d.\n", - output->rect.width, output->rect.height, ws->orientation); - } else { - ws->orientation = config.default_orientation; - } - + Con *ws = create_workspace_on_output(output, content); /* TODO: Set focus in main.c */ con_focus(ws); @@ -515,8 +433,6 @@ void init_ws_for_output(Output *output, Con *content) { * */ static void output_change_mode(xcb_connection_t *conn, Output *output) { - //i3Font *font = load_font(conn, config.font); - DLOG("Output mode changed, updating rect\n"); assert(output->con != NULL); output->con->rect = output->rect; @@ -526,6 +442,14 @@ static void output_change_mode(xcb_connection_t *conn, Output *output) { /* Point content to the container of the workspaces */ content = output_get_content(output->con); + /* Fix the position of all floating windows on this output. + * The 'rect' of each workspace will be updated in src/render.c. */ + TAILQ_FOREACH(workspace, &(content->nodes_head), nodes) { + TAILQ_FOREACH(child, &(workspace->floating_head), floating_windows) { + floating_fix_coordinates(child, &(workspace->rect), &(output->con->rect)); + } + } + /* If default_orientation is NO_ORIENTATION, we change the orientation of * the workspaces and their childs depending on output resolution. This is * only done for workspaces with maximum one child. */ @@ -536,11 +460,11 @@ static void output_change_mode(xcb_connection_t *conn, Output *output) { if (con_num_children(workspace) > 1) continue; - workspace->orientation = (output->rect.height > output->rect.width) ? VERT : HORIZ; - DLOG("Setting workspace [%d,%s]'s orientation to %d.\n", workspace->num, workspace->name, workspace->orientation); + workspace->layout = (output->rect.height > output->rect.width) ? L_SPLITV : L_SPLITH; + DLOG("Setting workspace [%d,%s]'s layout to %d.\n", workspace->num, workspace->name, workspace->layout); if ((child = TAILQ_FIRST(&(workspace->nodes_head)))) { - child->orientation = workspace->orientation; - DLOG("Setting child [%d,%s]'s orientation to %d.\n", child->num, child->name, child->orientation); + child->layout = workspace->layout; + DLOG("Setting child [%d,%s]'s layout to %d.\n", child->num, child->name, child->layout); } } } @@ -567,7 +491,7 @@ static void handle_output(xcb_connection_t *conn, xcb_randr_output_t id, new->id = id; new->primary = (primary && primary->output == id); FREE(new->name); - asprintf(&new->name, "%.*s", + sasprintf(&new->name, "%.*s", xcb_randr_get_output_info_name_length(output), xcb_randr_get_output_info_name(output)); @@ -628,7 +552,7 @@ 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. * */ -void randr_query_outputs() { +void randr_query_outputs(void) { Output *output, *other, *first; xcb_randr_get_output_primary_cookie_t pcookie; xcb_randr_get_screen_resources_current_cookie_t rcookie; @@ -748,19 +672,30 @@ void randr_query_outputs() { Con *next = NULL; if (TAILQ_FIRST(&(croot->focus_head)) == output->con) { DLOG("This output (%p) was focused! Getting next\n", output->con); - next = con_next_focused(output->con); + next = focused; DLOG("next = %p\n", next); } - /* 2: iterate through workspaces and re-assign them */ + /* 2: iterate through workspaces and re-assign them, fixing the coordinates + * of floating containers as we go */ Con *current; Con *old_content = output_get_content(output->con); while (!TAILQ_EMPTY(&(old_content->nodes_head))) { current = TAILQ_FIRST(&(old_content->nodes_head)); + if (current != next && TAILQ_EMPTY(&(current->focus_head))) { + /* the workspace is empty and not focused, get rid of it */ + DLOG("Getting rid of current = %p / %s (empty, unfocused)\n", current, current->name); + tree_close(current, DONT_KILL_WINDOW, false, false); + continue; + } DLOG("Detaching current = %p / %s\n", current, current->name); con_detach(current); DLOG("Re-attaching current = %p / %s\n", current, current->name); con_attach(current, first_content, false); + 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)); DLOG("Done, next\n"); } DLOG("re-attached all workspaces\n"); @@ -768,6 +703,7 @@ void randr_query_outputs() { if (next) { DLOG("now focusing next = %p\n", next); con_focus(next); + workspace_show(con_get_workspace(next)); } /* 3: move the dock clients to the first output */ @@ -791,7 +727,7 @@ void randr_query_outputs() { } DLOG("destroying disappearing con %p\n", output->con); - tree_close(output->con, DONT_KILL_WINDOW, true); + tree_close(output->con, DONT_KILL_WINDOW, true, false); DLOG("Done. Should be fine now\n"); output->con = NULL; } @@ -811,8 +747,6 @@ void randr_query_outputs() { disable_randr(conn); } - ewmh_update_workarea(); - /* Just go through each active output and assign one workspace */ TAILQ_FOREACH(output, &outputs, outputs) { if (!output->active) @@ -849,9 +783,10 @@ void randr_init(int *event_base) { const xcb_query_extension_reply_t *extreply; extreply = xcb_get_extension_data(conn, &xcb_randr_id); - if (!extreply->present) + if (!extreply->present) { disable_randr(conn); - else randr_query_outputs(); + return; + } else randr_query_outputs(); if (event_base != NULL) *event_base = extreply->first_event;