Switcher Service in vorssaint-utils: Features, Configuration, and Implementation Guide

The Switcher service in vorssaint-utils provides a highly configurable macOS window-switching panel with icon-row and grid layouts, customizable shortcuts, live window previews, and advanced session management.

The vorssaint-utils repository delivers a powerful App Switcher feature through its Switcher service, offering macOS users a customizable alternative to the native Command-Tab interface. This Swift-based implementation supports multiple display modes, per-app rules, and robust event handling for seamless window navigation. Whether you need a compact icon bar or a full thumbnail grid, the Switcher service adapts to your workflow with extensive configuration options.

Core Window-Switching Capabilities

The Switcher service operates as the central orchestrator for the App Switcher feature, handling everything from window enumeration to UI rendering. At its core, AppSwitcher.swift manages the session lifecycle, while SwitcherView.swift renders the actual panel using SwiftUI.

The service supports two primary visual modes controlled by the iconRowMode and simpleMode settings. In Sources/Vorssaint/UI/Switcher/SwitcherView.swift, the body property (lines 56-64) automatically selects between iconRowPanel and standardPanel based on these user preferences. This allows the switcher to present either a compact horizontal row of application icons or a comprehensive grid showing live window thumbnails.

Panel Layout Modes: Icon-Row vs. Grid

Icon-Row Layout

The icon-row layout displays applications as a compact horizontal strip with configurable spacing and geometry. The SwitcherIconRowLayout.compute(...) method in Sources/Vorssaint/Services/Switcher/SwitcherSupport.swift (lines 79-106) calculates:

  • Visible icon count based on screen width
  • Panel dimensions and positioning
  • Horizontal spacing between icons
  • Whether shortcut hint overlays appear

This layout supports hover-edge behavior: when the cursor remains on the last visible icon, the row automatically scrolls after a configurable interval. The timing constants iconRowEdgeHoverInterval, iconRowEdgeHoverRepeatInterval, and iconRowEdgeHoverAnimationDuration in SwitcherSupport.swift (lines 72-86) control this interaction.

Grid Layout with Live Previews

The standard grid layout provides a visual overview of all open windows using captured thumbnails. The SwitcherGrid struct dynamically calculates rows and columns based on screen real estate and window count. Preview resolution is controlled by captureAlphaGridSize in SwitcherSupport.swift (lines 69-71), allowing performance tuning based on hardware capabilities.

Users can enable minimal-preview mode by setting the minimalPreviews AppStorage key, which disables the thin outline stroke around each thumbnail for a cleaner aesthetic (handled in SwitcherView.swift, lines 80-84).

Advanced Configuration Options

Screen Placement Control

The SwitcherScreenPlacement enum in SwitcherSupport.swift (lines 93-104) defines three positioning strategies:

  • Pointer screen: Opens on the display containing the cursor
  • Menu-bar screen: Opens on the primary display with the menu bar
  • Active window screen: Opens on the display containing the currently focused window

Appearance Delay

Users can configure the delay before the panel appears when holding the activation shortcut. The default value is stored in SwitcherSupport.defaultAppearanceDelayMilliseconds, with sanitizing helpers ensuring valid ranges (lines 33-38).

Session Scope Modes

The SwitcherSessionScope enum controls enumeration behavior:

  • allApps: Lists all applications with their windows
  • frontmostApp: Shows only windows belonging to the currently active application

Keyboard Shortcuts and Navigation

Global Shortcut Handling

The service intercepts system shortcuts using SwitcherNativeSymbolicHotKey (lines 48-60 in SwitcherSupport.swift), mapping hot-key IDs for:

  • command-tab and command-shift-tab navigation
  • Next/previous window selection
  • Optional takeover of native macOS shortcuts

Shortcut Hint Overlays

When enabled via showsShortcutHints, the panel displays visual indicators for available keyboard shortcuts. The SwitcherShortcutHints struct (lines 28-32) stores the hint strings rendered in the UI.

Letter Actions

While the panel is visible, specific key presses trigger SwitcherLetterAction behaviors:

  • W: Close the selected window
  • Q: Quit the selected application
  • S: Pin the search field

Search and Pinning

The switcher includes a real-time search field that filters the window list. The pinning feature (isSearchPinned) allows users to continue typing without holding the modifier key. In SwitcherView.swift (lines 24-32), a visual chip indicates the pinned state, and the searchQuery property drives the filtering logic.

Session Management and App Behavior

Windowless App Entries

The SwitcherWindowlessApps enum (lines 62-73) handles applications without open windows:

  • off: Hides windowless apps
  • finder: Shows only Finder when it has no windows
  • all: Displays all running apps regardless of window state

App-Specific Rules

Per-application overrides allow fine-grained control via the SwitcherAppRule enum (lines 17-27):

  • Force apps to appear without windows
  • Restrict apps to windows-only display
  • Hide specific applications entirely

Hidden App Tracking

The service maintains state for hidden applications across sessions using functions like isConfirmedHiddenAppWindow (demonstrated in MetricsTests.swift, lines 2769-2777), ensuring hidden apps reappear correctly in subsequent switching sessions.

Merge Tabs Option

When mergeWindowsByApp is enabled (stored in AppStorage and honored in SwitcherView.swift, lines 51-52), multiple windows from the same application collapse into a single selectable entry, reducing panel clutter.

Robust Concurrency Handling

AppSwitcher.swift (lines 21-46) implements thread-safe session management using SwitcherPendingKeyDecision and SwitcherPendingSessionStart enums with lock-protected state. This prevents race conditions during concurrent event-tap threads and ensures graceful cancellation when users release modifier keys before the panel appears.

Implementation Architecture

The Switcher service relies on several coordinated components:

Code Examples

Activating the Switcher Programmatically

import Vorssaint

// Access the shared singleton instance
let switcher = AppSwitcher.shared

// Start a session listing all applications
switcher.startSession(scope: .allApps, reversed: false)

// Navigate using Tab / Shift-Tab or arrow keys

Querying Window State

let windows = switcher.windows               // Array of SwitcherItem
let selected = switcher.selectedIndex        // Currently highlighted index
let totalCount = switcher.totalWindowCount   // Total window count

Configuring User Preferences

// Enable compact icon-row mode
UserDefaults.standard.set(true, forKey: DefaultsKey.switcherIconRowMode)

// Display shortcut hint overlays
UserDefaults.standard.set(true, forKey: DefaultsKey.switcherShowShortcutHints)

Customizing Appearance Timing

// Set 250ms delay before panel appears
UserDefaults.standard.set(250, forKey: DefaultsKey.switcherAppearanceDelay)

Defining App-Specific Rules

// Force Music app to appear even without windows
let rules: [String: SwitcherAppRule] = ["com.apple.Music": .showWithoutWindows]
UserDefaults.standard.set(SwitcherAppRule.storedValue(rules),
                          forKey: DefaultsKey.switcherAppRules)
// Close a specific window
if let window = switcher.windows.first {
    switcher.closeWindow(window)
}

// Pin the search field to release modifier key
switcher.isSearchPinned = true

Summary

  • The Switcher service provides dual layout modes (icon-row and grid) with automatic geometry calculations via SwitcherIconRowLayout.compute().
  • Configuration options include screen placement strategies, appearance delays, and session scopes (allApps vs frontmostApp).
  • Advanced features encompass windowless app entries, per-app override rules via SwitcherAppRule, and hidden app state preservation.
  • Navigation enhancements include global shortcut interception, letter actions (W for close, Q for quit), and a pinnable search field.
  • Thread-safe implementation uses SwitcherPendingKeyDecision and lock-protected state in AppSwitcher.swift to handle concurrent event taps safely.

Frequently Asked Questions

How does the Switcher service handle apps without open windows?

The service uses the SwitcherWindowlessApps enum defined in SwitcherSupport.swift to control visibility of windowless applications. You can configure it to hide all windowless apps, show only Finder, or display all running applications regardless of window state. This setting integrates with the Accessibility-based window enumeration performed by WindowEnumerator.swift.

What is the difference between icon-row mode and simple mode?

Icon-row mode displays a horizontal strip of application icons with optional shortcut hints and hover-edge scrolling. Simple mode (controlled by the simpleMode setting) further strips down the interface by hiding live previews entirely, showing only the icon bar. Simple mode is ideal for low-resource environments or users who prefer minimal visual overhead, as implemented in SwitcherView.swift lines 94-100.

Can I customize which keyboard shortcuts activate the switcher?

Yes. The SwitcherNativeSymbolicHotKey enum maps symbolic hot-key IDs that the service registers with the WindowServer. While the default implementation uses Command-Tab bindings, the architecture supports custom shortcut takeovers. The AppSwitcher.swift class handles the global event tap and translates these into startSession calls with appropriate reversed parameters for backward navigation.

How does the search pinning feature work?

When you press the S key while the switcher is visible (as defined in SwitcherLetterAction), the isSearchPinned boolean toggles to true. This allows you to release the modifier key while continuing to type your search query. The UI displays a visual chip indicating the pinned state, and the searchQuery property filters the windows array in real-time without requiring held keys.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →