Repository navigation
✨ Option to make Next/Previous display movement follow clockwise order #1000
Description
Activity
I just tried Rectangle, and it also didn’t follow the clockwise order.
So maybe this order is provided by the system?
Just find the code:
https://github.com/MrKai77/Loop/blob/8e82a047225289042faef2ce197bf78e06903be5/Loop/Utilities/ScreenUtility.swift#L96
/// Sorts all NSScreens in an order such that the next/previous screen are in positional order.
private static func getOrderedScreens() -> [NSScreen] {
NSScreen.screens.sorted { screen1, screen2 in
if screen2.frame.maxY <= screen1.frame.minY {
return true
}
if screen1.frame.maxY <= screen2.frame.minY {
return false
}
return screen1.frame.minX < screen2.frame.minX
}
}
Or add another feature to let users manually sort their displays?
The behavior you’re seeing is actually intended; the screen switching roughly follows a “vertically stacked Z” shape. That said, I agree that sorting screens in a clockwise direction could be interesting. I'm thinking that it might make more sense to expose an advanced option that lets them choose how “Next/Previous Screen” determines the next screen: using a Z-shaped order, clockwise, or counter-clockwise.
It would be great to have this feature. But I just wonder, if a user has 9 displays and they are arranged in a 3x3 layout, how would clockwise ordering work? I mean, how would the center display be handled?
I’d expect it would cycle through the outer displays clockwise first, then move on to the inner displays, again in a clockwise order :)
By the way, I asked AI (please don't get mad for this) last night and this is his answer:
private static func getOrderedScreensClockwise() -> [NSScreen] {
let screens = NSScreen.screens
// 1. Compute the center point of each screen
let centers = screens.map { screen -> CGPoint in
CGPoint(
x: screen.frame.midX,
y: screen.frame.midY
)
}
// 2. Compute the geometric center of the entire display layout
let centerX = centers.map(\.x).reduce(0, +) / CGFloat(centers.count)
let centerY = centers.map(\.y).reduce(0, +) / CGFloat(centers.count)
let layoutCenter = CGPoint(x: centerX, y: centerY)
// 3. Sort screens by their angular position around the layout center (clockwise)
return screens.sorted { s1, s2 in
let a1 = atan2(
s1.frame.midY - layoutCenter.y,
s1.frame.midX - layoutCenter.x
)
let a2 = atan2(
s2.frame.midY - layoutCenter.y,
s2.frame.midX - layoutCenter.x
)
// atan2 returns angles in counterclockwise order; reversing it yields clockwise traversal
return a1 > a2
}
}I think it's a little complex, and I don't like math. Tried to test locally today, but the build failed because I don't have a developer account, probably.
By the way, I asked AI (please don't get mad for this) last night and this is his answer:
private static func getOrderedScreensClockwise() -> [NSScreen] {
let screens = NSScreen.screens// 1. Compute the center point of each screen let centers = screens.map { screen -> CGPoint in CGPoint( x: screen.frame.midX, y: screen.frame.midY ) } // 2. Compute the geometric center of the entire display layout let centerX = centers.map(\.x).reduce(0, +) / CGFloat(centers.count) let centerY = centers.map(\.y).reduce(0, +) / CGFloat(centers.count) let layoutCenter = CGPoint(x: centerX, y: centerY) // 3. Sort screens by their angular position around the layout center (clockwise) return screens.sorted { s1, s2 in let a1 = atan2( s1.frame.midY - layoutCenter.y, s1.frame.midX - layoutCenter.x ) let a2 = atan2( s2.frame.midY - layoutCenter.y, s2.frame.midX - layoutCenter.x ) // atan2 returns angles in counterclockwise order; reversing it yields clockwise traversal return a1 > a2 }}
I think it's a little complex, and I don't like math. Tried to test locally today, but the build failed because I don't have a developer account, probably.
Test locally, works great 😊
@mrkai77
Should we add an option to let users choose between the previous “Z” order and the new clockwise order, or should we simply make the clockwise order the default?
If we add an option, should it be placed under Settings > Behavior > Display Order? We might also need two icons to represent the different orders.
Yes, it makes sense to expose this as an option for users while keeping the current behavior as the default. I think it would fit well in the Advanced tab, since it’s likely not something most users will need to change.
As for the code you attached above, it would work, but the main caveat is that it won’t handle doubly-layered (or higher-ordered) screen layouts, since it relies purely on angles rather than processing the outermost and then innermost layouts clockwise 😉
Hey @Caffeine19! I haven’t had a chance to fully test this on my end yet either, but here’s a build that adds an option to navigate screens in a clockwise order:
https://github.com/MrKai77/Loop/actions/runs/22194367772/artifacts/5577914708
If you’re able to try it out, I’d really appreciate hearing whether it works as expected! You can find the setting under the Advanced tab :)
Hey @Caffeine19! I haven’t had a chance to fully test this on my end yet either, but here’s a build that adds an option to navigate screens in a clockwise order: https://github.com/MrKai77/Loop/actions/runs/22194367772/artifacts/5577914708
If you’re able to try it out, I’d really appreciate hearing whether it works as expected! You can find the setting under the Advanced tab :)
Thanks, bro. I’ll try it later. Sorry, I’m on holiday and can’t get four displays to test. 😘
Hey @Caffeine19! I haven’t had a chance to fully test this on my end yet either, but here’s a build that adds an option to navigate screens in a clockwise order: https://github.com/MrKai77/Loop/actions/runs/22194367772/artifacts/5577914708
If you’re able to try it out, I’d really appreciate hearing whether it works as expected! You can find the setting under the Advanced tab :)
Happy New Year 😘
Just tested with the new "Clockwise" option:
It works great in this display layout:
But still moves in Z-pattern in this display layout, which I actually is:

Hey @Caffeine19! This is now merged in #1156 and will be in the next development build. You can switch to development builds from Loop’s About tab. Once you’ve updated, go to Advanced > Next/previous screen order and choose Clockwise :)
About the layout you mentioned last time, where it still moved in a Z pattern: the clockwise order is now worked out differently. Loop traces the outline of your screen arrangement clockwise and visits each screen the first time the outline reaches it. This should handle two-row layouts much better, including rows that are a few pixels out of line or that mix screen sizes. Please let us know if it still doesn’t follow the order you’d expect!
Bug Description
These are my display arrangements and the order I would expect when moving a window to the next / previous display in a clockwise direction, as illustrated below:
In this layout, I expect the window to move between displays following the clockwise order shown by the numbered arrows.
Actual behavior
However, this is what actually happens:
The window traversal order does not follow the physical clockwise arrangement of the displays and instead jumps between displays in an unintuitive order.
Affected Scope
User interface
Steps to Reproduce
Reproducibility
Always
Expected vs Actual Behavior
Expected behavior
When moving a window to the next or previous display, the window should follow the physical display layout in a clockwise order.
Actual behavior
When moving a window to the next or previous display, the window moves between displays in a non-clockwise and unintuitive order.
Screen Recordings / Screenshots
No response
Severity
Critical (major functionality broken)
macOS Version
macOS 15.7.3
Loop Version
Version 🧪 1.4.1 (1673)
Did You Try the Development Build?
Yes
Additional Context
No response
Final Checks