From e09861f73fa21f95b58cd0ecec4647d585f91326 Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Sat, 17 Mar 2018 17:42:49 +0200 Subject: [PATCH 1/4] contained_by_output: return output and rename to output_containing_rect --- include/randr.h | 9 ++++----- src/floating.c | 2 +- src/randr.c | 26 ++++++++++++++++++-------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/include/randr.h b/include/randr.h index bfbfd5a9..d365a9e4 100644 --- a/include/randr.h +++ b/include/randr.h @@ -95,15 +95,14 @@ Output *get_output_containing(unsigned int x, unsigned int y); */ 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); /** * Gets the output which is the next one in the given direction. diff --git a/src/floating.c b/src/floating.c index e958153d..29b9cab3 100644 --- a/src/floating.c +++ b/src/floating.c @@ -867,7 +867,7 @@ drag_result_t drag_pointer(Con *con, const xcb_button_press_event_t *event, xcb_ void floating_reposition(Con *con, Rect newrect) { /* Sanity check: Are the new coordinates on any output? If not, we * ignore that request. */ - if (!contained_by_output(newrect)) { + if (!output_containing_rect(newrect)) { ELOG("No output found at destination coordinates. Not repositioning.\n"); return; } diff --git a/src/randr.c b/src/randr.c index 85add08f..efdd0352 100644 --- a/src/randr.c +++ b/src/randr.c @@ -136,27 +136,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; } /* From 8a3ef3a81bd4946777c7e3585384283bf12d89be Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Sat, 17 Mar 2018 20:42:54 +0200 Subject: [PATCH 2/4] Introduce get_output_from_rect --- include/randr.h | 8 ++++++++ src/randr.c | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/randr.h b/include/randr.h index d365a9e4..39182c54 100644 --- a/include/randr.h +++ b/include/randr.h @@ -88,6 +88,14 @@ Output *get_output_by_name(const char *name, const bool require_active); */ Output *get_output_containing(unsigned int x, unsigned int y); +/** + * 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); + /** * Returns the active output which spans exactly the area specified by * rect or NULL if there is no output like this. diff --git a/src/randr.c b/src/randr.c index efdd0352..c43c6455 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. From 128122e7663a5a1f38bd8f921ecaef55ff2a4b13 Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Sat, 17 Mar 2018 17:47:16 +0200 Subject: [PATCH 3/4] floating_enable: change reassign logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the floating container's top left corner to be mapped outside any output as long as they are contained partially by one. This, for example, will allow: mpv --geometry +1+1 video.mp4 For windows mapped to (0, 0) see comment in floating.c:270-273: /* Some clients (like GIMP’s color picker window) get mapped * to (0, 0), so we push them to a reasonable position * (centered over their leader) */ The floating_reassign_ws call is removed since we try to place the new floating container in the current output: /* Sanity check: Are the coordinates on the appropriate output? If not, we * need to change them */ Fixes #1341 --- src/floating.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/src/floating.c b/src/floating.c index 29b9cab3..1c310abe 100644 --- a/src/floating.c +++ b/src/floating.c @@ -284,10 +284,7 @@ void floating_enable(Con *con, bool automatic) { /* Sanity check: Are the coordinates on the appropriate output? If not, we * need to change them */ - Output *current_output = get_output_containing(nc->rect.x + - (nc->rect.width / 2), - nc->rect.y + (nc->rect.height / 2)); - + Output *current_output = get_output_from_rect(nc->rect); Con *correct_output = con_get_output(ws); if (!current_output || current_output->con != correct_output) { DLOG("This floating window is on the wrong output, fixing coordinates (currently (%d, %d))\n", @@ -295,11 +292,13 @@ void floating_enable(Con *con, bool automatic) { /* If moving from one output to another, keep the relative position * consistent (e.g. a centered dialog will remain centered). */ - if (current_output) + if (current_output) { floating_fix_coordinates(nc, ¤t_output->con->rect, &correct_output->rect); - else { - nc->rect.x = correct_output->rect.x; - nc->rect.y = correct_output->rect.y; + /* Make sure that the result is in the correct output. */ + current_output = get_output_from_rect(nc->rect); + } + if (!current_output || current_output->con != correct_output) { + floating_center(nc, ws->rect); } } @@ -320,21 +319,6 @@ void floating_enable(Con *con, bool automatic) { if (set_focus) con_activate(con); - /* Check if we need to re-assign it to a different workspace because of its - * coordinates and exit if that was done successfully. */ - if (floating_maybe_reassign_ws(nc)) { - goto done; - } - - /* Sanitize coordinates: Check if they are on any output */ - if (get_output_containing(nc->rect.x, nc->rect.y) != NULL) { - goto done; - } - - ELOG("No output found at destination coordinates, centering floating window on current ws\n"); - floating_center(nc, ws->rect); - -done: floating_set_hint_atom(nc, true); ipc_send_window_event("floating", con); } From 8e9b26fc9028d19b4756bd8e3ed3a3ecfcf5fd6f Mon Sep 17 00:00:00 2001 From: Orestis Floros Date: Sat, 17 Mar 2018 20:43:11 +0200 Subject: [PATCH 4/4] floating_maybe_reassign_ws: use get_output_from_rect This significantly reduces the number of ELOGs while dragging floating containers. The behaviour is improved since floating containers in the edge of the screen will still get reassigned to their closest workspace. For example, consider this setup: fake-outputs 500x500+0+0,500x500+500+0 Now, open a window in the right output and run: i3-msg floating enable, move position 0 px 450 px The window is on the bottom edge of the left workspace but if you run: i3-msg focus mode_toggle focus will go to the right workspace since floating_maybe_reassign_ws didn't change the assigned workspace of the floating container. --- src/floating.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/floating.c b/src/floating.c index 1c310abe..13b30f16 100644 --- a/src/floating.c +++ b/src/floating.c @@ -413,9 +413,7 @@ void floating_raise_con(Con *con) { * */ bool floating_maybe_reassign_ws(Con *con) { - Output *output = get_output_containing( - con->rect.x + (con->rect.width / 2), - con->rect.y + (con->rect.height / 2)); + Output *output = get_output_from_rect(con->rect); if (!output) { ELOG("No output found at destination coordinates?\n");