Skip to content

fix(movewindow): prevent windows from escaping tab groups#295

Open
sim590 wants to merge 2 commits into
outfoxxed:masterfrom
sim590:fix/movewindow-tab-containment
Open

fix(movewindow): prevent windows from escaping tab groups#295
sim590 wants to merge 2 commits into
outfoxxed:masterfrom
sim590:fix/movewindow-tab-containment

Conversation

@sim590

@sim590 sim590 commented Apr 27, 2026

Copy link
Copy Markdown

Summary

When using hy3:movewindow to move a window out of a sub-group (e.g. SplitH) nested inside a tab group, the window escapes the tab group entirely instead of being placed as a sibling within it.

For example, given t(h(a, b)), moving b to the right should produce t(h(a), b), but instead b exits the tab group completely.

Root cause

In shiftOrGetFocus, the parent traversal loop uses once as the sole condition to stop at group boundaries after breaking out of a child group. Since once is false by default, the loop keeps climbing past tab groups. Similarly, after the break, the neighbor descent logic enters adjacent groups instead of placing the window next to them.

Fix

Two one-line changes in src/Hy3Layout.cpp:

  1. Break condition (line 1477): Add group.isTab() so the traversal loop stops at tab group boundaries:

    - if ((has_broken_once && once && shift)
    + if ((has_broken_once && shift && (once || group.isTab()))
  2. Neighbor descent guard (line 1526): Add parent_group.isTab() so the window is placed next to the neighboring group instead of descending into it:

    - || (shift && once && has_broken_once))
    + || (shift && has_broken_once && (once || parent_group.isTab())))

Testing

Manually tested the following scenarios:

# Initial tree Action Expected result Status
1 t(h(a, b)) movewindow right on b t(h(a), b) Pass
2 t(a, b, c) movewindow right on b t(a, c, b) Pass
3 t(a) movewindow right on a exits tab group Pass
4 h(a, b) movewindow right on a h(b, a) (unchanged) Pass
5 t(v(a, b)) movewindow down on a t(v(b, a)) (unchanged) Pass
6 t(h(a, b), c) movewindow right on b t(h(a), b, c) Pass
7 h(t(a,b,c), d) movewindow left on d t(a,b,c,d) Pass

@sim590
sim590 changed the base branch from 0.54 to master May 27, 2026 18:27
When moving a window out of a sub-group (e.g. SplitH) inside a tab
group, the window would traverse the entire tab group instead of
stopping at its boundary. Add group.isTab() to the break condition
in the parent traversal loop and to the neighbor descent guard so
that movewindow stops at tab group boundaries.
@sim590
sim590 force-pushed the fix/movewindow-tab-containment branch from baa1d6c to 1f2bf4a Compare May 27, 2026 18:31
sim590 added a commit to sim590/hy3 that referenced this pull request May 28, 2026
The merge conflict resolution between outfoxxed#295 (movewindow-tab-containment)
and outfoxxed#296 (wrap-tab-single-child) kept only the outfoxxed#296 condition
(break_parent->parent isTab) and dropped the outfoxxed#295 condition
(group.isTab). Both are needed: outfoxxed#295 stops traversal when
break_parent itself is a tab group, outfoxxed#296 stops when a split's
parent is a tab. Without outfoxxed#295's check, windows escape tab groups
when moved at the boundary.
When a split group's parent is a tab group, the shift traversal
must also stop at that boundary. Without this, windows can escape
a tab group that contains split children.

This complements the existing group.isTab() check which handles
the case where break_parent itself is a tab group.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant