fix: clean lock-surface teardown + roundtrip on unlock (Hyprland multi-output)#6
Open
josephdunn wants to merge 1 commit into
Open
Conversation
Hyprland was treating multi-output rustlock unlocks as client crashes and showing its "lockscreen died" failsafe instead of unlocking. Two issues: 1. Order. ext-session-lock-v1 recommends destroying every ext_session_lock_surface_v1 before issuing unlock_and_destroy on ext_session_lock_v1. rustlock did the opposite. Move lock_surfaces.clear() into handle_auth_result so it runs before session_lock.unlock(), and drop the now-redundant clear from the auth-feedback callback. 2. Drain. After unlock_and_destroy the compositor sends keyboard/pointer leave events and delete_id acks; if the client disconnects before processing them, Hyprland treats the disconnect as unclean. Add a conn.roundtrip() after the main loop to drain those events before exit. Single-output setups tolerate both of these (which is why the bug does not show up on the upstream author's laptop). The failsafe only reproduces with multiple outputs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On a multi-output Hyprland setup, unlocking rustlock consistently triggers Hyprland's "lockscreen died" failsafe screen instead of unlocking, even though rustlock exits cleanly with status 0. Single-output setups are unaffected (which is presumably why this hasn't shown up before).
Reproduced on Hyprland with three outputs (two rotated 2560x1440 + one 3840x2160).
Root cause
Two issues in the unlock path, both tolerated by Hyprland on single-output but not on multi-output:
Wrong teardown order.
ext-session-lock-v1recommends destroying eachext_session_lock_surface_v1before issuingunlock_and_destroyonext_session_lock_v1. rustlock did the opposite: it calledsession_lock.unlock()first insidehandle_auth_result, then clearedlock_surfacesfrom the auth-feedback callback afterwards.No event drain before disconnect. After
unlock_and_destroy, the compositor sends backwl_keyboard.leave,wl_pointer.leave, andwl_display.delete_idevents. Without dispatching those, rustlock disconnects mid-conversation; Hyprland treats that as an unclean exit.A
WAYLAND_DEBUG=clienttrace of the baseline showedunlock_and_destroysent first, thenlock_surface.destroy()/wl_surface.destroy()pairs, then disconnect — nowl_display.errorfrom the compositor, just the failsafe afterwards. A trace of the fix shows the spec-recommended order followed by a brief drain of leave/delete_id events before exit, and Hyprland unlocks normally.Fix
self.lock_surfaces.clear()intohandle_auth_resultso it runs beforesession_lock.unlock(). Remove the now-redundant clear from the auth-feedback callback.state.conn.roundtrip()after the main event loop exits to drain the post-unlock events before disconnect.Total change: +11/−3 in
src/main.rs.Test plan
WAYLAND_DEBUG=clienttrace confirms teardown order matches the spec recommendation and leave/delete_id events are drained before disconnect.Note
AI (Claude) helped me diagnose and write the fix.