diff --git a/locker/src/monitor.rs b/locker/src/monitor.rs index 286c406..2d97249 100644 --- a/locker/src/monitor.rs +++ b/locker/src/monitor.rs @@ -1,8 +1,8 @@ use log::{debug, warn}; -use std::{cmp, cell::RefCell}; -use xcb::{x, randr, xfixes, Xid}; +use std::cmp; +use xcb::{x, randr, Xid}; -use bscreensaver_util::{BSCREENSAVER_WM_CLASS, create_atom}; +use bscreensaver_util::{BSCREENSAVER_WM_CLASS, create_atom, destroy_pixmap}; const BACKLIGHT_ATOM_NAME: &[u8] = b"Backlight"; const BACKLIGHT_FALLBACK_ATOM_NAME: &[u8] = b"BACKLIGHT"; @@ -20,12 +20,11 @@ pub struct Monitor { pub output: randr::Output, pub blanker_window: x::Window, pub unlock_window: x::Window, + pub blank_cursor: x::Cursor, pub x: i16, 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, } @@ -52,6 +51,7 @@ impl Monitor { let reply = conn.wait_for_reply(cookie)?; let (blanker_window, unlock_window) = create_windows(conn, &screen, &reply)?; + let blank_cursor = create_blank_cursor(conn, &screen)?; let black_gc: x::Gcontext = conn.generate_id(); conn.send_and_check_request(&x::CreateGc { @@ -74,11 +74,11 @@ impl Monitor { output: *output, blanker_window, unlock_window, + blank_cursor, x: reply.x(), y: reply.y(), width: reply.width(), height: reply.height(), - cursor_hidden: RefCell::new(0), backlight_control: backlight_control.ok().flatten(), }); } @@ -196,25 +196,24 @@ impl Monitor { } 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 { - window: self.blanker_window, - }) { - warn!("Failed to show cursor: {}", err); - } else { - let _ = self.cursor_hidden.try_borrow_mut().map(|mut ch| *ch -= 1); - } + if let Err(err) = conn.send_and_check_request(&x::ChangeWindowAttributes { + window: self.blanker_window, + value_list: &[ + x::Cw::Cursor(x::CURSOR_NONE), + ], + }) { + warn!("Failed to show cursor: {}", err); } } pub fn hide_cursor(&self, conn: &xcb::Connection) { - if let Err(err) = conn.send_and_check_request(&xfixes::HideCursor { + if let Err(err) = conn.send_and_check_request(&x::ChangeWindowAttributes { window: self.blanker_window, + value_list: &[ + x::Cw::Cursor(self.blank_cursor), + ], }) { warn!("Failed to hide cursor: {}", err); - } else { - let _ = self.cursor_hidden.try_borrow_mut().map(|mut ch| *ch += 1); } } @@ -353,6 +352,37 @@ fn create_windows(conn: &xcb::Connection, screen: &x::Screen, crtc_info: &randr: Ok((blanker_window, unlock_window)) } +fn create_blank_cursor(conn: &xcb::Connection, screen: &x::Screen) -> xcb::Result { + let blank_cursor: x::Cursor = conn.generate_id(); + let pixmap: x::Pixmap = conn.generate_id(); + + conn.send_and_check_request(&x::CreatePixmap { + pid: pixmap, + drawable: x::Drawable::Window(screen.root()), + depth: 1, + width: 1, + height: 1, + })?; + + conn.send_and_check_request(&x::CreateCursor { + cid: blank_cursor, + source: pixmap, + mask: x::PIXMAP_NONE, + fore_red: 0, + fore_green: 0, + fore_blue: 0, + back_red: 0, + back_green: 0, + back_blue: 0, + x: 0, + y: 0, + })?; + + destroy_pixmap(conn, pixmap)?; + + Ok(blank_cursor) +} + fn find_backlight_control(conn: &xcb::Connection, output: randr::Output) -> xcb::Result> { for prop_name in [BACKLIGHT_ATOM_NAME, BACKLIGHT_FALLBACK_ATOM_NAME] { let property = create_atom(conn, prop_name)?; diff --git a/util/src/lib.rs b/util/src/lib.rs index ed4cd4b..f8c3091 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -32,6 +32,20 @@ pub fn create_atom(conn: &xcb::Connection, name: &[u8]) -> xcb::Result Ok(conn.wait_for_reply(cookie)?.atom()) } +pub fn destroy_pixmap(conn: &xcb::Connection, pixmap: x::Pixmap) -> xcb::Result<()> { + conn.send_and_check_request(&x::FreePixmap { + pixmap, + })?; + Ok(()) +} + +pub fn destroy_cursor(conn: &xcb::Connection, cursor: x::Cursor) -> xcb::Result<()> { + conn.send_and_check_request(&x::FreeCursor { + cursor, + })?; + Ok(()) +} + pub fn destroy_gc(conn: &xcb::Connection, gc: x::Gcontext) -> xcb::Result<()> { conn.send_and_check_request(&x::FreeGc { gc,