ADR 0086: Keep macOS on the regular activation policy
- Status: Accepted
- Date: 2026-08-14
- Deciders: PI-Desktop core
- Related: D223, E2E-127, ADR 0072, ADR 0078, ADR 0080
Context
The global plugin launcher (ADR 0072) is a frameless always-on-top panel that should appear over whatever the user is doing, so its window asked Electron for setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true }). On macOS that option is not a per-window flag: Electron implements it by calling TransformProcessType(kProcessTransformToUIElementApplication) on the whole process, because macOS 10.14 and later only let accessory applications float windows above another app's fullscreen Space. The process therefore became a UIElement app and PI-Desktop disappeared from the Dock and from Cmd+Tab.
ADR 0080 then moved launcher creation into boot warm-up, so the transform ran on every launch even when the launcher was never opened. The window itself was still on screen, which made the symptom look like a window-manager bug rather than an activation-policy change.
Minimize hides the main window into the tray (ADR 0078), and macOS only emits Electron's activate event from applicationShouldHandleReopen: — a Dock click or a relaunch. Cmd+Tab and App Exposé do not reach it, so a tray-hidden window had no keyboard route back even once the app was listed again.
Decision
- PI-Desktop is a regular (foreground) macOS application for its entire lifetime. No code path may transform the process type: the launcher passes
skipTransformProcessType: true, andapp.dock.hide()andapp.setActivationPolicystay out of the main process. Dock and Cmd+Tab presence is an invariant, not a side effect of one window's options. - The launcher keeps its collection behavior: it joins every regular Space and floats above PI-Desktop's own fullscreen window. It does not overlay another application's fullscreen Space; macOS reserves that for accessory apps, and activation switches Spaces there instead.
- macOS activation restores the shell through
did-become-activeas well asactivate, gated on a booted, non-quitting app with no visible window. Cmd+Tab and App Exposé bring a tray-hidden window back, while showing the launcher or a plugin panel does not drag the main window forward with it. - Tests assert the launcher call shape and the activation handler, so a future window option cannot silently make the app accessory again.
Consequences
- The app is always reachable from the Dock, Cmd+Tab, App Exposé, and the tray.
- The launcher cannot overlay another app's fullscreen Space. Invoking it from one activates PI-Desktop and switches Spaces, which is ordinary foreground-app behavior.
- Panel focus is unchanged:
show()activates the app and makes the panel key under both policies, so ADR 0080's latency work is untouched.
Alternatives
- Toggle the policy around each launcher show (
app.dock.hide()before,app.dock.show()after). It restores fullscreen overlay, but it flickers the Dock icon on every invocation, adds work to the path ADR 0080 optimized, keeps a window where Cmd+Tab cannot see the app, and leaves the app permanently accessory if the restore is ever missed. - Drop
visibleOnFullScreenentirely. Same Dock fix, but the launcher would also stop covering PI-Desktop's own fullscreen window for no gain. - Ship PI-Desktop as an
LSUIElementtray app. That contradicts ADR 0078's resident main window and the product's main-window shape. Overlaying other apps' fullscreen Spaces would need a separate accessory helper process, not a process-wide transform in the app that owns the main window.