Avoid unmatched ShowCursor/HideCursor requests
This commit is contained in:
parent
63a176c26e
commit
344907f55a
@ -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<u32>,
|
||||
backlight_control: Option<BacklightControl>,
|
||||
}
|
||||
|
||||
@ -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<F: FnOnce(&BacklightControl, u32) -> 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);
|
||||
|
@ -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<xcb::Event>,
|
||||
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<xcb::Event>) -> anyhow::Result<UnlockDialog<'a>> {
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user