Repository navigation
How it works
Nothing on the real menu bar is moved or modified. The app asks macOS to show only an allow-list of apps, reads item lists through Accessibility, and copies menus.
macOS 27's MenuBarAgent has a private "assessment mode" in MenuBarClientCore (MBAssessmentModeConfiguration / MBAssessmentModeAssertion). While a process holds an assertion, the bar shows only the allowed bundles plus system items. The assertion ends on invalidate or when the process exits.
SmartHiddenBar builds the allow-list from where each app's item sits relative to its own icon:
-
allowed: SmartHiddenBar itself, the system owners (
com.apple.MenuBarAgent,com.apple.controlcenter,com.apple.systemuiserver), every app with an item right of the icon's midpoint, and parked apps never seen left of the icon; - denied (hidden): every app with an item left of the icon.
So hiding is per app, not per icon. The list is re-evaluated when apps launch or quit, after wake or a display change, and by a 5 second poll (which also catches items an already-running app adds).
Safety valves:
- Quitting, Disable SmartHiddenBar, or Show items, releases the assertion and the full bar returns.
- If the app's own icon ends up parked or missing, it releases the allow-list rather than leave nothing to click.
- If activation fails, it stays shown and stops retrying until you click again.
- If the private API is missing, an alert says hiding isn't available on this macOS and everything stays visible. The approach cannot catch an Objective-C exception from a changed private API; it checks the classes and selectors up front.
MenuBarAgent resolves allow-listed bundle ids through LaunchServices, which picks the copy in /Applications. A copy running from anywhere else never matches, so the allow-list hides its own icon. At launch the app compares its path with what LaunchServices resolves for its bundle id and quits with a message if they differ.
For every running app the app reads the AXExtrasMenuBar accessibility element and its children. MenuBarAgent wraps the real item in an action-less group, so the code unwraps to the child that has actions. For each item it records the app, position, size and its index within the app's items (stable while hidden, unlike x).
An item counts as off the bar when it is left of the notch, overlaps its right-hand neighbour past its midpoint (macOS stacks overflow items there), or is parked off the bar (macOS 27 moves items it hides to about (0, screen bottom)). This runs off the main thread, because the app's own item is answered by the main thread.
- Press the real item through Accessibility and wait for its menu (static menus that are readable while closed are copied with no press at all).
- Copy the AX menu tree into an
NSMenu; each row remembers its index path. - Close the real menu by posting Escape to that app's own event queue.
- Pop the copy up under SmartHiddenBar's icon.
- On a pick, reopen the real menu, follow the same path, and press the row, only if its title still matches.
Limitation: a mirrored menu is a snapshot; titles that change while it is open may be stale.
With Screen Recording and Real menu bar icons selected, the app takes one display capture of the menu bar strip (ScreenCaptureKit) and crops each visible item out of it. Captures happen at launch and shortly after items are shown. They are cached per bundle id, item index and bar brightness (light or dark, measured from the strip), and fall back to the app icon.
Things the code works around:
- Status-item clicks carry no modifier flags or click count, so ⌥ is read from the current modifier state. There is no double click: clicks act at once. Our icon is drawn by MenuBarAgent, so a click on it first reaches the app's global "click outside" monitor; a bar closed less than 0.5 s earlier counts as still open.
- Assessment mode blocks Notification Center even when
com.apple.notificationcenteruiis allowed, so a click on the clock (com.apple.menuextra.clock, found by AX hit test) releases the allow-list until Notification Center has no on-screen window. - There are no per-item status windows: the bar is one "Menubar" window, so icons are cropped from a display capture and include the bar's wallpaper tint.
- Hidden items are parked near (0, screen bottom), not removed; Accessibility keeps reporting items at their old frames while they are hidden.
- The allow-list matches a bundle id only for an app in
/Applications(via LaunchServices); a copy elsewhere is never "allowed". A new item created under the list is placed by the next list that includes it, within about a second. - Apps switched off in System Settings → Menu Bar → "Allow in the Menu Bar" are parked by MenuBarAgent at creation, whatever the allow-list says.
- Menu item images are hidden by default, so mirrored rows set image visibility explicitly.
- Closed status menus stay in the AX tree at size 0×0, so "open" means "has a size".
- A menu press blocks until the menu closes, so Accessibility messaging timeouts are shortened.
- Allow-list activation needs
NSArrays for both system ids and bundle ids; unknown system ids are ignored.
See Architecture for the file map.
SmartHiddenBar · MIT © Roy Padina · More Mac apps · Support on Ko-fi ☕