From d43038b141a98762535b4a74eb03e0d81147a29e Mon Sep 17 00:00:00 2001 From: Milad Alizadeh Date: Tue, 6 Jan 2026 21:40:40 +0000 Subject: [PATCH] workspace: match i3's depth-first workspace-output assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When selecting which workspace to create on an output, i3 uses a "depth-first" approach: for each workspace, it checks if the current output is the *first available* choice in that workspace's output list. This allows configurations like: workspace 1 output DP-1 eDP-1 workspace 9 output eDP-1 When only eDP-1 is connected, i3 would select workspace 1 (since eDP-1 is its first available output). Previously, sway would check if the output was *anywhere* in the workspace's list, which could lead to unexpected behavior depending on config order. This change updates both workspace_valid_on_output() and workspace_next_name() to use the same "first available" logic as i3, making sway's workspace-output assignment behavior match i3 more closely. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- sway/tree/workspace.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 733a002b4..c6a93792b 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -201,9 +201,14 @@ static bool workspace_valid_on_output(const char *output_name, return true; } + // Match i3's behavior: a workspace is only valid on an output if that + // output is the first available choice in the workspace's output list. for (int i = 0; i < wsc->outputs->length; i++) { - if (output_match_name_or_id(output, wsc->outputs->items[i])) { - return true; + struct sway_output *first_available = + output_by_name_or_id(wsc->outputs->items[i]); + if (first_available) { + // Found the first available output - valid only if it matches + return first_available == output; } } @@ -319,11 +324,21 @@ char *workspace_next_name(const char *output_name) { continue; } bool found = false; + // Find the first available output for this workspace, matching i3's + // depth-first behavior: only select this workspace if the current + // output is the first available choice in its output list. for (int j = 0; j < wsc->outputs->length; ++j) { - if (output_match_name_or_id(output, wsc->outputs->items[j])) { - found = true; - free(target); - target = strdup(wsc->workspace); + struct sway_output *first_available = + output_by_name_or_id(wsc->outputs->items[j]); + if (first_available) { + // Found the first available output for this workspace + if (first_available == output) { + // Current output is the first choice - select this workspace + found = true; + free(target); + target = strdup(wsc->workspace); + } + // Always break: we only care about the first available output break; } }