From 344907f55ac5f674014ad44520637e08c3bc8f8b Mon Sep 17 00:00:00 2001 From: "Brian J. Tarricone" Date: Tue, 24 May 2022 20:32:15 -0700 Subject: [PATCH] Avoid unmatched ShowCursor/HideCursor requests --- locker/src/monitor.rs | 33 +++++++++++++++++++++++++-------- locker/src/screensaver.rs | 24 +++++++++++++----------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/locker/src/monitor.rs b/locker/src/monitor.rs index 7441d17..286c406 100644 --- a/locker/src/monitor.rs +++ b/locker/src/monitor.rs @@ -1,5 +1,5 @@ use log::{debug, warn}; -use std::cmp; +use std::{cmp, cell::RefCell}; use xcb::{x, randr, xfixes, Xid}; use bscreensaver_util::{BSCREENSAVER_WM_CLASS, create_atom}; @@ -7,7 +7,6 @@ use bscreensaver_util::{BSCREENSAVER_WM_CLASS, create_atom}; const BACKLIGHT_ATOM_NAME: &[u8] = b"Backlight"; const BACKLIGHT_FALLBACK_ATOM_NAME: &[u8] = b"BACKLIGHT"; -#[derive(Clone, Copy)] struct BacklightControl { property: x::Atom, min_level: i32, @@ -15,7 +14,6 @@ struct BacklightControl { step: u32, } -#[derive(Clone, Copy)] pub struct Monitor { pub root: x::Window, pub black_gc: x::Gcontext, @@ -26,6 +24,8 @@ pub struct Monitor { pub y: i16, pub width: u16, pub height: u16, + // RefCell used here to avoid requiring '&mut self' on blank/unblank + cursor_hidden: RefCell, backlight_control: Option, } @@ -78,6 +78,7 @@ impl Monitor { y: reply.y(), width: reply.width(), height: reply.height(), + cursor_hidden: RefCell::new(0), backlight_control: backlight_control.ok().flatten(), }); } @@ -87,6 +88,15 @@ impl Monitor { Ok(monitors) } + pub fn geometry(&self) -> x::Rectangle { + x::Rectangle { + x: self.x, + y: self.y, + width: self.width, + height: self.height, + } + } + pub fn blank(&self, conn: &xcb::Connection) -> anyhow::Result<()> { let mut cookies = Vec::new(); cookies.push(conn.send_request_checked(&x::ConfigureWindow { @@ -186,10 +196,15 @@ impl Monitor { } pub fn show_cursor(&self, conn: &xcb::Connection) { - if let Err(err) = conn.send_and_check_request(&xfixes::ShowCursor { - window: self.blanker_window, - }) { - warn!("Failed to show cursor: {}", err); + let ok = self.cursor_hidden.try_borrow().map(|ch| *ch > 0).unwrap_or(true); + if ok { + if let Err(err) = conn.send_and_check_request(&xfixes::ShowCursor { + window: self.blanker_window, + }) { + warn!("Failed to show cursor: {}", err); + } else { + let _ = self.cursor_hidden.try_borrow_mut().map(|mut ch| *ch -= 1); + } } } @@ -198,6 +213,8 @@ impl Monitor { window: self.blanker_window, }) { warn!("Failed to hide cursor: {}", err); + } else { + let _ = self.cursor_hidden.try_borrow_mut().map(|mut ch| *ch += 1); } } @@ -210,7 +227,7 @@ impl Monitor { } fn brightness_change i32>(&self, conn: &xcb::Connection, updater: F) -> anyhow::Result<()> { - if let Some(backlight_control) = self.backlight_control { + if let Some(backlight_control) = &self.backlight_control { if let Ok(Some(cur_brightness)) = self.get_current_brightness(conn, &backlight_control) { let new_level = updater(&backlight_control, cur_brightness); let new_level = cmp::min(backlight_control.max_level, new_level); diff --git a/locker/src/screensaver.rs b/locker/src/screensaver.rs index f369c49..90925b0 100644 --- a/locker/src/screensaver.rs +++ b/locker/src/screensaver.rs @@ -24,7 +24,8 @@ pub enum BlankerState { } struct UnlockDialog<'a> { - monitor: Monitor, + monitor_geom: x::Rectangle, + blanker_window: x::Window, embedder: Embedder<'a>, event_to_forward: Option, child: Child, @@ -204,9 +205,9 @@ impl<'a> Screensaver<'a> { }, xcb::Event::X(x::Event::ConfigureNotify(ev)) if ev.window() == self.embedder_window() => { if let Some(unlock_dialog) = &self.unlock_dialog { - let monitor = &unlock_dialog.monitor; - let x = std::cmp::max(0, monitor.x as i32 + monitor.width as i32 / 2 - ev.width() as i32 / 2); - let y = std::cmp::max(0, monitor.y as i32 + monitor.height as i32 / 2 - ev.height() as i32 / 2); + let monitor_geom = &unlock_dialog.monitor_geom; + let x = std::cmp::max(0, monitor_geom.x as i32 + monitor_geom.width as i32 / 2 - ev.width() as i32 / 2); + let y = std::cmp::max(0, monitor_geom.y as i32 + monitor_geom.height as i32 / 2 - ev.height() as i32 / 2); if x != ev.x() as i32 || y != ev.y() as i32 { conn.send_and_check_request(&x::ConfigureWindow { window: unlock_dialog.embedder.embedder_window(), @@ -274,7 +275,7 @@ impl<'a> Screensaver<'a> { }, Some(unlock_dialog) => { let mut cookies = Vec::new(); - for win in [unlock_dialog.monitor.blanker_window, unlock_dialog.embedder.embedder_window(), unlock_dialog.embedder.client_window()] { + for win in [unlock_dialog.blanker_window, unlock_dialog.embedder.embedder_window(), unlock_dialog.embedder.client_window()] { cookies.push(conn.send_request_checked(&x::ConfigureWindow { window: win, value_list: &[ @@ -324,7 +325,7 @@ impl<'a> Screensaver<'a> { } fn start_unlock_dialog(&self, conn: &'a xcb::Connection, trigger_event: Option) -> anyhow::Result> { - let mut pointer_monitor = None; + let mut monitor_data = None; for monitor in &self.monitors { let cookie = conn.send_request(&x::QueryPointer { window: monitor.root, @@ -336,13 +337,14 @@ impl<'a> Screensaver<'a> { && px >= monitor.x as i32 && px < monitor.x as i32 + monitor.width as i32 && py >= monitor.y as i32 && py < monitor.y as i32 + monitor.height as i32 { - pointer_monitor = Some(monitor); + monitor_data = Some((monitor.geometry(), monitor.blanker_window, monitor.unlock_window)); break; } } - let pointer_monitor = pointer_monitor.unwrap_or_else(|| { + let (monitor_geom, blanker_window, unlock_window) = monitor_data.unwrap_or_else(|| { warn!("Unable to determine which monitor pointer is on; using first one"); - self.monitors.iter().nth(0).unwrap() + let monitor = self.monitors.iter().nth(0).unwrap(); + (monitor.geometry(), monitor.blanker_window, monitor.unlock_window) }); for monitor in &self.monitors { @@ -391,11 +393,11 @@ impl<'a> Screensaver<'a> { })?; } - let unlock_window = pointer_monitor.unlock_window; let embedder = Embedder::start(conn, unlock_window, client_window)?; Ok(UnlockDialog { - monitor: *pointer_monitor, + monitor_geom, + blanker_window, embedder, event_to_forward: trigger_event, child,