Skip to content

Add menu-bar-item config option to hide the menu bar item - #2241

Open
christophervalles wants to merge 1 commit into
nikitabobko:mainfrom
christophervalles:menu-bar-item
Open

Add menu-bar-item config option to hide the menu bar item#2241
christophervalles wants to merge 1 commit into
nikitabobko:mainfrom
christophervalles:menu-bar-item

Conversation

@christophervalles

Copy link
Copy Markdown

Summary

AeroSpace always shows its own item in the macOS menu bar (the per-monitor workspace readout, e.g. 1 │ 2 │ *3). Users who already run a separate workspace indicator — SketchyBar, a waybar-style bar, etc. — end up with a duplicate they can't turn off from config.

This adds an opt-in config option to hide it:

menu-bar-item = true   # default, unchanged
menu-bar-item = false  # remove AeroSpace's menu bar item entirely

How it works

  • New top-level menu-bar-item bool on Config (default true), parsed with the existing parseBool.
  • TrayMenuModel gets a @Published var menuBarItemIsShown, which updateTrayText() keeps in sync with config.menuBarItem.
  • The MenuBarExtra scene is created with the isInserted: initializer bound to menuBarItemIsShown. Setting it false removes the item from the menu bar entirely.

Because updateTrayText() runs on every session refresh, the item appears/disappears live on reload-config — no relaunch needed.

Default is true, so behavior is unchanged unless the option is opted into.

Test plan

  • swift build — clean.
  • swift test — all pass, incl. a new testParseMenuBarItem (default true, parses true/false, rejects a non-bool).
  • ./lint.sh — SwiftFormat clean, no unused code.
  • Manually: with menu-bar-item = false, AeroSpace's menu bar item is gone; toggling back to true + reload-config brings it back without relaunch.

Files

  • Sources/AppBundle/config/Config.swift — the config field
  • Sources/AppBundle/config/parseConfig.swift — registry entry
  • Sources/AppBundle/ui/TrayMenuModel.swift — published flag + sync in updateTrayText
  • Sources/AppBundle/ui/MenuBar.swiftMenuBarExtra(isInserted:)
  • Sources/AppBundleTests/config/ConfigTest.swifttestParseMenuBarItem
  • docs/config-examples/default-config.toml — documented default

@github-actions github-actions Bot added the not-actionable By default, all PRs have this label. If the PR makes sense, the label will be removed. label Aug 24, 2026
AeroSpace's MenuBarExtra is the app's only SwiftUI scene. Removing it
(e.g. via MenuBarExtra(isInserted:)) leaves the App with no active scene,
which the system terminates — even for an LSUIElement agent app. So the
menu bar item can't be removed outright.

Instead, 'menu-bar-item = false' keeps the scene present and collapses the
label to a single compact icon (square.split.2x2) in place of the workspace
readout. This is for users who run their own workspace indicator (SketchyBar,
etc.) and don't want the duplicate. Defaults to true (unchanged behavior).

TrayMenuModel.menuBarItemIsShown mirrors config.menuBarItem and is updated in
updateTrayText (guarded to avoid a redundant @published republish on every
refresh).
@christophervalles

Copy link
Copy Markdown
Author

Revised the implementation. The original approach used MenuBarExtra(isInserted:) to remove the item entirely, but that turns out to be broken: MenuBarExtra is AeroSpace's only SwiftUI scene, so setting isInserted = false leaves the App with no active scene and the system terminates the process (confirmed on macOS 26, even though AeroSpace is an LSUIElement agent; an invisible Settings/Window keep-alive scene does not prevent it either). It also caused a 100% CPU render loop because the binding's setter wrote to an @Published property unconditionally.

So a full removal isn't achievable while MenuBarExtra is the sole scene. Instead, menu-bar-item = false now keeps the scene present and collapses the label to a single compact icon (square.split.2x2) in place of the workspace readout — the minimal footprint for users who run their own indicator (SketchyBar, etc.). Default remains true (unchanged behavior). Happy to adjust the glyph or the config semantics if you'd prefer a different framing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

not-actionable By default, all PRs have this label. If the PR makes sense, the label will be removed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant