DEV Community

zhengsihua
zhengsihua

Posted on AI-assisted

Designing a window-first macOS switcher in Swift

With two browser windows open, macOS still gives me one browser icon in Command-Tab. That is enough to select the application, but my next action usually concerns a particular window: the documentation, the page I am editing, or the terminal beside it.

I maintain Open Contexts, a free, open-source Mac window switcher.

I had been using Contexts because its window list and edge sidebar matched this workflow. Concerns about its future compatibility led me to rebuild the parts I relied on. Open Contexts uses Swift, AppKit, and SwiftUI, and adds saved custom window groups.

The useful design question is what a switcher should remember about a window, and what the user should be able to expect from that memory.

Put the window in the selection model

A window-first switcher needs to distinguish several windows belonging to the same app. An app icon remains useful, but the window title provides the information needed to make a selection.

Open Contexts lists individual windows in most recently used order. Each item includes the app name, icon, and window title. The default interaction keeps a familiar rhythm: hold Command, press Tab to move through the list, and release Command to activate the selected window. Arrow keys, reverse switching, and Escape provide other ways to navigate or cancel.

window switcher

Replacing a familiar global shortcut creates an expectation about when the replacement is active. The current app requires Accessibility permission before it takes over Command-Tab. Closing the app or running it without that permission leaves the system shortcut in place. Both the all-window and current-app shortcuts can be changed in Settings.

That gives a developer a concrete interaction contract to document: the trigger, the item being selected, the confirmation action, and the conditions under which the shortcut is intercepted.

Keep recent order and task order separate

Recent order answers which window I used a moment ago. A custom group answers which windows belong to a task. Those are useful for different reasons.

For example, a coding task might involve an editor, a terminal, and browser documentation. Grouping only by application would split that task across several sections. A cross-app group can keep those windows together in the sidebar while the keyboard switcher continues to serve rapid recent-window navigation.

Open Contexts lets users create and rename groups, drag windows between groups, and pin a window's position in its group. Pinning preserves its list position during automatic updates; it does not pin a desktop window to a particular screen coordinate.

This distinction is easy to lose in feature copy. “Saved groups” describes an organization feature. It should not suggest that opening a group will launch applications, reopen documents, or restore a desktop layout.

Persistence needs a matching rule

The project's documented state file is ~/Library/Application Support/OpenContexts/groups.json. It retains group information and expected positions for windows that can be restored to the list.

The matching rule matters more than the existence of the file. According to the current project documentation, Open Contexts first matches a window using the application identifier and document URL, then falls back to its title when no document URL is available. Windows without enough identifying information can remain usable in the current session without becoming reliable saved records.

There are two practical consequences. A group name and its order can persist even when some windows cannot be matched after a restart. Also, a saved entry represents a place in a list; it does not guarantee that a corresponding desktop window exists.

For anyone building a similar tool, this is a useful boundary to specify before promising “restore.” Describe which records can be recognized, what happens to ambiguous records, and whether the operation changes organization, application state, or screen geometry.

Search belongs inside the switching interaction

The original Chinese article predates the search feature. Current Open Contexts supports filtering by app name and window title while the shortcut modifier remains held. Releasing it activates the selected result.

Search is case-insensitive and currently accepts printable ASCII. Chinese input and pinyin are not supported. If nothing matches, releasing the modifier dismisses the switcher without activating a different window.

The no-match behavior is part of the interaction contract too. A failed query should leave the user aware that no new target was selected.

Make the limits inspectable

Open Contexts is free under Apache 2.0, with no account or subscription. The current documentation declares macOS 13 or later as the minimum target, while noting that macOS 13 has not been verified on physical hardware. Trackpad switching gestures are not supported, and full-screen behavior needs more real-world verification.

These boundaries are useful information for contributors and users deciding whether to try the app. They are also more actionable than a broad claim that a replacement recreates every behavior of the original utility.

The source and documentation are available to inspect, and the website includes an interactive demo. If you build tools around application windows, I would be interested in how you handle window identity when documents are untitled or titles change.

Top comments (0)