feat(settings): Launch at login via SMAppService in Settings#5
Merged
Conversation
added 3 commits
June 5, 2026 17:23
Launch-at-login was only reachable from the status-bar menu, which is hidden entirely when the user enables "Hide menu bar icon" — leaving no way to change the setting from the UI. Surface it as a checkbox in Settings → General → Application alongside the hide-icon option. Extract the LaunchAgent plist read/write out of AppDelegate into a shared LaunchAtLogin helper so the menu item and the new checkbox read and mutate the same source of truth (the plist's presence), keeping the two controls in agreement without a separate stored flag.
Ticking the new Settings checkbox wrote the LaunchAgent plist but left the status menu's "Launch at Login" item showing its stale state until the next unrelated menu rebuild. Unlike the RuleStore-backed settings, launch-at-login has no setter that posts a change notification. Post .rulesDidChange after the toggle so AppDelegate rebuilds the menu and re-reads LaunchAtLogin.isEnabled, matching how the store-backed toggles already keep the menu in sync. The extra FocusMonitor.reload this triggers is a cheap no-op when the observed bundle set is unchanged.
The plist-based LaunchAgent put TermIMS in System Settings' "Allow in the Background" list as a raw exec entry attributed to an "unidentified developer", because the agent pointed at the inner Mach-O rather than the app bundle. Switch to SMAppService.mainApp (macOS 13+), which registers the bundle itself so it shows up under "Open at Login" with the real icon and name. setEnabled also clears any stale LaunchAgent plist from older builds so migrating users aren't launched twice. With the Settings checkbox now the single entry point, remove the "Launch at Login" item (and its toggleLogin handler / loginItem property) from the status menu so there's nothing to keep in sync.
The General tab is built once and the window controller is cached, so a launch-at-login change made outside the app — most notably the user removing TermIMS from System Settings → Login Items — left the checkbox showing a stale state on the next open. macOS posts no notification when our login item is toggled externally, so there's nothing to observe. Re-read the live SMAppService status on NSWindow.didBecomeKeyNotification so the checkbox reflects reality every time the Settings window comes forward.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
SMAppService.mainApp(macOS 13+) instead of a hand-written LaunchAgent plist, so the entry lands in System Settings → Login Items under "Open at Login" with the real app icon and name — not in "Allow in the Background" as a rawexecfrom an "unidentified developer".setEnabledclears any stale~/Library/LaunchAgents/top.cuiko.termims.plistfrom older builds so migrating users aren't launched twice.Why
Launch-at-login was only reachable from the status menu, which vanishes when "Hide menu bar icon" is on. Moving it to Settings fixes the access gap; switching to SMAppService fixes the wrong-section / wrong-icon / unidentified-developer presentation that the legacy plist caused.
Test plan
make buildcleanmake run— Settings → General shows "Launch at login" under Application~/Library/LaunchAgents/top.cuiko.termims.plistNote
Ad-hoc signing means macOS may still surface an approval prompt on first registration (toggle the switch in System Settings if so). A clean "identified developer" label needs Developer ID signing + notarization, which is out of scope here.