From f3b64311045c3241ac6be3fd293dff8bfd55b6d4 Mon Sep 17 00:00:00 2001 From: Scott Leggett Date: Fri, 29 May 2026 14:30:00 +0800 Subject: [PATCH] commands/focus: implement focus wrapping for floating windows When switching focus between floating windows, those in exactly the same location (like newly floated windows) have a relative distance of 0. Previously, since 0 is not `< 0`, all were considered valid candidates for focus in any direction. This led to two issues: 1. It was not possible to directionally focus away from a set of windows in the same location, as the distance of 0 to the other window in that location was considered closer than a floating window in another location. 2. If floating windows were moved from the same location, any window in the opposite direction had a negative distance and would be ignored as a focus candidate, so focus switching did not "wrap". Focusing a window raises it to the end of workspace->floating. A set of windows in the same location were always valid focus candidates, so shuffling focus between them created the illusion that focus was wrapping, when it was actually just "trapped" in that location. This change fixes both issues: 1. The distance check is changed to `<= 0`. Windows at distance 0 are no longer considered valid candidates in the target direction, allowing directional focus change to escape windows in the same location. 2. The furthest window in the opposite direction is now tracked. If no focus candidates are found in the target direction and focus wrapping is enabled, focus will now wrap around to the furthest window in the opposite direction. --- sway/commands/focus.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 8ae75f229..ba624a600 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -230,6 +230,8 @@ static struct sway_node *node_get_in_direction_floating( double ref_ly = con->pending.y + con->pending.height / 2; double closest_distance = DBL_MAX; struct sway_container *closest_con = NULL; + double furthest_distance = 1; + struct sway_container *furthest_con = NULL; if (!con->pending.workspace) { return NULL; @@ -246,7 +248,12 @@ static struct sway_node *node_get_in_direction_floating( if (dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_UP) { distance = -distance; } - if (distance < 0) { + if (distance <= 0) { + // Track the furthest window in the opposite direction for wrapping + if (distance < furthest_distance) { + furthest_distance = distance; + furthest_con = floater; + } continue; } if (distance < closest_distance) { @@ -254,6 +261,11 @@ static struct sway_node *node_get_in_direction_floating( closest_con = floater; } } + // If there is no window in the requested direction, wrap around to the + // furthest window in the opposite direction. + if (!closest_con && config->focus_wrapping != WRAP_NO) { + closest_con = furthest_con; + } return closest_con ? &closest_con->node : NULL; }