Summary
On macOS, a Perry-compiled desktop app's window stays above a normal windowed app and does not go behind it when that app is clicked. Observed over a Chrome window: clicking Chrome does not bring it in front of the Perry window. Behavior over native-fullscreen apps is inconsistent. Some become active when clicked, some do not. The behavior is not universal across all apps.
Environment
- Perry 0.5.1531 (local build)
- macOS, Darwin 25.6.0, arm64
- Native macOS target (
perry-ui-macos)
Steps to reproduce
- Compile a minimal macOS UI app:
perry compile app.ts -o myapp.
- Run
./myapp. A window opens and comes to the front.
- With a normal windowed app such as Chrome, click it.
- It does not come in front. The Perry window stays on top.
Expected
Clicking another app brings that app in front of the Perry window, like any normal macOS app.
Suspected cause
Perry's macOS desktop output is a bare Mach-O executable, not a .app bundle. It embeds a minimal Info.plist as a __TEXT,__info_plist section (crates/perry/src/commands/compile/link/build_and_run.rs: "Perry's direct desktop output is a Mach-O executable, not a .app bundle") and sets the activation policy to Regular at runtime (crates/perry-ui-macos/src/app.rs, setActivationPolicy). A non-bundled process registered this way is not fully known to LaunchServices, so macOS does not reliably reorder its window when another app activates. That fits the inconsistency: the window stays over normal windowed apps but native-fullscreen apps on their own Space are affected differently.
It is not a window-level issue. The main window is at normal level (0). The only setLevel path is gated on the App() level option, which this app does not pass.
Fix confirmed for the windowed case
Wrapping the same binary in a minimal .app bundle makes the window yield normally when another app is clicked:
myapp.app/
Contents/
Info.plist # CFBundleExecutable, CFBundleIdentifier, CFBundlePackageType=APPL
MacOS/myapp
Suggested fix
Emit a real .app bundle for the macOS target. Perry already builds bundles for iOS, tvOS, watchOS, and visionOS (crates/perry/src/commands/compile/bundle_apple.rs), so the machinery exists.
Separately, for automated or headless runs such as Geisterhand, add an agent launch mode (LSUIElement or accessory activation) so a driven app does not take the foreground.
Scope
macOS desktop apps built with Perry. The exact behavior varies with the other app's window state (normal window vs native fullscreen).
Summary
On macOS, a Perry-compiled desktop app's window stays above a normal windowed app and does not go behind it when that app is clicked. Observed over a Chrome window: clicking Chrome does not bring it in front of the Perry window. Behavior over native-fullscreen apps is inconsistent. Some become active when clicked, some do not. The behavior is not universal across all apps.
Environment
perry-ui-macos)Steps to reproduce
perry compile app.ts -o myapp../myapp. A window opens and comes to the front.Expected
Clicking another app brings that app in front of the Perry window, like any normal macOS app.
Suspected cause
Perry's macOS desktop output is a bare Mach-O executable, not a
.appbundle. It embeds a minimal Info.plist as a__TEXT,__info_plistsection (crates/perry/src/commands/compile/link/build_and_run.rs: "Perry's direct desktop output is a Mach-O executable, not a .app bundle") and sets the activation policy to Regular at runtime (crates/perry-ui-macos/src/app.rs,setActivationPolicy). A non-bundled process registered this way is not fully known to LaunchServices, so macOS does not reliably reorder its window when another app activates. That fits the inconsistency: the window stays over normal windowed apps but native-fullscreen apps on their own Space are affected differently.It is not a window-level issue. The main window is at normal level (0). The only
setLevelpath is gated on theApp()leveloption, which this app does not pass.Fix confirmed for the windowed case
Wrapping the same binary in a minimal
.appbundle makes the window yield normally when another app is clicked:Suggested fix
Emit a real
.appbundle for the macOS target. Perry already builds bundles for iOS, tvOS, watchOS, and visionOS (crates/perry/src/commands/compile/bundle_apple.rs), so the machinery exists.Separately, for automated or headless runs such as Geisterhand, add an agent launch mode (LSUIElement or accessory activation) so a driven app does not take the foreground.
Scope
macOS desktop apps built with Perry. The exact behavior varies with the other app's window state (normal window vs native fullscreen).