Skip to content

Commit 3f261d3

Browse files
hi2gageclaude
andauthored
Add tileActiveApp action to tile windows of the active application (#1684)
Adds a new window action that tiles only windows belonging to the currently active (foremost) app into a grid, leaving all other windows alone. This complements the existing cascadeActiveApp action. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Gage <[email protected]> Co-authored-by: Claude Opus 4.5 <[email protected]>
1 parent cbc4996 commit 3f261d3

File tree

3 files changed

+39
-5
lines changed

3 files changed

+39
-5
lines changed

Rectangle/MultiWindow/MultiWindowManager.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ class MultiWindowManager {
2525
case .cascadeActiveApp:
2626
cascadeActiveAppWindowsOnScreen(windowElement: parameters.windowElement)
2727
return true
28+
case .tileActiveApp:
29+
tileActiveAppWindowsOnScreen(windowElement: parameters.windowElement)
30+
return true
2831
default:
2932
return false
3033
}
@@ -186,4 +189,29 @@ class MultiWindowManager {
186189
w.setFrame(rect)
187190
w.bringToFront()
188191
}
192+
193+
static func tileActiveAppWindowsOnScreen(windowElement: AccessibilityElement? = nil) {
194+
guard let (screens, windows) = allWindowsOnScreen(windowElement: windowElement, sortByPID: true),
195+
let frontWindowElement = AccessibilityElement.getFrontWindowElement()
196+
else {
197+
return
198+
}
199+
200+
let screenFrame = screens.currentScreen.adjustedVisibleFrame().screenFlipped
201+
202+
// keep windows with a pid equal to the front window's pid
203+
let filtered = windows.filter { $0.pid == frontWindowElement.pid }
204+
205+
let count = filtered.count
206+
207+
let columns = Int(ceil(sqrt(CGFloat(count))))
208+
let rows = Int(ceil(CGFloat(count) / CGFloat(columns)))
209+
let size = CGSize(width: (screenFrame.maxX - screenFrame.minX) / CGFloat(columns), height: (screenFrame.maxY - screenFrame.minY) / CGFloat(rows))
210+
211+
for (ind, w) in filtered.enumerated() {
212+
let column = ind % Int(columns)
213+
let row = ind / Int(columns)
214+
tileWindow(w, screenFrame: screenFrame, size: size, column: column, row: row)
215+
}
216+
}
189217
}

Rectangle/WindowAction.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ enum WindowAction: Int, Codable {
9898
largerHeight = 82,
9999
smallerHeight = 83,
100100
centerTwoThirds = 84,
101-
centerThreeFourths = 85
101+
centerThreeFourths = 85,
102+
tileActiveApp = 86
102103

103104
// Order matters here - it's used in the menu
104105
static let active = [leftHalf, rightHalf, centerHalf, topHalf, bottomHalf,
@@ -121,7 +122,7 @@ enum WindowAction: Int, Codable {
121122
halveHeightUp, halveHeightDown, halveWidthLeft, halveWidthRight,
122123
tileAll, cascadeAll,
123124
leftTodo, rightTodo,
124-
cascadeActiveApp
125+
cascadeActiveApp, tileActiveApp
125126
]
126127

127128
func post() {
@@ -233,6 +234,7 @@ enum WindowAction: Int, Codable {
233234
case .leftTodo: return "leftTodo"
234235
case .rightTodo: return "rightTodo"
235236
case .cascadeActiveApp: return "cascadeActiveApp"
237+
case .tileActiveApp: return "tileActiveApp"
236238
case .centerProminently: return "centerProminently"
237239
case .largerWidth: return "largerWidth"
238240
case .smallerWidth: return "smallerWidth"
@@ -378,7 +380,7 @@ enum WindowAction: Int, Codable {
378380
return nil
379381
case .doubleHeightUp, .doubleHeightDown, .doubleWidthLeft, .doubleWidthRight, .halveHeightUp, .halveHeightDown, .halveWidthLeft, .halveWidthRight:
380382
return nil
381-
case .specified, .reverseAll, .tileAll, .cascadeAll, .leftTodo, .rightTodo, .cascadeActiveApp:
383+
case .specified, .reverseAll, .tileAll, .cascadeAll, .leftTodo, .rightTodo, .cascadeActiveApp, .tileActiveApp:
382384
return nil
383385
case .centerProminently, .largerWidth, .smallerWidth, .largerHeight, .smallerHeight:
384386
return nil
@@ -410,7 +412,7 @@ enum WindowAction: Int, Codable {
410412

411413
var isDragSnappable: Bool {
412414
switch self {
413-
case .restore, .previousDisplay, .nextDisplay, .moveUp, .moveDown, .moveLeft, .moveRight, .specified, .reverseAll, .tileAll, .cascadeAll, .larger, .smaller, .largerWidth, .smallerWidth, .cascadeActiveApp,
415+
case .restore, .previousDisplay, .nextDisplay, .moveUp, .moveDown, .moveLeft, .moveRight, .specified, .reverseAll, .tileAll, .cascadeAll, .larger, .smaller, .largerWidth, .smallerWidth, .cascadeActiveApp, .tileActiveApp,
414416
// Ninths
415417
.topLeftNinth, .topCenterNinth, .topRightNinth, .middleLeftNinth, .middleCenterNinth, .middleRightNinth, .bottomLeftNinth, .bottomCenterNinth, .bottomRightNinth,
416418
// Corner thirds
@@ -557,6 +559,7 @@ enum WindowAction: Int, Codable {
557559
case .leftTodo: return NSImage()
558560
case .rightTodo: return NSImage()
559561
case .cascadeActiveApp: return NSImage()
562+
case .tileActiveApp: return NSImage()
560563
case .centerProminently: return NSImage()
561564
case .largerWidth: return NSImage(imageLiteralResourceName: "largerWidthTemplate")
562565
case .smallerWidth: return NSImage(imageLiteralResourceName: "smallerWidthTemplate")
@@ -604,7 +607,7 @@ enum WindowAction: Int, Codable {
604607
return Defaults.applyGapsToMaximize.userDisabled ? .none : .both;
605608
case .maximizeHeight:
606609
return Defaults.applyGapsToMaximizeHeight.userDisabled ? .none : .vertical;
607-
case .almostMaximize, .previousDisplay, .nextDisplay, .larger, .smaller, .largerWidth, .smallerWidth, .largerHeight, .smallerHeight, .center, .centerProminently, .restore, .specified, .reverseAll, .tileAll, .cascadeAll, .cascadeActiveApp:
610+
case .almostMaximize, .previousDisplay, .nextDisplay, .larger, .smaller, .largerWidth, .smallerWidth, .largerHeight, .smallerHeight, .center, .centerProminently, .restore, .specified, .reverseAll, .tileAll, .cascadeAll, .cascadeActiveApp, .tileActiveApp:
608611
return .none
609612
}
610613
}

TerminalCommands.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,14 @@ The key codes are:
257257
* tileAll
258258
* cascadeAll
259259
* cascadeActiveApp
260+
* tileActiveApp
260261

261262
_tileAll_ and _cascadeAll_ act on all visible windows.
262263

263264
_cascadeActiveApp_ cascades and brings to the front only windows belonging to the currently active (foremost) app, leaving all other windows alone.
264265

266+
_tileActiveApp_ tiles only windows belonging to the currently active (foremost) app into a grid, leaving all other windows alone.
267+
265268
For example, the command for setting the cascadeActiveApp shortcut to `ctrl shift 2` would be:
266269

267270
```bash

0 commit comments

Comments
 (0)