# How Vorssaint Implements Per-App Window Grouping in Its Switcher

> Learn how Vorssaint implements per-app window grouping by consolidating windows by process ID and using the most visible for thumbnails. Discover the code in vorssaint-utils.

- Repository: [vorssaint/vorssaint-utils](https://github.com/vorssaint/vorssaint-utils)
- Tags: internals
- Published: 2026-09-06

---

**Vorssaint implements per-app window grouping by collapsing all windows sharing the same process ID into a single representative entry, selecting the most visible window as the thumbnail while preserving the full window list for downstream UI components.**

Vorssaint's app switcher in the `vorssaint/vorssaint-utils` repository supports both window-level and application-level navigation modes. When enabled, per-app window grouping consolidates multiple windows from the same application into one switcher icon, simplifying the interface while maintaining full access to individual window metadata for previews and keyboard shortcuts.

## Configuration Settings That Control Grouping

Grouping behavior is governed by a combination of user preferences and per-application rules defined in [`Sources/Vorssaint/Services/Switcher/SwitcherSupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Services/Switcher/SwitcherSupport.swift).

**SwitcherAppRule** provides per-app overrides that force specific applications to appear with or without windows, or to be hidden entirely. These rules are evaluated during enumeration to determine eligibility for grouping (lines 17‑23).

**SwitcherWindowlessApps** controls whether apps without visible windows—such as Finder—remain listed in the switcher. This setting interacts with the grouping logic to ensure windowless applications do not create empty groups (lines 62‑71).

The boolean preference `mergeWindowsByApp` (exposed through the Switcher preferences panel) serves as the master toggle. When `true`, the `WindowEnumerator` applies the grouping algorithm; when `false`, each window receives its own switcher entry.

## Enumerating Windows with Grouping Support

The primary entry point for window discovery is `WindowEnumerator.enumerateSwitchableWindows`. During enumeration, the system collects all windows and filters them based on visibility, minimization status, and fullscreen state.

If `mergeWindowsByApp` is enabled and the caller requests preservation of grouped data (`preservingGroupedWindows == true`), the enumerator stores the filtered list for later expansion:

```swift
let groupedBackingWindows = groupByApp && preservingGroupedWindows ? filtered : []

```

*Source:* [`Sources/Vorssaint/Services/Switcher/WindowEnumerator.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Services/Switcher/WindowEnumerator.swift) (lines 65‑66)

The enumerator then branches based on the grouping flag:

```swift
let ordered = groupByApp ? groupWindowsByApp(orderedRaw) : orderedRaw

```

*Source:* [`Sources/Vorssaint/Services/Switcher/WindowEnumerator.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Services/Switcher/WindowEnumerator.swift) (lines 77‑78)

## The Core Grouping Algorithm

The static helper `groupWindowsByApp(_:)` performs the actual deduplication by walking the ordered window array and building a compact list where each **PID** appears exactly once.

```swift
private static func groupWindowsByApp(_ windows: [SwitcherItem]) -> [SwitcherItem] {
    var indexByPid: [pid_t: Int] = [:]
    var grouped: [SwitcherItem] = []
    for window in windows {
        if let index = indexByPid[window.pid] {
            // Keep the most "visible" window as the representative
            if (window.isOnScreen && !grouped[index].isOnScreen) ||
               (window.isFullscreen && !grouped[index].isFullscreen) {
                grouped[index] = window
            }
        } else {
            indexByPid[window.pid] = grouped.count
            grouped.append(window)
        }
    }
    return grouped
}

```

*Source:* [`Sources/Vorssaint/Services/Switcher/WindowEnumerator.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Services/Switcher/WindowEnumerator.swift) (lines 945‑960)

**Key implementation details:**

- **PID-based deduplication** – A dictionary (`indexByPid`) tracks the first occurrence of each process ID.
- **Visibility hierarchy** – If a later window is on-screen or fullscreen while the current representative is off-screen, the more visible window replaces it as the representative. This ensures the switcher thumbnail always reflects the window the user expects to see.

## Re-expanding Groups for Simple Mode

When the switcher operates in "simple" mode, the UI displays one icon per application but still requires the full list of windows to render title chips and handle keyboard shortcuts. To support this, the enumerator expands the grouped list back into a fully populated window list **only for the visible applications**:

```swift
result = SwitcherSupport.expandGroupedWindows(
    orderedWindows: backingOrdered,
    representatives: result)

```

*Source:* [`Sources/Vorssaint/Services/Switcher/WindowEnumerator.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Services/Switcher/WindowEnumerator.swift) (lines 99‑103)

The helper `SwitcherSupport.expandGroupedWindows` iterates through the representatives and re-injects the remaining windows for each application in most-recently-used (MRU) order.

*Source:* [`Sources/Vorssaint/Services/Switcher/SwitcherSupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Services/Switcher/SwitcherSupport.swift) (lines 224‑231)

## Building the App Group Model for the View Layer

The view layer consumes grouped data through `SwitcherSupport.appGroups(items:)`, which transforms the flat window list into an array of **`SwitcherAppGroup`** objects (one per PID):

```swift
static func appGroups(items: [SwitcherItem]) -> [SwitcherAppGroup] {
    var seen: Set<pid_t> = []
    var groups: [SwitcherAppGroup] = []
    for (index, item) in items.enumerated() where !seen.contains(item.pid) {
        seen.insert(item.pid)
        groups.append(SwitcherAppGroup(pid: item.pid,
                                       appName: item.appName,
                                       representativeIndex: index,
                                       itemIDs: items.filter { $0.pid == item.pid }.map(\.id)))
    }
    return groups
}

```

*Source:* [`Sources/Vorssaint/Services/Switcher/SwitcherSupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Services/Switcher/SwitcherSupport.swift) (lines 49‑59)

`SwitcherView` (lines 57‑71) reads these groups to compute preview placement, layout the icon row, and render per-app title chips beneath each grouped icon.

## Summary

- **Master toggle:** The `mergeWindowsByApp` user default enables or disables per-app window grouping across the entire switcher.
- **Deduplication logic:** `WindowEnumerator.groupWindowsByApp` collapses windows by PID, using an on-screen visibility heuristic to select the best representative thumbnail.
- **Data preservation:** When grouping is active, the filtered window list is stored in `groupedBackingWindows` to support "simple" mode expansion via `SwitcherSupport.expandGroupedWindows`.
- **UI abstraction:** `SwitcherSupport.appGroups` converts the flat window array into `SwitcherAppGroup` objects, allowing `SwitcherView` to render one icon per application while retaining access to all underlying window IDs.

## Frequently Asked Questions

### How does Vorssaint decide which window represents a grouped app?

Vorssaint selects the representative window based on visibility hierarchy within the `groupWindowsByApp` function. If multiple windows exist for the same PID, the algorithm prefers windows that are currently on-screen over off-screen ones, and fullscreen windows over non-fullscreen ones. This ensures the switcher thumbnail matches the user's current context.

### What happens to hidden windows when grouping is enabled?

Hidden windows are not discarded; they are preserved in `groupedBackingWindows` when the `preservingGroupedWindows` flag is set. For simple mode layouts, `SwitcherSupport.expandGroupedWindows` re-injects these hidden windows back into the result set so the UI can still access them for title chips and keyboard shortcuts, even though only one icon appears per app.

### Can users disable per-app grouping entirely?

Yes. Users can disable grouping by setting the `mergeWindowsByApp` preference to `false` in the Switcher preferences panel. Additionally, per-application overrides via `SwitcherAppRule` (defined in [`SwitcherSupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/SwitcherSupport.swift)) can force specific apps to always show individual windows regardless of the global setting.

### Where is the grouping logic located in the codebase?

The core grouping algorithm resides in [`Sources/Vorssaint/Services/Switcher/WindowEnumerator.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Services/Switcher/WindowEnumerator.swift) (lines 945‑960). Supporting utilities—including expansion logic and app group construction—are implemented in [`Sources/Vorssaint/Services/Switcher/SwitcherSupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Services/Switcher/SwitcherSupport.swift). The UI consumption of grouped data occurs in [`Sources/Vorssaint/UI/Switcher/SwitcherView.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/UI/Switcher/SwitcherView.swift) (lines 57‑71).