Skip to content

add new window actions: tile a display in rows or columns - #1850

Open
dank-openai wants to merge 6 commits into
rxhanson:mainfrom
dank-openai:dank/wip/rectangle-rows-columns-upstream
Open

add new window actions: tile a display in rows or columns#1850
dank-openai wants to merge 6 commits into
rxhanson:mainfrom
dank-openai:dank/wip/rectangle-rows-columns-upstream

Conversation

@dank-openai

@dank-openai dank-openai commented Sep 7, 2026

Copy link
Copy Markdown

Summary

  • Add separate, on-demand Tile Windows in Rows and Tile Windows in Columns actions in General > Extras, with independent bindings, localized labels, icons, and URL actions.
  • Arrange eligible windows in the current Space on the focused window's display, or the display under the mouse when no ordinary window is focused. Tile All uses the same display-selection rule. Rows and Columns span the combined area when Rectangle's combined-display mode is enabled and macOS "Displays have separate Spaces" is disabled; otherwise windows on other displays stay in place.
  • Fill the configured work area in backing-pixel bands when window sizes allow it, honoring screen-edge gaps and the existing Todo sidebar reservation while redistributing space around size limits. Todo remains excluded under the existing multi-window rules.

Why This Change

Tile All makes a grid. Rows and Columns provide full-width top-to-bottom or full-height left-to-right layouts without continuous reflow. Neither action has a default shortcut, so existing bindings are preserved. Window order follows their upper-left positions before any moves. An empty target does nothing.

With separate display areas, for example, no focused window and the pointer on the right monitor makes tiling arrange that monitor's windows. Focusing a window on the left monitor makes that monitor the target even if the pointer remains on the right.

If three windows share 901 backing pixels of available height after configured edge gaps, Rows assigns 301, 300, and 300 pixels. The bands meet without an internal gap, while the reserved screen edges remain clear. With a work area 1000 pixels wide before a 200-pixel Todo sidebar reservation, the other windows tile within 800 pixels and Todo stays in place.

Limits and validation

If an app refuses a requested size, Rectangle attempts to rebalance the bands; an impossible layout may still leave a gap or overlap. A window without an accessible ID may be left untiled when on-screen evidence cannot distinguish it from a window in another Space. When matching windows to determine their Space, position and size are compared separately using the same backing-pixel tolerance, so independent rounding does not exclude an otherwise matching window.

All 24 tiling tests pass against compiled application code with synthetic windows. Coverage includes focused-display priority, pointer fallback on either monitor, non-window focus, current-Space selection, empty targets, independent frame rounding, Todo exclusion even when focused, and tiling across combined display bounds. Restoring physical-display filtering or bypassing Todo exclusion makes the corresponding regressions fail.

A nonlaunching xcodebuild build-for-testing succeeded. On earlier feature builds, the author manually tested Rows and Columns with focused windows and confirmed that windows on other monitors stayed in place. The author also confirmed pointer fallback in a separate installed local build that contains additional grid features and shares this PR's display-selection logic. Combined-display mode, Todo, and nonzero edge gaps have not been tested in the running app on this PR branch.

Expose separate on-demand shortcuts in More Shortcuts and arrange ordinary
windows from the current Space into pixel-aligned bands on the focused
display. Respect configured screen-edge gaps and window size limits while
leaving other displays in place.

Include the Todo sidebar transition, icons, localization, documentation,
and focused layout regression tests.
@dank-openai dank-openai changed the title Window actions: tile the focused display in rows or columns add new window actions: tile the focused display in rows or columns Sep 7, 2026
@rxhanson

rxhanson commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Thanks for contributing! At the moment, new window actions are being placed in the popover at the Extras button in the General tab until I rearrange things in this release. Would you mind moving these there?

Rows and Columns retain their independent saved action keys, localized
labels, icons, and shortcut recording. Remove their old storyboard rows
and obsolete extracted strings.
@dank-openai

Copy link
Copy Markdown
Author

Would you mind moving these there?

Sure, I moved the Rows and Columns shortcut fields to General > Extras.

FYI, I'm planning a follow-up PR to cycle through different splits. With six windows, for example, it could cycle from six columns with one window each, to three columns with two windows stacked in each (a 50% split), to two columns with three windows stacked in each (splits at 33% and 66%).

Tile All, Rows, and Columns select the ordinary focused window's display,
falling back to the mouse display when no ordinary window has focus. Keep
focus optional through band placement and leave an empty target unchanged.

Exercise focus priority, pointer fallback, current-Space selection, and
empty displays with synthetic windows. The pointer regression detects a
deliberate restoration of the missing-fallback behavior. The existing
ID-less frame-rounding test still has two assertions that fail at the
original PR head as well.
@rxhanson

Copy link
Copy Markdown
Owner

Great, thanks for moving those settings. In looking through the code changes, I'm a little confused as to why the TodoManager and ScreenDetection were modified, since those are not files I would have modified if I were implementing this myself. I'll have to take a closer look to understand the details, but maybe it's worth checking if you can still accomplish this without modifying those files?

@rxhanson

Copy link
Copy Markdown
Owner

Also, the follow-on idea sounds good to me.

@dank-openai dank-openai changed the title add new window actions: tile the focused display in rows or columns add new window actions: tile a display in rows or columns Sep 10, 2026
Compare each frame component within the existing tolerance so ID-less windows keep valid current-Space evidence when position and size both round. Preserve raw-ID reservation and ambiguity handling. Cover both axes and reject components beyond the tolerance.
@dank-openai

dank-openai commented Sep 10, 2026

Copy link
Copy Markdown
Author

maybe it's worth checking if you can still accomplish this without modifying those files?

I checked both. ScreenDetection.swift contains the shared usable-frame calculation. Rows/Columns must use one physical display even when combined-display mode is enabled (unless, of course, you want this behavior changed). The new entry point does that while reusing the Dock, Stage Manager, and screen-edge gap rules. The mouse fallback already reuses the existing detectScreensAtCursor().

The TodoManager changes support including the Todo window in Rows/Columns. After tiling moves it out of its sidebar, ordinary resize actions otherwise keep reserving the old strip. The new check reserves space only while Todo is on-screen in its expected pinned position. For example, with 1000 pixels of usable width and a 200-pixel sidebar, maximizing another window after tiling Todo would otherwise still use only 800 pixels. Reflow also calculates the future sidebar area before clearing space and pinning Todo again.

Keeping Todo pinned, as Tile All does, would let us remove the TodoManager changes; Rows/Columns would then exclude Todo. For the current behavior, I recommend keeping these rules in the shared helpers.

@rxhanson

Copy link
Copy Markdown
Owner

Thanks for following up!

The premise of Todo mode is that the todo window is ignored by all other window commands performed by Rectangle, and I think the use-case for Todo mode users is that they would disable Todo mode if they desired to tile the todo window with these. My preference is to not adjust TodoManager for these actions, to keep them more consistent with the Todo functionality in the rest of the app.

For ScreenDetection, primarily combined display mode: From what I can tell, the majority of people that disable "Displays have separate spaces" are doing this to treat two identical displays as one; to allow windows to span across the displays. In that sense, if I had that setup then my expectation would be that the tiling simply spans all of these displays as though they were one. As such, my thought here is also to not bother with forcing the single display. If there is compelling reason to limit the tiling to the focused display, then this might be more elegantly done within the window actions themselves instead of modifying the ScreenDetection file.

My intent isn't to nitpick, but simply to keep the app features cohesive and reduce risk on changing commonly hit code paths.

Keep Todo outside Rows/Columns and tile within the existing sidebar
reservation. Use the shared usable-frame calculation and include current-Space
windows across displays when combined-display mode is active. Display selection
still prefers the focused window's display, with the display under the pointer
as the fallback.

Apply focus recovery before candidate filtering so it cannot reintroduce a
focused Todo window. ScreenDetection and TodoManager need no feature-specific
changes.

Focused tests cover Todo exclusion, reserved work area, combined-display
placement, current-Space filtering, and ordinary display isolation. In-memory
window fixtures exercise compiled application code without moving live windows.
@rxhanson

Copy link
Copy Markdown
Owner

One more thing I forgot to mention: rather than adding these into the menu by default, let's leverage Show additional sizes in menu to add these in as a submenu when that is checked. Once this pull request is merged, I'm going to change the shortcuts tab to include all shortcuts in an outline view, so additions like this won't be as hidden (just holding out to avoid merge conflicts).

@dank-openai

Copy link
Copy Markdown
Author

My preference is to not adjust TodoManager for these actions

Thanks, that makes sense. Rows/Columns now follow the existing Todo exclusion and honor combined-display mode. I removed the PR's changes to TodoManager and ScreenDetection.

Group the two actions under Tiling and use Show additional sizes in menu
to control its visibility. Keep shortcut registration independent of the
menu and preserve the existing show-all-actions override.

Exercise the real menu builder with explicit options so tests do not
change saved preferences.
@dank-openai

Copy link
Copy Markdown
Author

rather than adding these into the menu by default

Done - Rows and Columns are grouped under Tiling, shown when Show additional sizes in menu is enabled. Their keyboard shortcuts remain available independently of menu visibility.

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.

2 participants