Skip to content
brennovichPublic

About

A wannabe window manager for macOS

Topics

Resources

Contributing

Stars

10 stars

Watchers

0 watching

Forks

Repository files navigation

OttoWM icon
OttoWM

A tiny virtual workspace manager for macOS
Inspired by 2bwm and wmutils,
and by the technical approach of AeroSpace
.

Latest release Pipeline status Coverage


OttoWM preview

OttoWM is a window manager for macOS under intense development.

Some important foundations:

  • No dependency on third-party libraries or frameworks
  • Relies on macOS public APIs only (up until now)
  • Backwards compatibility, it works on macOS Big Sur onwards

Features

It brings the workflow of a common Linux window manager to macOS, without fighting with Mission Control:

  • Native macOS Spaces keep working, whatever happens there won't affect OttoWM
  • Full screen apps are restored to their respective state when leaving full screen
  • Reaching a window through Cmd-Tab, the Dock or Mission Control switches to its workspace

Workspaces

Multiple workspaces on a single native macOS Space: no Space switch animation, no Mission Control. A window that leaves a workspace is parked in the bottom right corner, a point of it left on screen, and comes back to the frame it had, with the focus it had.

Pager

OttoWM relies on the same strategy as AeroSpace, a tiny portion of windows accumulates in the bottom right corner, so the Pager covers this spot while offering nice other features.

Current workspace badge Smart auto-hide Secure input cue
Current workspace badge Smart auto-hide Secure input cue
The tab tells which workspace is current. It squeezes against the screen edge while a window reaches into the corner, and comes back once the corner is free. A pulse cue irradiates while an app holds secure input, e.g. a password field is focused, Password.app auth: every keystroke is withheld from OttoWM, so no binding works.

Option-click the tab to open the About window.

Tabbed windows

Native tab groups (Terminal, Ghostty, Finder, …) count as one window: sending a tab to another workspace takes the whole group, and the group comes back with the tab that was active.

Install

Download the latest OttoWM-<version>.zip from Releases:

curl -fsSL "$(curl -fsSL https://api.github.com/repos/brennovich/ottowm/releases/latest | grep -o 'https://[^"]*\.zip')" -o OttoWM.zip
unzip OttoWM.zip -d /Applications
xattr -cr /Applications/OttoWM.app
open /Applications/OttoWM.app

The app is ad-hoc signed, so Gatekeeper refuses it as coming from an unidentified developer until you clear the quarantine attribute. OttoWM needs Accessibility permission; grant it in System Settings → Privacy & Security → Accessibility on first launch.

Requirements

OttoWM expects a few macOS settings to be in place. They all live in System Settings → Desktop & Dock, under Mission Control and Dock.

Setting Value Why
Group windows by application on Fixes the positioning of windows on Mission Control
Displays have separate Spaces on Each display keeps its own Space, so a workspace switch stays on one display
Automatically rearrange Spaces based on most recent use off The Space order stays fixed, so the Space OttoWM runs on does not move
Automatically hide and show the Dock on Keep the parked windows as hidden as possible
defaults write com.apple.dock expose-group-apps -bool true
defaults write com.apple.spaces spans-displays -bool false
defaults write com.apple.dock mru-spaces -bool false
defaults write com.apple.dock autohide -bool true
killall Dock

spans-displays only takes effect after a log out.

To restore the macOS defaults:

defaults delete com.apple.dock expose-group-apps
defaults delete com.apple.spaces spans-displays
defaults delete com.apple.dock mru-spaces
defaults delete com.apple.dock autohide
killall Dock

Configuration

You can define your own bindings by creating a ~/.config/ottowm/ottowm, it's a good idea to start from the default:

mkdir -p ~/.config/ottowm
cp /Applications/OttoWM.app/Contents/Resources/ottowm ~/.config/ottowm/
# This is a comment

# One `key combo = action`
lopt-1 = switch-to-workspace 1

# or `setting = value` per line
spacing = 20

lopt-shift-1 = move-window-to-workspace 1
lopt-h = focus west
lopt-shift-h = move-window west

# CMD+Ctrl+Option+Shift+Q quits OttoWM
hyper-5 = switch-to-workspace 5
Entry Type Default Description
switch-to-workspace N Action  ⌥ + 1–4 Switch to workspace N
move-window-to-workspace N Action  ⌥⇧ + 1–4 Move the focused window to workspace N
focus D Action  ⌥ + H/J/K/L Focus the window D leads to: north, east, south or west
move-window D Action  ⌥⇧ + H/J/K/L Move the focused window D by the spacing
resize C Action  ⌥⌃⇧ + H/J/K/L Resize the focused window by the spacing: C is wider, narrower, taller or shorter
center-window Action  ⌥⌃ + C Center the focused window on the screen, keeping its size
maximize Action  ⌥⌃ + M Fill the screen with the focused window (toggable)
tile D Action  ⌥⌃ + H/J/K/L Tile the focused window to the half of the screen D leads to (toggable)
quit Action ⌘⌃⌥⇧ + Q Quit OttoWM, putting every parked window back
restart Action ⌘⌃⌥⇧ + R Read the config file again and rebind the keys
about Action ⌘⌃⌥⇧ + A Open the About window: version, Accessibility and hotkeys status, the config in use and the macOS settings above (toggable)
pager = off Setting on Hide the tab in the bottom right corner that shows the current workspace and covers the parked windows
spacing = N Setting 15 Number of points for the gap, the move-window step and the resize change

Note: ⌘ Command, ⌃ Control, ⌥ Option, ⇧ Shift. By default only the left Option (lopt) key triggers the default workspace bindings; the right one is left free for typing special characters™. You can always rebind to use both with opt instead.

Debugging

The About window (hyper-a, or Option-click on the pager tab) displays the all requirements and status statuses of the system, alongside with config and debug tools.

log stream --level debug --predicate 'subsystem == "com.github.brennovich.ottowm"'

Limitations

  • No support for two displays at once (yet). But position and windows size are preserved per display

Note: I have been a software developer for a long time, but this project was built with the help of AI tools, as an opportunity to learn Swift and macOS development.

About

A wannabe window manager for macOS

Topics

Resources

Contributing

Stars

10 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages