What It Does
ActiveSpace replaces macOS’s sluggish space-switching animation with instant transitions. Spaces change immediately — no sliding, no delay, no waiting for the compositor to catch up.
A numbered bubble in the menu bar shows your current space. Click it to switch, or configure keyboard shortcuts for hands-free navigation. Wrap-around is built in: on the last space, “next” takes you back to the first.
Optionally, ActiveSpace can also replace the system cmdtab switcher with one that only shows apps with windows on your current space — including minimised windows and windows of hidden apps. Off by default; enable it in Settings if you want it.
How It Works
ActiveSpace uses synthetic dock-swipe gesture events to switch spaces without animation. A lightweight virtual display ensures reliable behaviour across all monitor configurations — single screen, dual monitors, laptop lid open or closed.
With two spaces, a single click is all it takes to flip between them. With three or more, a popover appears with numbered buttons — click any to jump directly to that space.
Grid Layout
If you keep more than a handful of spaces and think of them as a grid — say 8 spaces as a 4×2 — tell ActiveSpace your row width in Settings. The popover reflows into rows of that width, and two extra hotkeys become available: Space Up and Space Down, which navigate ±rowWidth with column-cycling wrap so Space Down from the bottom of a column lands at the top of the same column.
With grid mode on, the existing Next Space and Previous Space shortcuts become row-aware too: Next from the last column of any row wraps back to the first column of the same row instead of stepping into the next row. Set row width to 0 to keep the original linear behaviour.
Space-Aware Cmd-Tab Switcher
Enable the Switcher in Settings and cmdtab shows only the apps with windows on your current space. Cycle with tab or arrow keys, reverse with shifttab, commit by releasing cmd or pressing return, cancel with esc. Click any icon in the HUD to commit directly.
Apps that are completely hidden (cmdH) or have only minimised windows on the current space still appear in the HUD with a small badge. Selecting one unminimises or unhides as needed before bringing it forward.
When the Switcher is off, native cmdtab behaviour is completely untouched.
Architecture
| File | Purpose |
|---|---|
ActiveSpaceApp.swift | Entry point; wires AppDelegate |
AppDelegate.swift | Owns the NSStatusItem, event tap, click routing, popover, settings window |
SpaceObserver.swift | Tracks current space index and total space count |
SpaceSwitcher.swift | Hybrid space switching: direct CGS API on single display, synthetic dock-swipe on multi-display |
VirtualDisplay.swift | Manages the invisible virtual display, drift reposition, cursor fence, and menu-bar reset on display reconfig |
VirtualDisplayHelper.m | Obj-C helper for CGVirtualDisplay creation |
MenuBarIcon.swift | Renders the numbered bubble icon dynamically |
SpaceSelectorView.swift | SwiftUI popover with numbered space buttons |
TransitionOverlay.swift | Per-screen blur overlay that masks intermediate-space flashes during multi-step jumps |
SwitcherController.swift | State machine for the space-aware cmdtab switcher |
SwitcherHUDWindow.swift | Borderless HUD with proportional icon scaling for any number of apps |
SwitcherAppResolver.swift | Enumerates apps with windows on the current space via SLSCopySpacesForWindows |
SwitcherAppStack.swift | Per-space MRU bundle-ID stack |
AppIconCache.swift | Pre-warms and caches scaled app icons so the first HUD draw is snappy |
ReconfigurationObserver.swift | Six-source observer for display + spaces + screen-lock + poll events |
DriftMonitor.swift | Classifies reconfiguration events; logs drift verdicts for debugging |
CGSPrivate.swift | Swift bindings for private CoreGraphics, SkyLight, and Accessibility APIs |
Space Detection
ActiveSpace queries the private CoreGraphics CGSCopyManagedDisplaySpaces API to enumerate all spaces across all displays and identify which is current. It stays up to date via three mechanisms:
- Space change notification — fires on every space switch
- Screen parameters notification — fires when spaces are added or removed via Mission Control
- 2-second poll timer — backstop for edge cases where notifications don't fire
Installation
Two formats on every release — both signed and notarised, pick whichever suits:
- Installer (
.pkg) — recommended for first-time installs. Double-click to run; macOS Installer places the app in/Applicationswithout quarantine or App Translocation. - Download (
.zip) — unzip and dragActiveSpace.appto your Applications folder.
Launch ActiveSpace from /Applications and grant Accessibility and Input Monitoring permissions when prompted.
Settings
Right-click the icon and choose Settings… to configure:
- Keyboard shortcuts — configurable Next Space and Previous Space shortcuts (plus Space Up and Space Down when grid layout is enabled)
- Grid — optional row width to reflow the popover and switch the navigation shortcuts to grid-aware wrapping
- Switcher — toggle the space-aware cmdtab replacement on or off
- Permissions — Accessibility and Input Monitoring status with grant buttons
- Launch at Login — start automatically when you log in
Auto-updates are handled by Sparkle. Use the “Check for Updates…” menu item to check on demand; Sparkle’s prompt offers an “Automatically download and install updates in the future” checkbox the first time an update is available. ActiveSpace checks for new versions automatically once a day in the background.
Permissions
ActiveSpace requires two permissions, both manageable from the Settings panel:
- Accessibility — required for space switching. macOS will prompt on first launch.
- Input Monitoring — required for keyboard shortcuts. If not granted, ActiveSpace will display an alert with a direct link to the correct System Settings pane.
To avoid conflicts with the built-in Mission Control shortcuts, disable control← and control→ in System Settings → Keyboard → Keyboard Shortcuts → Mission Control.
If your Dock disappears
ActiveSpace uses an invisible virtual display on single-monitor configurations to make space switching reliable. Very rarely, a display reconfiguration can cause the Dock to migrate onto it. If it happens, right-click the ActiveSpace bubble in the menu bar and choose Quit — your Dock will return immediately.
If your mouse pointer disappears
The same invisible virtual display sits 6000pt off-screen to the right. ActiveSpace installs a cursor fence to keep the pointer out of that region, but a fast cursor throw during exactly the wrong moment (e.g. just after waking from screen lock, while the fence is briefly disarmed) can occasionally slip past — and once the cursor is on the off-screen virtual, it’s invisible.
ActiveSpace ships MouseCatcher for exactly this case — a tiny keyboard-only utility that warps the cursor back to the centre of your main display. ActiveSpace deploys it to /Applications/MouseCatcher.app automatically on launch (sibling of ActiveSpace.app), so it’s already there when you need it. To recover the cursor:
- Press commandspace to open Spotlight
- Type MouseCatcher
- Press return
The cursor reappears immediately near the centre of your main display. MouseCatcher does its one job and exits — no Dock flash, no menu-bar item, no UI.
Building from Source
Open the Xcode project and build:
- Clone the repo:
git clone https://github.com/PerpetualBeta/ActiveSpace.git - Open
ActiveSpace.xcodeprojin Xcode - Build with commandB or run with commandR
Requirements
macOS 14 (Sonoma) or later. Universal binary (Apple Silicon and Intel).
Read about ActiveSpace
- When the Stars Align — how synthetic dock-swipe gestures enable instant space switching, with credit to the open-source projects that made it possible.
- When the Stars Align (Redux) — the single-monitor debugging odyssey, and the invisible virtual display that fixed everything.
- When the Stars Align (Final Cut)(Maybe) — the post-Redux week of subtle misbehaviour, three small fixes that finally let ActiveSpace ship cleanly, and the satisfying deletion of a fourth that the data showed wasn’t needed.