X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Frandr.c;h=fb127ab5622f1ada69da11b552a8778735972ec9;hb=b6282b47bc757c3521eff090748bc81481913297;hp=85add08fa41ea2cb64a60fc194a3fe65d02a1550;hpb=eda440d6ae84307c6e9327c24bd4946526592a80;p=i3%2Fi3 diff --git a/src/randr.c b/src/randr.c index 85add08f..fb127ab5 100644 --- a/src/randr.c +++ b/src/randr.c @@ -114,6 +114,20 @@ Output *get_output_containing(unsigned int x, unsigned int y) { return NULL; } +/* + * Returns the active output which contains the midpoint of the given rect. If + * such an output doesn't exist, returns the output which contains most of the + * rectangle or NULL if there is no output which intersects with it. + * + */ +Output *get_output_from_rect(Rect rect) { + unsigned int mid_x = rect.x + rect.width / 2; + unsigned int mid_y = rect.y + rect.height / 2; + Output *output = get_output_containing(mid_x, mid_y); + + return output ? output : output_containing_rect(rect); +} + /* * Returns the active output which spans exactly the area specified by * rect or NULL if there is no output like this. @@ -136,27 +150,37 @@ Output *get_output_with_dimensions(Rect rect) { } /* - * In contained_by_output, we check if any active output contains part of the container. + * In output_containing_rect, we check if any active output contains part of the container. * We do this by checking if the output rect is intersected by the Rect. * This is the 2-dimensional counterpart of get_output_containing. - * Since we don't actually need the outputs intersected by the given Rect (There could - * be many), we just return true or false for convenience. + * Returns the output with the maximum intersecting area. * */ -bool contained_by_output(Rect rect) { +Output *output_containing_rect(Rect rect) { Output *output; int lx = rect.x, uy = rect.y; int rx = rect.x + rect.width, by = rect.y + rect.height; + long max_area = 0; + Output *result = NULL; TAILQ_FOREACH(output, &outputs, outputs) { if (!output->active) continue; + int lx_o = (int)output->rect.x, uy_o = (int)output->rect.y; + int rx_o = (int)(output->rect.x + output->rect.width), by_o = (int)(output->rect.y + output->rect.height); 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); - 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; + int left = max(lx, lx_o); + int right = min(rx, rx_o); + int bottom = min(by, by_o); + int top = max(uy, uy_o); + if (left < right && bottom > top) { + long area = (right - left) * (bottom - top); + if (area > max_area) { + result = output; + } + } } - return false; + return result; } /* @@ -396,18 +420,17 @@ void output_init_con(Output *output) { * • Create the first unused workspace. * */ -void init_ws_for_output(Output *output, Con *content) { +void init_ws_for_output(Output *output) { + Con *content = output_get_content(output->con); + Con *previous_focus = con_get_workspace(focused); + /* 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_primary_name(output)) != 0) + if (!output_triggers_assignment(output, assignment)) { continue; - - /* 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)); + } + Con *workspace = get_existing_workspace_by_name(assignment->name); if (workspace == NULL) continue; @@ -422,49 +445,18 @@ void init_ws_for_output(Output *output, Con *content) { 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_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 - * with no active workspace */ - bool visible = workspace_is_visible(workspace); - Con *previous = NULL; - 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); - } - - /* 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); - - /* In case the workspace we just moved was visible but there was no - * other workspace to switch to, we need to initialize the source - * output as well */ - 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, true), - output_get_content(workspace_out)); - DLOG("Done re-initializing, continuing with \"%s\"\n", output_primary_name(output)); - } + DLOG("Moving workspace \"%s\" from output \"%s\" to \"%s\" due to assignment\n", + workspace->name, workspace_out->name, output_primary_name(output)); + /* Need to copy output's rect since content is not yet rendered. We + * can't call render_con here because render_output only proceeds if a + * workspace exists. */ + content->rect = output->con->rect; + workspace_move_to_output(workspace, output); } + /* Temporarily set the focused container, might not be initialized yet. */ + focused = content; + /* if a workspace exists, we are done now */ if (!TAILQ_EMPTY(&(content->nodes_head))) { /* ensure that one of the workspaces is actually visible (in fullscreen @@ -473,30 +465,31 @@ void init_ws_for_output(Output *output, Con *content) { GREP_FIRST(visible, content, child->fullscreen_mode == CF_OUTPUT); if (!visible) { visible = TAILQ_FIRST(&(content->nodes_head)); - focused = content; workspace_show(visible); } - return; + goto restore_focus; } /* otherwise, we create the first assigned ws for this output */ TAILQ_FOREACH(assignment, &ws_assignments, ws_assignments) { - if (strcmp(assignment->output, output_primary_name(output)) != 0) + if (!output_triggers_assignment(output, assignment)) { continue; + } LOG("Initializing first assigned workspace \"%s\" for output \"%s\"\n", assignment->name, assignment->output); - focused = content; workspace_show_by_name(assignment->name); - return; + goto restore_focus; } /* if there is still no workspace, we create the first free workspace */ DLOG("Now adding a workspace\n"); - Con *ws = create_workspace_on_output(output, content); + workspace_show(create_workspace_on_output(output, content)); - /* TODO: Set focus in main.c */ - con_activate(ws); +restore_focus: + if (previous_focus) { + workspace_show(previous_focus); + } } /* @@ -529,7 +522,7 @@ static void output_change_mode(xcb_connection_t *conn, Output *output) { } /* If default_orientation is NO_ORIENTATION, we change the orientation of - * the workspaces and their childs depending on output resolution. This is + * the workspaces and their children depending on output resolution. This is * only done for workspaces with maximum one child. */ if (config.default_orientation == NO_ORIENTATION) { TAILQ_FOREACH(workspace, &(content->nodes_head), nodes) { @@ -836,8 +829,9 @@ void randr_query_outputs(void) { /* 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) + if (root_output && root_output->active) { root_output->to_be_disabled = true; + } } else { DLOG("No active RandR output found. Enabling root output.\n"); root_output->active = true; @@ -915,7 +909,7 @@ void randr_query_outputs(void) { if (!TAILQ_EMPTY(&(content->nodes_head))) continue; DLOG("Should add ws for output %s\n", output_primary_name(output)); - init_ws_for_output(output, content); + init_ws_for_output(output); } /* Focus the primary screen, if possible */ @@ -924,7 +918,9 @@ void randr_query_outputs(void) { continue; DLOG("Focusing primary output %s\n", output_primary_name(output)); - con_activate(con_descend_focused(output->con)); + Con *content = output_get_content(output->con); + Con *ws = TAILQ_FIRST(&(content)->focus_head); + workspace_show(ws); } /* render_layout flushes */ @@ -952,13 +948,8 @@ void randr_disable_output(Output *output) { if (output->con != NULL) { /* We need to move the workspaces from the disappearing output to the first output */ - /* 1: Get the con to focus next, if the disappearing ws is focused */ - Con *next = NULL; - if (TAILQ_FIRST(&(croot->focus_head)) == output->con) { - DLOG("This output (%p) was focused! Getting next\n", output->con); - next = focused; - DLOG("next = %p\n", next); - } + /* 1: Get the con to focus next */ + Con *next = focused; /* 2: iterate through workspaces and re-assign them, fixing the coordinates * of floating containers as we go */ @@ -969,7 +960,7 @@ void randr_disable_output(Output *output) { 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_internal(current, DONT_KILL_WINDOW, false, false); + tree_close_internal(current, DONT_KILL_WINDOW, false); continue; } DLOG("Detaching current = %p / %s\n", current, current->name); @@ -981,13 +972,12 @@ void randr_disable_output(Output *output) { 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"); + /* Restore focus after con_detach / con_attach. next can be NULL, see #3523. */ if (next) { DLOG("now focusing next = %p\n", next); - con_activate(next); + con_focus(next); workspace_show(con_get_workspace(next)); } @@ -1015,7 +1005,7 @@ void randr_disable_output(Output *output) { Con *con = output->con; /* clear the pointer before calling tree_close_internal in which the memory is freed */ output->con = NULL; - tree_close_internal(con, DONT_KILL_WINDOW, true, false); + tree_close_internal(con, DONT_KILL_WINDOW, true); DLOG("Done. Should be fine now\n"); } @@ -1026,7 +1016,7 @@ void randr_disable_output(Output *output) { static void fallback_to_root_output(void) { root_output->active = true; output_init_con(root_output); - init_ws_for_output(root_output, output_get_content(root_output->con)); + init_ws_for_output(root_output); } /*