Skip to content

Add macOS support#17

Open
laveez wants to merge 14 commits into
mainfrom
feature/macos-support
Open

Add macOS support#17
laveez wants to merge 14 commits into
mainfrom
feature/macos-support

Conversation

@laveez
Copy link
Copy Markdown
Owner

@laveez laveez commented Jun 5, 2026

Overview

olsvr now runs natively on macOS alongside Linux/Wayland. On macOS it renders the same fading clock and weather overlay fullscreen on every display, keeps the OLED panel awake, hides the cursor, activates on idle, dismisses on input, and can install itself as a login agent with no Dock icon. Default behavior on Linux is unchanged.

What's included

  • A platform-agnostic core (Engine state machine + Compositor renderer) with the Wayland and macOS backends behind a cfg-gated seam, so the crate builds on both targets.
  • macOS backend: winit + Metal (wgpu), CoreGraphics idle detection, IOPMAssertion keep-awake, screen-saver-level windows, and a launchd login agent run from an LSUIElement app bundle.
  • New [activation] config (displays, keep_awake); defaults preserve the original single-display, inhibit-while-active behavior.
  • CI now builds and lints both the Linux (Wayland) and macOS legs.

Why these choices

  • The portable Engine/Compositor keep all activation, grace-period, and keep-awake logic platform-independent and unit-tested; each backend only owns its windowing glue.
  • The macOS saver sizes its own borderless window at screen-saver level rather than using winit fullscreen, because an LSUIElement (no-Dock-icon) app cannot drive winit's fullscreen path. This keeps it edge-to-edge as an accessory app.
  • launchd KeepAlive is crash-only (SuccessfulExit=false) to mirror the systemd unit's Restart=on-failure.

Testing

  • macOS (hardware-verified): fullscreen black saver on all displays, weather overlay, idle-activate, input-dismiss, panel stays awake, cursor hidden on the primary display, no Dock icon, no edge artifacts, large HiDPI surfaces.
  • Linux/Wayland: unchanged by default. CI verifies the Wayland backend still compiles and lints cleanly after the refactor; running the Wayland saver on a real session still needs a manual check.

TODO before merge

  • Compiles + clippy + fmt clean on Linux (Wayland) and macOS (CI)
  • macOS runtime verified on hardware (see Testing)
  • Run the Wayland saver on a real Linux session — CI proves the refactor compiles and lints, but the Wayland runtime path has not been exercised since the cross-platform refactor. Check: idle-activate, fullscreen black surface, input-dismiss, and idle-inhibit while active.
  • Fix a bug: Hide the cursor on secondary displays (macOS) — the mouse cursor is still visible on the external monitor on top of the saver.

laveez added 14 commits June 4, 2026 18:53
- Move smithay/wayland/calloop/dbus to a Linux-only target dependency table
- Relocate the Wayland event loop verbatim to src/backend/wayland.rs (Linux only)
- Slim main.rs to the shared CLI + cfg backend selection; macOS uses a stub pending the native backend
- Defaults (primary, while-active) preserve current Linux behavior
- Backward compatible: configs without [activation] deserialize to defaults
- Parsing unit-tested on macOS
- Pure event->command machine (idle/resume/dismiss/signal/quit) with dismiss + resume graces
- Encodes the activation + keep_awake policy; 6 unit tests, no display required
- Route idle/resume/input/signal events through Engine::handle and apply its commands
- Engine now owns the 1s dismiss and 5s resume graces (removed from the Wayland loop)
- No behavior change for the default policy; the idle inhibitor stays bundled in activate/deactivate
- Split surface creation out of Compositor::new; cfg(linux) new_wayland keeps the Wayland path
- Compositor core now compiles on macOS (verified); each backend picks the wgpu Backends
…erer)

- winit fullscreen window + wgpu(Metal) surface feeding the portable Compositor
- AlwaysOnTop window level so the saver shows and the surface is not occluded
- Idle detection, the IOPMAssertion keep-awake, and Engine wiring come next
…ather

- One fullscreen window + Compositor per monitor
- Hide the cursor over the saver; start the weather fetch thread
…kend

- Poll CGEventSource idle and drive the Engine: idle->show, input->hide, persist
- Hold a PreventUserIdleDisplaySleep assertion (the OLED-stays-awake / HDMI fix)
- Respect the activation policy (all/primary); release the assertion on exit
- Request the adapter's real limits so surfaces above 8192px (e.g. a 2x panel) are allowed
- Clamp the surface to the GPU max as a proportional safety net
- NSScreenSaverWindowLevel + all-Spaces / over-fullscreen via objc2 (AlwaysOnTop fallback)
- Hide the cursor globally with NSCursor (fixes the lingering main-screen cursor); restore on dismiss/exit
- Generate a LaunchAgent plist (RunAtLoad + crash-only KeepAlive) from the setup wizard
- Run the agent from an LSUIElement app bundle so it has no Dock icon
- cfg-split pid_path (macOS uses the per-user temp dir) and make olsvr stop boot out the agent
- Write and clean up the PID file in the macOS backend
- Add macOS to the CI check matrix
- Size each saver window to the display frame at screen-saver level instead of
  winit's Fullscreen::Borderless, which an LSUIElement accessory app can't drive
- Overscan ~2pt and paint the window opaque black with no shadow so HiDPI
  rounding leaves no grey seam at the edges
- Note the Wayland + macOS backends, Metal rendering, and launchd login agent
- Document the [activation] config (displays, keep_awake) with platform caveats
- Split Requirements into Linux (Wayland) and macOS; add a macOS PATH note
@laveez laveez self-assigned this Jun 5, 2026
@laveez laveez added the enhancement New feature or request label Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant