Hackily retry keyboard/pointer grabs if they fail
When using a global key combo to lock the screen, often the WM (or whatever) will still have an active grab on the keyboard by the time we try to get our own grab.
This commit is contained in:
parent
ab543afcbc
commit
d7a7d57ccd
@ -1,5 +1,5 @@
|
|||||||
use log::{debug, warn};
|
use log::{debug, error, warn};
|
||||||
use std::cmp;
|
use std::{cmp, thread, time::Duration};
|
||||||
use xcb::{x, randr, Xid};
|
use xcb::{x, randr, Xid};
|
||||||
|
|
||||||
use bscreensaver_util::{BSCREENSAVER_WM_CLASS, create_atom, destroy_cursor, destroy_pixmap, destroy_gc, destroy_window};
|
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)?;
|
self.conn.check_request(cookie)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cookie = self.conn.send_request(&x::GrabKeyboard {
|
if let Err(err) = self.grab_keyboard() {
|
||||||
owner_events: true,
|
warn!("Failed to grab keyboard on window {:?}: {:?}", self.blanker_window, err);
|
||||||
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_pointer() {
|
||||||
let cookie = self.conn.send_request(&x::GrabPointer {
|
error!("Failed to grab pointer on window {:?}: {:?}", self.blanker_window, err);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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<()> {
|
pub fn unlock(&self) -> anyhow::Result<()> {
|
||||||
let mut cookies = Vec::new();
|
let mut cookies = Vec::new();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user