Fix dead macOS menu-bar icon (+ clearer right-click menu)#4789
Conversation
The primary webView WindowGroup was the only scene missing handlesExternalEvents(matching:), so a scene activation request carrying targetContentIdentifier "ha.webview" (issued when tapping the menu-bar item with no open window) had no WindowGroup to bind to and no window appeared. Match the identifier here, consistent with the other groups. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The status-item right-click menu's first action was an ambiguous "Toggle Home Assistant". Replace it with two explicit actions — "Open Home Assistant" (activates the main window) and "Open Settings…" (activates the Settings window, keeping the ⌘, shortcut) — so a right-click clearly offers opening the app or its settings. The left-click show/hide toggle behaviour is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The real reason tapping the menu-bar icon did nothing: the status-item primary action toggled on `NSApp.isActive`, but in menu-bar (.accessory) mode the app can be "active" with no visible window, so the click took the hide branch and no window ever appeared — the icon looked inert. - `isActive` now also requires a visible standard window, so a click shows the app whenever no window is on screen. - `activate()` brings an existing (hidden/ordered-out) window back to the front via makeKeyAndOrderFront, which `NSApp.activate` alone doesn't do reliably in accessory mode. New windows are still created by the scene activation request, which the WindowGroup matcher (this branch) routes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Found 21 unused localization strings in the codebase. Click to see detailsTo clean up these strings, manually remove them from the |
There was a problem hiding this comment.
Pull request overview
This pull request fixes macOS (Catalyst) menu-bar status-item behavior when the app runs with .accessory activation policy, where clicking the status-item icon could fail to surface any window. It does so by improving “active” detection and window surfacing for the status-item click path, ensuring the main WindowGroup can be targeted by scene activation, and clarifying the right-click status-item menu options.
Changes:
- Make status-item “active” detection depend on having a visible, standard (
.normal) window; and explicitly bring an existing standard window to front on activation (MacBridgeStatusItem). - Add
.handlesExternalEvents(matching:)to the primary webViewWindowGroupsoactivateAnyScene(for: .webView)can create/route a new scene when needed (HAApp). - Replace the ambiguous status-item menu entry with explicit “Open Home Assistant” and “Open Settings…” and add new localized strings (
MenuManager,Localizable.strings,Strings.swift).
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| Sources/Shared/Resources/Swiftgen/Strings.swift | Adds SwiftGen accessors for the new status-item menu strings. |
| Sources/MacBridge/MacBridgeStatusItem.swift | Updates status-item activation logic to reliably surface a standard window in menu-bar (.accessory) mode. |
| Sources/App/Utilities/MenuManager.swift | Adjusts the status-item right-click menu to explicit “Open” actions and removes the duplicate preferences entry. |
| Sources/App/Resources/en.lproj/Localizable.strings | Introduces the new localized strings for the status-item menu labels. |
| Sources/App/HAApp.swift | Routes externally-activated ha.webview scenes to the primary WindowGroup via handlesExternalEvents. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4789 +/- ##
=======================================
Coverage ? 44.69%
=======================================
Files ? 275
Lines ? 16835
Branches ? 0
=======================================
Hits ? 7524
Misses ? 9311
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Root cause of the dead menu-bar icon (both left- and right-click did nothing even though the icon rendered and the custom menus worked): NSStatusBar/NSStatusItem are main-thread-only, but the item was built in MacBridgeStatusItem.init, which runs inside AppEnvironment's lazy initialiser — created on the first touch of `Current` anywhere. Under the SwiftUI app lifecycle that first touch can be a background thread (e.g. an early Current.Log call), so the button's target/action were wired off-main and never hooked into the main-thread event machinery: the image (set later from buildMenu, on main) still drew, but clicks were silently dropped. Defer creation+wiring to ensureStatusItem(), first reached via configure(using:) on the main-thread buildMenu path — no synchronous main-thread hop during the Current initialiser, so no deadlock risk. Also fall back to the button window's currentEvent in statusItemTapped so a configured item never drops a click if NSApp.currentEvent is nil. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
The macOS menu-bar icon was completely unresponsive — neither left- nor right-click did anything — even though the icon rendered and the app's custom menus worked. Combines and supersedes #4787 and #4788.
Root cause (the real fix) —
MacBridgeStatusItemNSStatusBar/NSStatusItemare main-thread-only. The item was built inMacBridgeStatusItem.init, which runs insideAppEnvironment's lazy initialiser — created on the first touch ofCurrentanywhere. Under the SwiftUI app lifecycle that first touch can be a background thread (e.g. an earlyCurrent.Logcall), so the button'starget/actionwere wired off-main and never hooked into the main-thread event machinery. The image (set later frombuildMenu, which runs on main) still drew, but every click was silently dropped — the icon looked inert.Fix: create + wire the status item lazily in
ensureStatusItem(), first reached viaconfigure(using:)on the main-threadbuildMenupath. No synchronous main-thread hop inside theCurrentinitialiser, so no deadlock risk. Plus a fallback to the button window'scurrentEventso a configured item never drops a click ifNSApp.currentEventis momentarily nil.Window activation, once clicks work —
MacBridgeStatusItemcallbackThe status-item primary action toggled on
NSApp.isActive, which in menu-bar (.accessory) mode can be true with no visible window — so the click would hide instead of show.isActivenow also requires a visible standard window, andactivate()brings an existing hidden/ordered-out window back viamakeKeyAndOrderFront(_:).Route a new webView scene to its WindowGroup —
HAApp(was #4787)The primary
WindowGroupwas the only scene missinghandlesExternalEvents(matching:); added so a freshly-created.webViewscene (when the window was fully closed) binds to it.Clearer right-click menu —
MenuManager(was #4788)Replaced the ambiguous "Toggle Home Assistant" with explicit Open Home Assistant and Open Settings… (keeps ⌘,); removed the duplicate "Preferences…" status-item entry.
Screenshots
Link to pull request in Documentation repository
Documentation: home-assistant/companion.home-assistant#
Any other notes
Regression from the SwiftUI app-lifecycle migration (#4748). New localized strings
menu.status_item.open/menu.status_item.open_settingsadded (non-English locales sync from Lokalise). Needs verification on a real Mac — the worktree can't build the Catalyst target.