feat(application): cross-platform system sleep/wake events#5425
Conversation
Mirrors the windows:APMSuspend / APMResumeAutomatic / APMResumeSuspend events that Wails v3 already raises from WM_POWERBROADCAST on Windows. NSWorkspace power notifications post to its own notification center (not the default NSNotificationCenter that NSApplicationDelegate uses) so the events are declared with the `!` suffix in events.txt to skip the delegate-selector auto-generation, and observers are wired by hand in application_darwin.go's init() alongside the existing theme-change observer on NSDistributedNotificationCenter. New events: - mac:ApplicationWillSleep (NSWorkspaceWillSleepNotification) - mac:ApplicationDidWake (NSWorkspaceDidWakeNotification) - mac:ApplicationScreensDidSleep (NSWorkspaceScreensDidSleepNotification) - mac:ApplicationScreensDidWake (NSWorkspaceScreensDidWakeNotification) Verification: compile + vet + existing unit tests pass on macOS, linux, windows. Runtime firing of the observers is not exercised by automated tests (same gap as the rest of the AppDelegate selectors) — to be confirmed via xbar2's #807 follow-up wiring and a manual sleep test. Motivation: xbar2 needs DidWake to force a plugin refresh sweep after sleep, addressing upstream xbar issue #807 (the most-upvoted open bug).
Adds Linux equivalents to the mac:ApplicationDidWake / WillSleep events introduced in the previous commit, completing power-event coverage across macOS, Windows, and Linux. Implementation subscribes to org.freedesktop.login1.Manager's PrepareForSleep signal on the system bus. The signal fires twice with a boolean arg — true just before suspend (→ linux:SystemWillSleep), false on resume (→ linux:SystemDidWake). The pattern mirrors monitorThemeChanges() in the same file (goroutine + AddMatchSignal + range over Signal channel), differing only in bus (system vs session) and dispatch logic. Graceful degradation: distros without logind/elogind reachable on the system bus (Alpine, Void, some Devuan setups) log a warning and the goroutine exits — the rest of the application keeps running. This matches the existing theme-monitor behaviour for missing session bus. New events: - linux:SystemWillSleep (PrepareForSleep arg=true) - linux:SystemDidWake (PrepareForSleep arg=false) Verification: darwin build + vet + tests pass. Linux cross-compile requires a GTK toolchain not available in this environment, so runtime behaviour will be confirmed when the branch is built on Linux + a manual systemctl suspend test. The function structure is a near-copy of the existing monitorThemeChanges() so the parse-time risk is low. godbus API calls (ConnectSystemBus, WithMatchInterface, WithMatchMember, WithMatchObjectPath) verified against v5.2.2 (the version in go.mod).
Adds two cross-platform power events so apps can listen for sleep/wake
once instead of branching on OS:
app.OnApplicationEvent(events.Common.SystemDidWake, …)
Each platform's events_common_<os>.go map gains an entry that
forwards the platform-specific event into the common one (same
pattern as Common.ThemeChanged and Common.ApplicationStarted):
darwin: Mac.ApplicationWillSleep → Common.SystemWillSleep
Mac.ApplicationDidWake → Common.SystemDidWake
windows: Windows.APMSuspend → Common.SystemWillSleep
Windows.APMResumeAutomatic → Common.SystemDidWake
linux: Linux.SystemWillSleep → Common.SystemWillSleep
Linux.SystemDidWake → Common.SystemDidWake
Notes:
- Windows APMResumeSuspend is deliberately not mapped — it fires
*after* APMResumeAutomatic when the wake was triggered by user
input, so mapping both would double-fire Common.SystemDidWake.
- Mac.ApplicationScreensDidWake / ScreensDidSleep are kept platform-
specific; they fire on display power state (separate from system
sleep) and have no Linux/Windows equivalent.
Verified: darwin build + tests pass locally; Linux build + tests
pass on lin-node1; windows cross-vet of pkg/events clean.
Adds documentation for the new Common.SystemWillSleep / SystemDidWake events plus the macOS Mac.ApplicationWillSleep / DidWake / ScreensDidSleep / ScreensDidWake and Linux SystemWillSleep / SystemDidWake variants. - features/events/system.mdx: code examples in the Common block + the macOS and Linux platform tabs; clarifies the Windows resume choice (APMResumeAutomatic vs APMResumeSuspend). - reference/events.mdx: adds the two common events to the application- events table. - guides/events-reference.mdx: adds rows to the Common, macOS, and Linux tables; notes the logind dependency on Linux and the screen- vs-system sleep distinction on macOS.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughAdds cross-platform system sleep/wake lifecycle events: new event types and renumbered IDs, runtime event name registrations, macOS and Linux native handlers, Windows-to-common mappings, standardized forwarding, and updated documentation with examples. ChangesSystem Sleep/Wake Event Lifecycle
Sequence DiagramssequenceDiagram
participant Application
participant macOS
participant Linux
participant Windows
participant EventBus
Application->>macOS: Register workspace observers
Application->>Linux: Subscribe to logind signals
Application->>Windows: Wire APM mapping
macOS->>EventBus: ApplicationWillSleep → SystemWillSleep
Linux->>EventBus: PrepareForSleep(true) → SystemWillSleep
Windows->>EventBus: APMSuspend → SystemWillSleep
macOS->>EventBus: ApplicationDidWake → SystemDidWake
Linux->>EventBus: PrepareForSleep(false) → SystemDidWake
Windows->>EventBus: APMResumeAutomatic → SystemDidWake
🎯 4 (Complex) | ⏱️ ~60 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/src/content/docs/guides/events-reference.mdx`:
- Around line 426-427: Add a new row for the Windows resume event
`windows:APMResumeAutomatic` to the Windows events reference table (near the
existing `common:SystemWillSleep` and `common:SystemDidWake` rows): include the
event name `windows:APMResumeAutomatic`, a short description like "System
resumed from automatic resume (APMResumeAutomatic)", and recommended actions
such as "Reconnect, refresh stale data" formatted as a markdown table row
matching the surrounding pipe-separated layout and backtick-wrapped event names.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 56432a83-116c-40cf-bbfd-365a3e526f24
📒 Files selected for processing (17)
docs/src/content/docs/features/events/system.mdxdocs/src/content/docs/guides/events-reference.mdxdocs/src/content/docs/reference/events.mdxv3/internal/generator/collect/known_events.gov3/internal/runtime/desktop/@wailsio/runtime/src/event_types.tsv3/pkg/application/application_darwin.gov3/pkg/application/application_darwin_delegate.mv3/pkg/application/application_linux.gov3/pkg/application/events_common_darwin.gov3/pkg/application/events_common_linux.gov3/pkg/application/events_common_windows.gov3/pkg/events/events.gov3/pkg/events/events.txtv3/pkg/events/events_darwin.hv3/pkg/events/events_ios.hv3/pkg/events/events_linux.hv3/pkg/events/known_events.go
There was a problem hiding this comment.
Pull request overview
This PR adds cross-platform system sleep/wake lifecycle events to Wails v3, aligning macOS and Linux capabilities with the existing Windows power-broadcast events and providing unified common events (Common.SystemWillSleep, Common.SystemDidWake) for application code to consume.
Changes:
- Adds new common + platform-specific event types (macOS sleep/wake + screen sleep/wake, Linux sleep/wake) and regenerates event IDs/mappings across Go/C headers/TS runtime.
- Implements Linux sleep/wake monitoring via
org.freedesktop.login1.Manager.PrepareForSleepon the system bus. - Implements macOS sleep/wake monitoring via
NSWorkspacenotification center observers, plus updates documentation to describe the new events.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| v3/pkg/events/known_events.go | Registers new common/linux/mac event names as known events. |
| v3/pkg/events/events.txt | Declares new events (including !-suffixed mac/linux entries for generator behavior). |
| v3/pkg/events/events.go | Adds new event constants and regenerates numeric IDs + eventToJS map. |
| v3/pkg/events/events_linux.h | Regenerates Linux C header event IDs (adds sleep/wake) and MAX_EVENTS. |
| v3/pkg/events/events_ios.h | Regenerates iOS C header event IDs due to global ID shifts. |
| v3/pkg/events/events_darwin.h | Regenerates macOS C header event IDs (adds sleep/wake + screen sleep/wake) and MAX_EVENTS. |
| v3/pkg/application/events_common_windows.go | Forwards Windows power events into new common sleep/wake events. |
| v3/pkg/application/events_common_linux.go | Forwards Linux sleep/wake events into new common sleep/wake events. |
| v3/pkg/application/events_common_darwin.go | Forwards macOS sleep/wake events into new common sleep/wake events. |
| v3/pkg/application/application_linux.go | Adds monitorPowerEvents() using logind PrepareForSleep signal; hooks it into app run. |
| v3/pkg/application/application_darwin.go | Registers NSWorkspace sleep/wake + screen sleep/wake observers during init. |
| v3/pkg/application/application_darwin_delegate.m | Adds delegate handlers for the new NSWorkspace notifications and emits events. |
| v3/internal/runtime/desktop/@wailsio/runtime/src/event_types.ts | Exposes the new event string constants to the JS runtime. |
| v3/internal/generator/collect/known_events.go | Updates generator-side known event list to include the new events. |
| docs/src/content/docs/reference/events.mdx | Documents new common SystemWillSleep / SystemDidWake events. |
| docs/src/content/docs/guides/events-reference.mdx | Adds new common + platform-specific sleep/wake entries to the reference guide. |
| docs/src/content/docs/features/events/system.mdx | Adds usage examples and platform notes for the new sleep/wake events. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if err = conn.AddMatchSignal( | ||
| dbus.WithMatchInterface("org.freedesktop.login1.Manager"), | ||
| dbus.WithMatchMember("PrepareForSleep"), | ||
| dbus.WithMatchObjectPath("/org/freedesktop/login1"), | ||
| ); err != nil { |
| var commonApplicationEventMap = map[events.ApplicationEventType]events.ApplicationEventType{ | ||
| events.Windows.SystemThemeChanged: events.Common.ThemeChanged, | ||
| events.Windows.ApplicationStarted: events.Common.ApplicationStarted, | ||
| events.Windows.SystemThemeChanged: events.Common.ThemeChanged, | ||
| events.Windows.ApplicationStarted: events.Common.ApplicationStarted, | ||
| events.Windows.APMSuspend: events.Common.SystemWillSleep, | ||
| events.Windows.APMResumeAutomatic: events.Common.SystemDidWake, | ||
| } |
| var commonApplicationEventMap = map[events.ApplicationEventType]events.ApplicationEventType{ | ||
| events.Linux.ApplicationStartup: events.Common.ApplicationStarted, | ||
| events.Linux.SystemThemeChanged: events.Common.ThemeChanged, | ||
| events.Linux.SystemWillSleep: events.Common.SystemWillSleep, | ||
| events.Linux.SystemDidWake: events.Common.SystemDidWake, | ||
| } |
| var commonApplicationEventMap = map[events.ApplicationEventType]events.ApplicationEventType{ | ||
| events.Mac.ApplicationDidFinishLaunching: events.Common.ApplicationStarted, | ||
| events.Mac.ApplicationDidChangeTheme: events.Common.ThemeChanged, | ||
| events.Mac.ApplicationWillSleep: events.Common.SystemWillSleep, | ||
| events.Mac.ApplicationDidWake: events.Common.SystemDidWake, | ||
| } |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Three review issues from #5425: 1. Common-event forwarding mutated the incoming *ApplicationEvent's Id before re-queuing. Because application listeners run concurrently (see EventProcessor.dispatchEventToListeners), this could race with other listeners observing the source event. Fix: emit a fresh ApplicationEvent for the common copy, sharing only ctx. Applied uniformly to all five setupCommonEvents implementations (darwin / linux / windows / ios / android) since they all had the same pattern. 2. Linux monitorPowerEvents claimed to warn and exit on systems without logind/elogind, but AddMatchSignal would succeed on any system bus and the goroutine would block forever on a channel that never receives. Probe org.freedesktop.DBus.NameHasOwner for org.freedesktop.login1 up front and warn + return if absent. Also constrain the match rule with WithMatchSender so a hostile bus name can't spoof PrepareForSleep signals (Copilot). 3. docs/guides/events-reference.mdx Windows table omitted APMResumeAutomatic. Added it with a note distinguishing it from APMResumeSuspend (CodeRabbit). Verified: darwin + linux build/test pass; dbus-send NameHasOwner returns true for org.freedesktop.login1 on the Linux test node.
|
Addressed the review feedback (pushed as `db85bdb`, rebased on top of the earlier Copilot autofix `335a902`):
Verified darwin build + tests pass; `dbus-send NameHasOwner` returns `true` for `org.freedesktop.login1` on the Linux test node, and the rebased branch builds + tests clean there too. |
Summary
Adds cross-platform sleep/wake events so apps can react to the system suspending/resuming. Closes a long-standing gap: Windows already exposed
WM_POWERBROADCASTasWindows.APMSuspend/APMResumeAutomatic/APMResumeSuspend, but macOS and Linux had no equivalent.What's added
macOS — observes
NSWorkspace's notification centre (separate from the default one used byNSApplicationDelegate):Mac.ApplicationWillSleep→NSWorkspaceWillSleepNotificationMac.ApplicationDidWake→NSWorkspaceDidWakeNotificationMac.ApplicationScreensDidSleep→NSWorkspaceScreensDidSleepNotificationMac.ApplicationScreensDidWake→NSWorkspaceScreensDidWakeNotificationDeclared with the
!suffix inevents.txtso the generator skips its auto-selector emission (NSWorkspace selectors don't belong onNSApplicationDelegate); observer registration is wired by hand inapplication_darwin.go::init()next to the existing theme-change observer.Linux — subscribes to
org.freedesktop.login1.Manager.PrepareForSleepon the system bus. The signal fires twice with a boolean arg (true before suspend, false on resume), dispatched toLinux.SystemWillSleepandLinux.SystemDidWake. MirrorsmonitorThemeChanges()in shape. Logs a warning and exits the goroutine cleanly on distros without logind/elogind (Alpine, Void, some Devuan setups) so the rest of the app keeps working.Common forwarding —
Common.SystemWillSleepandCommon.SystemDidWake. Each platform'sevents_common_<os>.gomap gains an entry that forwards the platform-specific event into the common one (same pattern asCommon.ThemeChangedandCommon.ApplicationStarted):Mac.ApplicationWillSleepCommon.SystemWillSleepMac.ApplicationDidWakeCommon.SystemDidWakeWindows.APMSuspendCommon.SystemWillSleepWindows.APMResumeAutomaticCommon.SystemDidWakeLinux.SystemWillSleepCommon.SystemWillSleepLinux.SystemDidWakeCommon.SystemDidWakeDocs updated in
docs/src/content/docs/features/events/system.mdx,reference/events.mdx, andguides/events-reference.mdx.Design notes
Windows.APMResumeSuspenddeliberately NOT mapped toCommon.SystemDidWake: it fires afterAPMResumeAutomaticwhen the resume was triggered by user input, so mapping both would double-fire the common event for keyboard/mouse wakes.Mac.ApplicationScreensDidSleep/Wakekept platform-specific. They fire on display-power transitions (e.g. lid lowered) distinct from full system sleep, with no clean Windows/Linux equivalent — display-power state on Linux lives in DE-specific D-Bus interfaces (GNOME ScreenSaver, KDE PowerManagement) too fragmented to unify.monitorThemeChangesuses —logindis a system-level service.Test plan
go build,go vet,go test ./pkg/events/ ./pkg/application/— all passgo build,go test ./pkg/application/— all passGOOS=windows go vet ./pkg/events/clean (CGO build path not exercised here;events_common_windows.gois straight Go mirroring the existing map pattern)Common.SystemDidWakefire afterpmset sleepnow+ wakeCommon.SystemDidWakefire aftersystemctl suspend+ wakeCommon.SystemDidWakefire after standby + wakeAutomated tests don't cover any of the existing AppDelegate-selector or D-Bus paths either; the manual sleep test mirrors how
Common.ThemeChangedand the Windows APM events are validated today.Supersedes #5423 (closed; that PR's branch was based on a stale tree with unrelated drift).
Summary by CodeRabbit
New Features
Documentation