diff --git a/locker/src/monitor.rs b/locker/src/monitor.rs index 9acb72c..7c9d56d 100644 --- a/locker/src/monitor.rs +++ b/locker/src/monitor.rs @@ -1,5 +1,5 @@ -use log::{debug, warn}; -use std::cmp; +use log::{debug, error, warn}; +use std::{cmp, thread, time::Duration}; use xcb::{x, randr, Xid}; use bscreensaver_util::{BSCREENSAVER_WM_CLASS, create_atom, destroy_cursor, destroy_pixmap, destroy_gc, destroy_window}; @@ -238,38 +238,65 @@ impl<'a> Monitor<'a> { self.conn.check_request(cookie)?; } - let cookie = self.conn.send_request(&x::GrabKeyboard { - owner_events: true, - grab_window: self.unlock_window, - time: x::CURRENT_TIME, - pointer_mode: x::GrabMode::Async, - keyboard_mode: x::GrabMode::Async, - }); - let reply = self.conn.wait_for_reply(cookie)?; - if reply.status() != x::GrabStatus::Success { - // FIXME: try to grab later? - warn!("Failed to grab keyboard on window {:?}: {:?}", self.blanker_window, reply.status()); + if let Err(err) = self.grab_keyboard() { + warn!("Failed to grab keyboard on window {:?}: {:?}", self.blanker_window, err); } - - let cookie = self.conn.send_request(&x::GrabPointer { - owner_events: true, - grab_window: self.unlock_window, - event_mask: x::EventMask::BUTTON_PRESS | x::EventMask::BUTTON_RELEASE | x::EventMask::POINTER_MOTION | x::EventMask::POINTER_MOTION_HINT, - pointer_mode: x::GrabMode::Async, - keyboard_mode: x::GrabMode::Async, - confine_to: self.blanker_window, - cursor: x::CURSOR_NONE, - time: x::CURRENT_TIME, - }); - let reply = self.conn.wait_for_reply(cookie)?; - if reply.status() != x::GrabStatus::Success { - // FIXME: try to grab later? - warn!("Failed to grab pointer on window {:?}: {:?}", self.blanker_window, reply.status()); + if let Err(err) = self.grab_pointer() { + error!("Failed to grab pointer on window {:?}: {:?}", self.blanker_window, err); } Ok(()) } + fn grab_keyboard(&self) -> anyhow::Result<()> { + let mut attempts_remaining = 10; + loop { + let cookie = self.conn.send_request(&x::GrabKeyboard { + owner_events: true, + grab_window: self.unlock_window, + time: x::CURRENT_TIME, + pointer_mode: x::GrabMode::Async, + keyboard_mode: x::GrabMode::Async, + }); + let reply = self.conn.wait_for_reply(cookie)?; + if reply.status() == x::GrabStatus::Success { + break Ok(()); + } else if attempts_remaining > 0 { + attempts_remaining -= 1; + warn!("Failed to grab keyboard ({:?}); retrying", reply.status()); + thread::sleep(Duration::from_millis(25)); + } else { + break Err(anyhow::anyhow!("{:?}", reply.status())); + } + } + } + + fn grab_pointer(&self) -> anyhow::Result<()> { + let mut attempts_remaining = 10; + loop { + let cookie = self.conn.send_request(&x::GrabPointer { + owner_events: true, + grab_window: self.unlock_window, + event_mask: x::EventMask::BUTTON_PRESS | x::EventMask::BUTTON_RELEASE | x::EventMask::POINTER_MOTION | x::EventMask::POINTER_MOTION_HINT, + pointer_mode: x::GrabMode::Async, + keyboard_mode: x::GrabMode::Async, + confine_to: self.blanker_window, + cursor: x::CURSOR_NONE, + time: x::CURRENT_TIME, + }); + let reply = self.conn.wait_for_reply(cookie)?; + if reply.status() == x::GrabStatus::Success { + break Ok(()); + } else if attempts_remaining > 0 { + attempts_remaining -= 1; + warn!("Failed to grab pointer ({:?}); retrying", reply.status()); + thread::sleep(Duration::from_millis(25)); + } else { + break Err(anyhow::anyhow!("{:?}", reply.status())); + } + } + } + pub fn unlock(&self) -> anyhow::Result<()> { let mut cookies = Vec::new();