Is there an easy way to make just one specific window floating and centered in the current monitor/workspace? #633
Replies: 16 comments 10 replies
-
|
Related discussion: armindarvish/consult-omni#19 (comment) |
Beta Was this translation helpful? Give feedback.
-
|
Looking for the same thing, in yabai, you can do something like: |
Beta Was this translation helpful? Give feedback.
-
|
also looking for something like this! |
Beta Was this translation helpful? Give feedback.
-
|
I've used bspwm extensively. It has a layout called "pseudo-tiling," which allows you to have a window in tiling mode with the ability to resize it individually. This feature lets you keep a single window centered at your desired size, and opening other windows will not overlap the first one. I think this could be the solution to this issue. |
Beta Was this translation helpful? Give feedback.
-
|
It's not easy and quite fragile so this is just a workaround, but I managed to achieve it using AppleScript. Just FYI. I wish if this feature is natively supported by aerospace itself. https://gist.github.com/lambdalisue/5f0ce431b0f41177633c0572fe47ccd7 CleanShot.2024-08-16.at.18.55.08.mp4 |
Beta Was this translation helpful? Give feedback.
-
|
I took @lambdalisue's gist ❤️ and implemented the following features using AppleScript: |
Beta Was this translation helpful? Give feedback.
-
|
Any updates on this? Seems like a basic feature needed to be included |
Beta Was this translation helpful? Give feedback.
-
|
+1 there should be a command to set a fixed position of a floating window |
Beta Was this translation helpful? Give feedback.
-
|
I agree it would be a nice implementation to have Aerospace supported natively. Meanwhile since I don't know swift, I attempted to use Chatgpt to write a swift script to take care of this and it's feels much faster than a shell script. So full credit for AI for getting this working properly 😬 center_floats.swift: import AppKit
// Function to parse arguments
func parseArguments() -> (width: CGFloat, height: CGFloat) {
var width: CGFloat = 1600
var height: CGFloat = 900
let args = CommandLine.arguments
for (index, arg) in args.enumerated() {
switch arg {
case "-w":
if index + 1 < args.count, let w = Double(args[index + 1]) {
width = CGFloat(w)
}
case "-h":
if index + 1 < args.count, let h = Double(args[index + 1]) {
height = CGFloat(h)
}
default:
break
}
}
return (width, height)
}
// Parse command-line arguments
let (desiredWidth, desiredHeight) = parseArguments()
// Function to run a shell command
@discardableResult
func runShellCommand(_ command: String) -> Int32 {
let process = Process()
process.executableURL = URL(fileURLWithPath: "/bin/zsh") // Change to /bin/bash if using bash
process.arguments = ["-c", command]
process.launch()
process.waitUntilExit()
return process.terminationStatus
}
// Function to get the frontmost window
func getFrontmostWindow() -> AXUIElement? {
guard let frontAppPID = NSWorkspace.shared.frontmostApplication?.processIdentifier else {
print("Failed to get the frontmost application.")
return nil
}
let appElement = AXUIElementCreateApplication(frontAppPID)
var focusedWindow: CFTypeRef?
let result = AXUIElementCopyAttributeValue(appElement, kAXFocusedWindowAttribute as CFString, &focusedWindow)
if result == .success, let window = focusedWindow {
return (window as! AXUIElement)
} else {
print("Failed to get the focused window.")
return nil
}
}
// Function to get the monitor where the window is currently located
func getMonitorForWindow(window: AXUIElement) -> NSScreen? {
var windowFrame = CGRect.zero
var value: CFTypeRef?
// Get window position
if AXUIElementCopyAttributeValue(window, kAXPositionAttribute as CFString, &value) == .success,
AXValueGetValue(value as! AXValue, .cgPoint, &windowFrame.origin) {
// Get window size
if AXUIElementCopyAttributeValue(window, kAXSizeAttribute as CFString, &value) == .success,
AXValueGetValue(value as! AXValue, .cgSize, &windowFrame.size) {
// Find the screen containing this window
return NSScreen.screens.first(where: { $0.frame.intersects(windowFrame) })
}
}
return nil
}
// Function to set window position and size
func setWindowPositionAndSize(window: AXUIElement, x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) {
var position = CGPoint(x: x, y: y) // Create mutable CGPoint
var size = CGSize(width: width, height: height) // Create mutable CGSize
let positionValue = AXValueCreate(.cgPoint, &position) // Pass mutable variable
let sizeValue = AXValueCreate(.cgSize, &size) // Pass mutable variable
if let positionValue = positionValue, let sizeValue = sizeValue {
AXUIElementSetAttributeValue(window, kAXPositionAttribute as CFString, positionValue)
AXUIElementSetAttributeValue(window, kAXSizeAttribute as CFString, sizeValue)
}
}
// Main execution
// Run Aerospace commands
let flattenStatus = runShellCommand(let flattenStatus = runShellCommand("aerospace layout floating || aerospace layout tiling")
if flattenStatus != 0 {
print("Failed to execute Aerospace commands.")
exit(1)
}
if let window = getFrontmostWindow() {
if let screen = getMonitorForWindow(window: window) ?? NSScreen.main {
let screenFrame = screen.visibleFrame
let newX = screenFrame.origin.x + (screenFrame.width - desiredWidth) / 2
let newY = screenFrame.origin.y + (screenFrame.height - desiredHeight) / 2
setWindowPositionAndSize(window: window, x: newX, y: newY, width: desiredWidth, height: desiredHeight)
} else {
print("Failed to get the monitor for the window.")
}
} else {
print("No frontmost window found.")
}You can compile it with(make sure to swiftc center_floats.swift -o center_floatsRun it manually: ./center_floats -w 1600 -h 800Or in aerospace.toml example: f = [
'exec-and-forget ~/.config/aerospace/scripts/center_floats',
'move-mouse window-force-center',
'mode main',
]If you don't set a width(-w) and height(-h) it defaults to 1600x800, but you can change it before compiling it yourself if you would like. Also, this works as a toggle between floating and tiling layout. It just made sense to toggle back to tiling if you run it again and the window is already floating. If you don't compile it you can still run the script by adding this line to the very top of the script or simply run with #!/usr/bin/swiftAlthough I highly recommend compiling so it's not calling the interpreter each time. ran a simple time comparison between the shell script I had vs the compiled swift script and got a noticeable difference every time: time ./center_floats.sh
./center_floats.sh 0.11s user 0.30s system 58% cpu 0.693 total
time ./center_floats -w 1600 -h 900
./center_floats -w 1600 -h 900 0.01s user 0.01s system 14% cpu 0.154 total |
Beta Was this translation helpful? Give feedback.
-
|
@wojciech-kulik How would you "separate" rectangle and aerospace? I am new to aerospace and a central floating window is something I am missing. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
I could also do this with hammerspoon scripts, but don't want to have one extra tool to achieve it. |
Beta Was this translation helpful? Give feedback.
-
|
This is quite an essential functionality, what is the native way to achieve a centered floating window @nikitabobko ? |
Beta Was this translation helpful? Give feedback.
-
|
I got a workaround that works pretty well with this: and then on aerospace config: |
Beta Was this translation helpful? Give feedback.
-
|
If you use raycast (pro), here's a solution that combines the best of aerospace and raycast: |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.



Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I tried using the following bash script (called with a keyboard shortcut that is then executed by Raycast):
It kind-of works, because it creates the emacs buffer and puts it horizontally centered for a specific starting state of my Windows (a terminal and an always present Emacs frame). But Aerospace creates the window, modifies the tiling to make space for this newly created window, then moves it and changes the window to float.
The end result with all the window moving is very uncomfortable/distracting. Is there a way to suppress all the window animation/movements (sort of showing the end result window at a centered position only)? Maybe this is not possible, just wondering...
By the way, I am using "Reduce motion" ON in my
Accessibility > Displaysetttings.Beta Was this translation helpful? Give feedback.
All reactions