Skip to content

fix: prevent multiple instances of Hidden Bar from running simultaneously#376

Open
bunnysayzz wants to merge 18 commits into
dwarvesf:masterfrom
bunnysayzz:develop
Open

fix: prevent multiple instances of Hidden Bar from running simultaneously#376
bunnysayzz wants to merge 18 commits into
dwarvesf:masterfrom
bunnysayzz:develop

Conversation

@bunnysayzz

Copy link
Copy Markdown

Hidden Bar didn't prevent multiple instances from running — launching it again would spin up a whole new copy instead of switching to the existing one. On a menu bar utility this is especially confusing since there's no visible window.

Added an early check in applicationDidFinishLaunching that scans NSWorkspace.shared.runningApplications for another instance with the same bundle ID. If found, it activates the existing instance and terminates the new one.

Addresses #324.

tieubao and others added 18 commits June 12, 2026 03:32
- bump MACOSX_DEPLOYMENT_TARGET to 13.0 on all configurations (was 10.12/10.14, unbuildable against HotKey's 10.13 floor on current Xcode)
- autostart now registers the main app via SMAppService.mainApp (login item appears in System Settings); replaces deprecated SMLoginItemSetEnabled + helper-app pattern (closes dwarvesf#338, dwarvesf#282 class of issues)
- one-shot launch migration deauthorizes the legacy LauncherApplication BTM record for upgrading users (BTM never garbage-collects it, TN3111)
- delete LauncherApplication target, sources (~4.1k lines), embed copy phase, build configs, leftover shared scheme, and the killLauncher distributed-notification dance
- drop dead #available(OSX 10.14) guards after the floor bump
- weak-self closure cleanups in StatusBarController
- ignore local agent tooling layer
- updateCollapsedLengths now derives from the widest attached screen instead of NSScreen.main; the menubar replicates across displays, so sizing from the focused screen leaked hidden icons on wider monitors (dwarvesf#345 dwarvesf#348 dwarvesf#298 dwarvesf#314 dwarvesf#353, 26.4 symptom in dwarvesf#351). Cap 4000 -> 6000 to cover 5K2K ultrawides.
- status items force isVisible=true at launch (and on always-hidden recreation): Cmd-dragging them off persisted via autosaveName and left the app unreachable (dwarvesf#359 dwarvesf#340 dwarvesf#285 dwarvesf#208); the controls are the app's only UI so they self-restore.
- dock-icon cluster (dwarvesf#311 dwarvesf#192 dwarvesf#152) confirmed by-design: LSUIElement already true, icon appears only via the use-full-status-bar pref. No code change.
At timer fire, if the pointer sits in any screen's menubar band (visibleFrame.maxY to frame.maxY, exact menubar height incl. notch) the collapse defers and the timer re-arms; the countdown resumes once the pointer leaves. No global monitor, no polling: one point-in-rect check per fire. Closes the interaction cluster (dwarvesf#237 dwarvesf#331 dwarvesf#186 dwarvesf#66 dwarvesf#151 dwarvesf#195 dwarvesf#317; menu-dropdown case partially covered, see implementation notes).
With defaults write com.dwarvesv.minimalbar hoverToExpand -bool true, a ~0.5s pointer dwell in any menubar band expands the collapsed bar; auto-hide then behaves normally. Default off and fully inert: the global mouseMoved monitor is only installed when the pref is true at launch. Closes dwarvesf#235 dwarvesf#123 dwarvesf#90 functionally; prefs-window checkbox is a recorded follow-up.
- the always-hidden tutorial used SF Symbols private-use glyphs (command, chevron, bar) in 7 locale tables; they render as tofu in plain-text contexts (dwarvesf#301, dwarvesf#297). Replaced with U+2318, <, and |. All tables plutil-lint clean.
- global-shortcut display rendered F-keys as Fn18; keyCode-mapped F1-F20 names now render F18 etc., genuine fn-modifier combos keep the Fn prefix (dwarvesf#191). Dropped a stray print(keyCode) in the same property.
- dwarvesf#287 receipted as macOS per-app language setting (no code defect).
Settings were only reachable via the separator's menu, which most users never click. Right-click on the expand/collapse arrow now pops the same shared menu (dwarvesf#356); left-click toggle is unchanged and the separators/always-hidden toggle stays on option-click.
Invalidate a pending hover dwell timer in deinit (defensive; controller is app-lifetime today) and document three intent points the review flagged: the unbounded-by-design timer re-arm, the fullscreen zero-height band, and option+right-click landing on the separators toggle. Review verdict SHIP 8/10.
Absorbs the still-relevant pieces of three community PRs that overlapped this branch, with authorship credit:

- collapse length re-applies to the live separator when displays change, and isCollapsed compares > btnHiddenLength so the state survives the recompute; collapse sizing uses frame.width x2 capped at the documented 10,000pt NSStatusItem maximum (from dwarvesf#354)
- NSLayoutConstraint.deactivate before removeFromSuperview in removeAllSubViews, plugging the tutorial-view rebuild leak (from dwarvesf#335)
- PreferencesViewController balances its prefsChanged observer in deinit (from dwarvesf#335/dwarvesf#346)

Co-authored-by: Laveez <niko.muukkonen1@gmail.com>
Co-authored-by: huynguyenh <hoanghuy2908@gmail.com>
Co-authored-by: Rob Mulder <hallo@robmulder.com>
Backfills the operating documentation for the modernized app:

- docs/ARCHITECTURE.md: the length-inflation mechanism, status-item topology (mermaid), behavior layers, autostart path, security posture, and the honest list of architectural limits (notch, macOS 27, open-menu detection)
- docs/MANUAL.md: every setting incl. the Terminal-only defaults keys (hoverToExpand, arbitrary auto-hide delay, AppleLanguages) and troubleshooting
- docs/RUNBOOK.md: build commands, the AX-size-based behavioral verification methodology, release sequence (notarization, MAS lag, cask), stacked-PR hygiene
- README links the three docs

Accuracy gated by an adversarial doc-vs-code verification pass (3 corrections applied); a full-tree security audit (SECURE, 9/10) accompanies the batch, its four hygiene findings tracked for a follow-up commit.
Security-hygiene pass from the full-tree audit (no behavior change):
- Pin HotKey to exactVersion 0.1.3 (was upToNextMajor) to stop supply-chain drift.
- Remove the unused com.apple.security.files.user-selected.read-only entitlement
  (no open/save panels exist in the app).
- Delete orphan EventMonitor.swift (unreferenced, not in the project, never compiled).
- Remove the UserDefaults observeValue override that only printed "hi!" and
  swallowed all KVO callbacks.
The icon-order cluster (dwarvesf#28 dwarvesf#107 dwarvesf#156 dwarvesf#181 dwarvesf#233 dwarvesf#239 dwarvesf#252 dwarvesf#254 dwarvesf#275 dwarvesf#334) is
macOS inserting new status items at the far-left (hidden) slot; no public API
lets one app reposition another's menu-bar icon. Document the root cause and the
one-time cmd-drag workaround so it stops reading as a Hidden Bar bug. The real
fix (pinning chosen icons) is the menu-bar redesign tracked separately.
The always-hidden cluster (dwarvesf#171 dwarvesf#224 dwarvesf#242 dwarvesf#288 dwarvesf#205) traces to the always-hidden
separator only inflating when 'hide separators' is also on, so always-hidden
items can reappear after expanding. That coupling is core and is being reworked
with the menu-bar redesign. Document the current behavior + the option-click
workaround, and warn against placing critical icons there until the rework lands.
With 'use full menu bar on expanding' enabled, the auto-collapse timer
deactivated the app and dismissed the preferences window mid-edit (dwarvesf#170, same
family as dwarvesf#66/dwarvesf#151). Defer the auto-collapse while the preferences window is on
screen, mirroring the existing mouse-in-menubar deferral. Non-core: touches only
the auto-hide timer guard, not the separator length logic.
macOS 27 may ignore NSStatusItem.length, silently breaking hiding (dwarvesf#360). On
the first collapse with the menu-bar window ready, log the separator geometry
(requested length, host-window width, button width, actual length) so a macOS 27
capture reveals which signal distinguishes 'honored' from 'ignored'. Diagnostic
only: no behavior change on macOS <= 26. The degrade action is intentionally not
shipped yet, review found the trigger unverifiable without 27 hardware; the
captured data calibrates it. Design + options in SPEC-003 (local).
MARKETING_VERSION 1.8 -> 1.11 (the project version was stale; releases were
tagged without bumping it), build 13 -> 14. Add CHANGELOG.md summarizing the
v1.11 line from the actually-shipped commits since v1.10. Release notes staged
in-repo; notarizing/signing/publishing the release needs the Developer ID and is
left to the maintainer.
Durable index of open items (macOS 27 cluster, v1.11 release tail, Option D epic) that survives a fresh clone; the detailed planning layer under _meta/.claude is gitignored and local-only.
…usly

When launching Hidden Bar while another instance is already running,
the new instance now activates the existing one and terminates itself.

Addresses issue dwarvesf#324 where users accidentally ended up with multiple
instances running.
@bunnysayzz
bunnysayzz changed the base branch from develop to master July 14, 2026 20:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants