Skip to content

fix(session): wait for lock screen to render before suspending#3125

Open
Aitor42 wants to merge 4 commits into
noctalia-dev:mainfrom
Aitor42:main
Open

fix(session): wait for lock screen to render before suspending#3125
Aitor42 wants to merge 4 commits into
noctalia-dev:mainfrom
Aitor42:main

Conversation

@Aitor42

@Aitor42 Aitor42 commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR ensures that the deferred suspend command is executed only after all active lock screen surfaces have successfully drawn and committed their first frame.

  • Overrode render() in LockSurface to track when m_firstFrameRendered is set to true and trigger a render callback.
  • Added allSurfacesReady() in LockScreen to verify if all output surfaces have completed their first render.
  • Updated runAfterSessionLocked and handleLocked to defer execution of the pending suspend callback until allSurfacesReady() is true.

Motivation

This resolves a race condition where the system suspends before the lock screen has finished rendering. When resuming, the unlocked desktop could briefly flash or remain visible, presenting a security vulnerability and visual glitch.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring
  • Build / packaging

Related Issue

Closes #2962

Testing

Built the daemon and ran the entire test suite:
meson compile -C build
meson test -C build
All tests pass successfully.

Manual Coverage

  • Tested on Niri
  • Tested on Hyprland
  • Tested on Sway
  • Tested on another compositor:
  • Tested with different bar positions and density settings
  • Tested at different interface scaling values
  • Tested with multiple monitors

Checklist

  • This PR is ready for review, or it is marked as Draft.
  • I read and followed the relevant guidance in CONTRIBUTING.md.
  • I ran just format with clang-format v22+ installed, or this PR has no code changes.
  • I ran the relevant build or test commands, or explained why they were not run.
  • I self-reviewed the changes.
  • I checked for new warnings or errors.
  • I will update end-user documentation after merge, or this PR does not change user-facing configuration or behavior.
  • I added or updated assets/translations/en.json, or this PR adds no new user-facing strings.
  • I did not edit non-English translation files unless this PR is explicitly for translation tooling, an import/export sync, or a maintainer-requested locale change.
  • I used the existing canonical names for config keys, IPC names, paths, and identifiers.

Additional Notes

If a lock surface fails to configure or render due to driver glitches or compositor-specific edge cases, the suspend sequence could get indefinitely postponed. I sugest adding a 2-3 second fallback timer to trigger suspend regardless of render status.

@Ly-sec

Ly-sec commented Jun 25, 2026

Copy link
Copy Markdown
Member

Hey @Aitor42 , thanks for tackling this, the direction looks good to me.

The race is real: handleLocked is compositor state, not "pixels are on screen." Waiting for a first render() on every LockSurface before running the pending suspend callback is a sensible fix for #2962 .

I'd want a timeout fallback before merge though. If a surface never renders, suspend could hang forever. A 2-3s timer that warns and runs the callback anyway is a reasonable tradeoff.

Minor nits: the flush-when-ready logic is duplicated in three places (a tryFlushPendingAfterLocked() helper would help), and firstFrameRendered could reset on reconfigure for accuracy mid-lock. Neither is a blocker.

Manual testing is fine here. Nice work overall.

@Aitor42

Aitor42 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

Hey @Aitor42 , thanks for tackling this, the direction looks good to me.

The race is real: handleLocked is compositor state, not "pixels are on screen." Waiting for a first render() on every LockSurface before running the pending suspend callback is a sensible fix for #2962 .

I'd want a timeout fallback before merge though. If a surface never renders, suspend could hang forever. A 2-3s timer that warns and runs the callback anyway is a reasonable tradeoff.

Minor nits: the flush-when-ready logic is duplicated in three places (a tryFlushPendingAfterLocked() helper would help), and firstFrameRendered could reset on reconfigure for accuracy mid-lock. Neither is a blocker.

Manual testing is fine here. Nice work overall.

Thanks for the feedback! I added the timeout to 3 seconds and the tryFlushPendingAfterLocked() function. For the firstFrameRendered rest I only change it when a real geometry change occurs, preventing unnecessary re-blocking of the flush during non-sizing configure events.

Let me know if you see something else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] lock+suspend lets you see session briefly before opening lock screen

2 participants