# Architecture Hidden Bar is a single-process, sandboxed AppKit menubar utility (~1.5k lines of Swift, one dependency: [HotKey](https://github.com/soffes/HotKey)). There is no helper app, no daemon, no network. Everything happens inside three `NSStatusItem`s and one window. ## The core trick macOS offers no API to hide other apps' menubar icons. Hidden Bar fakes it with geometry: a separator status item whose **length is inflated to roughly the width of the widest attached screen**, shoving every icon to its left off-screen. Collapsing and expanding is just flipping that length between ~20pt and the inflated value. ```mermaid flowchart LR subgraph menubar [menu bar, right to left] direction RL ARROW["arrow item\n(toggle, variable length)"] SEP["separator item\n20pt expanded / ~2x screen width collapsed"] HIDDEN["other apps' icons\npushed off-screen when collapsed"] ALWAYS["always-hidden separator\n(optional)"] end ARROW --- SEP --- HIDDEN --- ALWAYS ``` Key consequences of this design: - The menubar replicates on every display, so the collapse length derives from the **widest** screen (`NSScreen.screens`), never `NSScreen.main`, and is re-applied to the live item on `didChangeScreenParametersNotification` (display hot-plug). - The length is bounded: `max(500, min(widestFrameWidth * 2, 10_000))`. macOS enforces a hard 10,000pt maximum on `NSStatusItem.length`. - `isCollapsed` is derived state: `separator.length > 20`, deliberately not an equality check, so it survives the length being recomputed while collapsed. - Icons macOS inserts to the LEFT of the separator (where new status items appear) are in the hidden zone by default; that is inherent to the trick. ## Topology ```mermaid flowchart TD AD[AppDelegate] -->|owns| SBC[StatusBarController] AD -->|registers| SM["SMAppService.mainApp\n(login item, macOS 13+)"] AD -->|global hotkey| HK[HotKey lib] SBC -->|3 status items| NSB[NSStatusBar.system] SBC -->|auto-hide| T["one-shot Timer\n(re-arms while pointer in menubar)"] SBC -->|opt-in| HM["global mouseMoved monitor\n(hover-to-expand, only if pref on)"] PREFS[Preferences facade] -->|UserDefaults| UD[(UserDefaults)] PREFS -->|posts| NC{{NotificationCenter\n.prefsChanged / .alwayHideToggle}} NC --> SBC PVC[PreferencesViewController] --> PREFS SBC -->|context menu| PVC ``` - **`AppDelegate`** (entry): registers default prefs, sets up the global hotkey, runs the one-shot legacy login-item migration, owns the `StatusBarController`. - **`StatusBarController`** (the product, ~370 lines): the three status items, when to collapse/expand, auto-hide timer, interaction-awareness, hover-to-expand, self-restore of dragged-off items. - **`MenuBarEngine`** (`Features/StatusBar/Engine/`): how hiding is achieved. The controller calls `collapse` / `expand` / `updateAlwaysHiddenSection` / `invalidateLayout` and never writes a status-item length itself. `MenuBarEngineFactory` is the one place that picks an engine for the running OS; today that is always `LegacyLengthEngine` (the length trick below). - **`Preferences`** (facade enum): typed accessors over `UserDefaults`; setters post `NotificationCenter` notifications that the controller and prefs window observe. There is no other state store. - **`PreferencesViewController` / `PreferencesWindowController`**: the only window (storyboard-based), shown on demand from the context menu. ## Behavior layers on the core trick | Layer | Mechanism | Cost when unused | |---|---|---| | Auto-hide | one-shot `Timer` after expand; at fire, if the pointer sits in any screen's menubar band (`visibleFrame.maxY ... frame.maxY`), it re-arms instead of collapsing | none (single point-in-rect check at fire) | | Hover-to-expand (opt-in) | global `.mouseMoved` monitor + 0.5s dwell timer; installed only when the `hoverToExpand` default is true at launch | zero: monitor not installed | | Self-restore | `isVisible = true` forced on our items at launch; Cmd-dragging them off otherwise bricks the app (its only UI is those items) | none | | Always-hidden section | a second separator item; its own length games, gated by `alwaysHiddenSectionEnabled` | item not created | ## Autostart macOS 13+ `SMAppService.mainApp`: the app registers itself; the login item is visible and revocable in System Settings > General > Login Items. On first launch after upgrade, a one-shot migration deauthorizes the legacy `com.dwarvesv.LauncherApplication` helper registration (the BTM database never garbage-collects those; see Apple TN3111). The helper app itself is gone. ## Security posture Sandboxed (`com.apple.security.app-sandbox`), hardened runtime, no network entitlement, no file I/O, no IPC surface, no shell or subprocess use. The only dependency is HotKey (a small Carbon `RegisterEventHotKey` wrapper) locked by the committed `Package.resolved`. The opt-in hover monitor observes pointer position only and discards event payloads. About-window links are hardcoded. A full-tree audit (2026-06) scored 9/10 with hygiene-level findings only. ## Known architectural limits - **The notch**: hidden icons sit "under" the notch area on notched Macs; the trick cannot reveal them there. The real fix is a spillover/second-bar design (tracked in issues #357/#341/#148; candidate implementations in PRs #350/#358). - **macOS 27**: the menu bar re-architecture in macOS 27 betas (`NSMenuBarNavigationSceneExtension`) breaks length-inflation hiding entirely (issue #360). A different mechanism may be required. - **Other apps' open menus**: interaction-awareness is pointer-position-based; a pointer deep inside another app's open dropdown is below the menubar band, so the collapse can still fire there.