Avoid unmatched ShowCursor/HideCursor requests
This commit is contained in:
parent
63a176c26e
commit
344907f55a
@ -1,5 +1,5 @@
|
|||||||
use log::{debug, warn};
|
use log::{debug, warn};
|
||||||
use std::cmp;
|
use std::{cmp, cell::RefCell};
|
||||||
use xcb::{x, randr, xfixes, Xid};
|
use xcb::{x, randr, xfixes, Xid};
|
||||||
|
|
||||||
use bscreensaver_util::{BSCREENSAVER_WM_CLASS, create_atom};
|
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_ATOM_NAME: &[u8] = b"Backlight";
|
||||||
const BACKLIGHT_FALLBACK_ATOM_NAME: &[u8] = b"BACKLIGHT";
|
const BACKLIGHT_FALLBACK_ATOM_NAME: &[u8] = b"BACKLIGHT";
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
struct BacklightControl {
|
struct BacklightControl {
|
||||||
property: x::Atom,
|
property: x::Atom,
|
||||||
min_level: i32,
|
min_level: i32,
|
||||||
@ -15,7 +14,6 @@ struct BacklightControl {
|
|||||||
step: u32,
|
step: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct Monitor {
|
pub struct Monitor {
|
||||||
pub root: x::Window,
|
pub root: x::Window,
|
||||||
pub black_gc: x::Gcontext,
|
pub black_gc: x::Gcontext,
|
||||||
@ -26,6 +24,8 @@ pub struct Monitor {
|
|||||||
pub y: i16,
|
pub y: i16,
|
||||||
pub width: u16,
|
pub width: u16,
|
||||||
pub height: u16,
|
pub height: u16,
|
||||||
|
// RefCell used here to avoid requiring '&mut self' on blank/unblank
|
||||||
|
cursor_hidden: RefCell<u32>,
|
||||||
backlight_control: Option<BacklightControl>,
|
backlight_control: Option<BacklightControl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +78,7 @@ impl Monitor {
|
|||||||
y: reply.y(),
|
y: reply.y(),
|
||||||
width: reply.width(),
|
width: reply.width(),
|
||||||
height: reply.height(),
|
height: reply.height(),
|
||||||
|
cursor_hidden: RefCell::new(0),
|
||||||
backlight_control: backlight_control.ok().flatten(),
|
backlight_control: backlight_control.ok().flatten(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -87,6 +88,15 @@ impl Monitor {
|
|||||||
Ok(monitors)
|
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<()> {
|
pub fn blank(&self, conn: &xcb::Connection) -> anyhow::Result<()> {
|
||||||
let mut cookies = Vec::new();
|
let mut cookies = Vec::new();
|
||||||
cookies.push(conn.send_request_checked(&x::ConfigureWindow {
|
cookies.push(conn.send_request_checked(&x::ConfigureWindow {
|
||||||
@ -186,10 +196,15 @@ impl Monitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_cursor(&self, conn: &xcb::Connection) {
|
pub fn show_cursor(&self, conn: &xcb::Connection) {
|
||||||
|
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 {
|
if let Err(err) = conn.send_and_check_request(&xfixes::ShowCursor {
|
||||||
window: self.blanker_window,
|
window: self.blanker_window,
|
||||||
}) {
|
}) {
|
||||||
warn!("Failed to show cursor: {}", err);
|
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,
|
window: self.blanker_window,
|
||||||
}) {
|
}) {
|
||||||
warn!("Failed to hide cursor: {}", err);
|
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<()> {
|
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) {
|
if let Ok(Some(cur_brightness)) = self.get_current_brightness(conn, &backlight_control) {
|
||||||
let new_level = updater(&backlight_control, cur_brightness);
|
let new_level = updater(&backlight_control, cur_brightness);
|
||||||
let new_level = cmp::min(backlight_control.max_level, new_level);
|
let new_level = cmp::min(backlight_control.max_level, new_level);
|
||||||
|
@ -24,7 +24,8 @@ pub enum BlankerState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct UnlockDialog<'a> {
|
struct UnlockDialog<'a> {
|
||||||
monitor: Monitor,
|
monitor_geom: x::Rectangle,
|
||||||
|
blanker_window: x::Window,
|
||||||
embedder: Embedder<'a>,
|
embedder: Embedder<'a>,
|
||||||
event_to_forward: Option<xcb::Event>,
|
event_to_forward: Option<xcb::Event>,
|
||||||
child: Child,
|
child: Child,
|
||||||
@ -204,9 +205,9 @@ impl<'a> Screensaver<'a> {
|
|||||||
},
|
},
|
||||||
xcb::Event::X(x::Event::ConfigureNotify(ev)) if ev.window() == self.embedder_window() => {
|
xcb::Event::X(x::Event::ConfigureNotify(ev)) if ev.window() == self.embedder_window() => {
|
||||||
if let Some(unlock_dialog) = &self.unlock_dialog {
|
if let Some(unlock_dialog) = &self.unlock_dialog {
|
||||||
let monitor = &unlock_dialog.monitor;
|
let monitor_geom = &unlock_dialog.monitor_geom;
|
||||||
let x = std::cmp::max(0, monitor.x as i32 + monitor.width as i32 / 2 - ev.width() as i32 / 2);
|
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.y as i32 + monitor.height as i32 / 2 - ev.height() 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 {
|
if x != ev.x() as i32 || y != ev.y() as i32 {
|
||||||
conn.send_and_check_request(&x::ConfigureWindow {
|
conn.send_and_check_request(&x::ConfigureWindow {
|
||||||
window: unlock_dialog.embedder.embedder_window(),
|
window: unlock_dialog.embedder.embedder_window(),
|
||||||
@ -274,7 +275,7 @@ impl<'a> Screensaver<'a> {
|
|||||||
},
|
},
|
||||||
Some(unlock_dialog) => {
|
Some(unlock_dialog) => {
|
||||||
let mut cookies = Vec::new();
|
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 {
|
cookies.push(conn.send_request_checked(&x::ConfigureWindow {
|
||||||
window: win,
|
window: win,
|
||||||
value_list: &[
|
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>> {
|
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 {
|
for monitor in &self.monitors {
|
||||||
let cookie = conn.send_request(&x::QueryPointer {
|
let cookie = conn.send_request(&x::QueryPointer {
|
||||||
window: monitor.root,
|
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
|
&& 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
|
&& 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;
|
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");
|
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 {
|
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)?;
|
let embedder = Embedder::start(conn, unlock_window, client_window)?;
|
||||||
|
|
||||||
Ok(UnlockDialog {
|
Ok(UnlockDialog {
|
||||||
monitor: *pointer_monitor,
|
monitor_geom,
|
||||||
|
blanker_window,
|
||||||
embedder,
|
embedder,
|
||||||
event_to_forward: trigger_event,
|
event_to_forward: trigger_event,
|
||||||
child,
|
child,
|
||||||
|
Loading…
Reference in New Issue
Block a user