fix: clean up lock surfaces and drain compositor events on unlock
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 commit is contained in:
+11
-3
@@ -139,6 +139,11 @@ impl WaylandLock {
|
|||||||
|
|
||||||
if success {
|
if success {
|
||||||
log::info!("✅ Authentication successful - unlocking session");
|
log::info!("✅ Authentication successful - unlocking session");
|
||||||
|
// ext-session-lock-v1 recommends destroying lock surfaces before
|
||||||
|
// issuing unlock_and_destroy. With multiple outputs Hyprland
|
||||||
|
// otherwise treats the unlock as a client crash and shows its
|
||||||
|
// failsafe screen.
|
||||||
|
self.lock_surfaces.clear();
|
||||||
if let Some(session_lock) = &self.session_lock {
|
if let Some(session_lock) = &self.session_lock {
|
||||||
session_lock.unlock();
|
session_lock.unlock();
|
||||||
let _ = self.conn.flush();
|
let _ = self.conn.flush();
|
||||||
@@ -808,9 +813,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
.insert_source(auth_feedback_rx_actual, |event, _, state| {
|
.insert_source(auth_feedback_rx_actual, |event, _, state| {
|
||||||
if let calloop::channel::Event::Msg(success) = event {
|
if let calloop::channel::Event::Msg(success) = event {
|
||||||
state.handle_auth_result(success);
|
state.handle_auth_result(success);
|
||||||
if success {
|
|
||||||
state.lock_surfaces.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@@ -906,6 +908,12 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
event_loop.dispatch(Duration::from_millis(16), &mut state)?;
|
event_loop.dispatch(Duration::from_millis(16), &mut state)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After unlock_and_destroy the compositor sends keyboard/pointer leave and
|
||||||
|
// delete_id events that must be processed before we disconnect, otherwise
|
||||||
|
// Hyprland treats the disconnect as a client crash and shows its failsafe
|
||||||
|
// screen (only reproducible on multi-output setups).
|
||||||
|
let _ = state.conn.roundtrip();
|
||||||
|
|
||||||
log::info!("Exiting rustlock");
|
log::info!("Exiting rustlock");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user