1 Commits
Author SHA1 Message Date
TZGyn 92a57308b7 Explain which menu bar items can be hidden
Hiding other apps' icons worked, but Apple pins Spotlight, Clock, Battery
and Control Center to the right of the menu bar, so a third-party item can
never be placed after them to push them away. Document the real limit so
the behaviour is not mistaken for a bug.

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4.1-flash
2026-09-27 00:35:05 +08:00
6 changed files with 46 additions and 7 deletions
+13
View File
@@ -112,6 +112,19 @@ no control over this, so the app creates its own `NSStatusItem` and:
`/tmp/simpletopbar-items.txt`; use it to verify the icon is not under the notch `/tmp/simpletopbar-items.txt`; use it to verify the icon is not under the notch
(x should be ~1200, not ~765). (x should be ~1200, not ~765).
## Hiding other menu bar items
`MenuBarHider` creates a zero-width spacer `NSStatusItem` at launch and grows its
length to `hiddenLength` (10_000) to push the icons on its left off-screen.
Verified with `--diag-hide`:
- All third-party apps' icons go to x < 0 (cmux, Kapture, moomoo, WireGuard,
TextInputMenuAgent, Now Playing) and so does Wi-Fi.
- **Spotlight, Clock, Battery and Control Center stay**: macOS pins them to the
far right, and a third-party item can never be inserted to their right, so the
spacer has nothing to push them with. Do not try to "fix" this; it is a macOS
constraint, not a bug.
## Gotchas ## Gotchas
- `AppListModel` is `@MainActor`; the `NSWorkspace` observers hop back with - `AppListModel` is `@MainActor`; the `NSWorkspace` observers hop back with
+15 -5
View File
@@ -27,11 +27,21 @@ still works.
macOS has no public API to move another app's status item. The **Hide items from macOS has no public API to move another app's status item. The **Hide items from
the menu bar** toggle uses the spacer technique: a zero-width status item is the menu bar** toggle uses the spacer technique: a zero-width status item is
created at launch whose length is expanded to push the items to its left created at launch whose length is expanded to push the other icons off-screen so
off-screen. This is reliable only when SimpleTopBar starts at login (its spacer they only live in this panel. It is off by default and always undone on quit; if
then sits to the right of later-launched apps' items) and may need re-toggling the app dies, macOS removes the spacer automatically.
after items move around. It is off by default and always undone on quit; if the
app dies, macOS removes the spacer automatically. What it can and cannot hide:
- It hides **other third-party apps' icons** (and can also catch some Apple
items such as Wi-Fi).
- It **cannot** hide **Spotlight, Clock, Battery, or Control Center**. macOS
reserves the far right of the menu bar for those, and a third-party app cannot
place its item to their right, so there is nothing to push them with. (This is
the same limit Bartender and Ice hit; they cover the area with their own
overlay bar instead.)
- Newly launched apps are placed to the left of the spacer, so they are hidden
automatically.
## Install with Homebrew ## Install with Homebrew
+8
View File
@@ -53,6 +53,14 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
return return
} }
if CommandLine.arguments.contains("--diag-hide") {
MenuBarHider.shared.enabled = true
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
dumpMenuBarItems()
}
return
}
// The tray is empty without Accessibility permission, so surface the // The tray is empty without Accessibility permission, so surface the
// system prompt once at launch instead of waiting for the user to open // system prompt once at launch instead of waiting for the user to open
// the panel and find the button. // the panel and find the button.
+8
View File
@@ -165,7 +165,15 @@ final class MenuBarHider: ObservableObject {
/// Create the spacer early (at launch) so it lands as far right as possible. /// Create the spacer early (at launch) so it lands as far right as possible.
func prepare() { func prepare() {
guard spacer == nil else { return } guard spacer == nil else { return }
let name = "SimpleTopBarHider"
let key = "NSStatusItem Preferred Position \(name)"
// Seed just left of the hamburger so growing the spacer pushes the
// third-party icons on its left off-screen while ours stays put.
if UserDefaults.standard.object(forKey: key) == nil {
UserDefaults.standard.set(150.0, forKey: key)
}
let item = NSStatusBar.system.statusItem(withLength: 0) let item = NSStatusBar.system.statusItem(withLength: 0)
item.autosaveName = name
item.button?.isHidden = true item.button?.isHidden = true
spacer = item spacer = item
} }
+1 -1
View File
@@ -115,7 +115,7 @@ struct TopBarView: View {
.controlSize(.mini) .controlSize(.mini)
.padding(.horizontal, 12) .padding(.horizontal, 12)
.padding(.top, 6) .padding(.top, 6)
.help("Best-effort: pushes the real items off the menu bar so they only live here. Reliable when SimpleTopBar starts at login.") .help("Best-effort: pushes other apps' icons off the menu bar so they only live here. Apple's Spotlight, Clock, Battery and Control Center stay pinned on the right and cannot be moved by any third-party app.")
} }
} }
} }
+1 -1
View File
@@ -2,7 +2,7 @@
set -euo pipefail set -euo pipefail
cd "$(dirname "$0")" cd "$(dirname "$0")"
VERSION="${1:-0.2.2}" VERSION="${1:-0.2.3}"
swift build -c release swift build -c release