Use regular X11 rather than XFIXES to hide cursor

The semantics of the XFIXES cursor hide deal are annoying and make
things harder.
This commit is contained in:
Brian Tarricone 2022-05-27 18:05:55 -07:00
parent 344907f55a
commit a516a25a9f
2 changed files with 62 additions and 18 deletions

View File

@ -1,8 +1,8 @@
use log::{debug, warn}; use log::{debug, warn};
use std::{cmp, cell::RefCell}; use std::cmp;
use xcb::{x, randr, xfixes, Xid}; 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_ATOM_NAME: &[u8] = b"Backlight";
const BACKLIGHT_FALLBACK_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 output: randr::Output,
pub blanker_window: x::Window, pub blanker_window: x::Window,
pub unlock_window: x::Window, pub unlock_window: x::Window,
pub blank_cursor: x::Cursor,
pub x: i16, pub x: i16,
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>,
} }
@ -52,6 +51,7 @@ impl Monitor {
let reply = conn.wait_for_reply(cookie)?; let reply = conn.wait_for_reply(cookie)?;
let (blanker_window, unlock_window) = create_windows(conn, &screen, &reply)?; 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(); let black_gc: x::Gcontext = conn.generate_id();
conn.send_and_check_request(&x::CreateGc { conn.send_and_check_request(&x::CreateGc {
@ -74,11 +74,11 @@ impl Monitor {
output: *output, output: *output,
blanker_window, blanker_window,
unlock_window, unlock_window,
blank_cursor,
x: reply.x(), x: reply.x(),
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(),
}); });
} }
@ -196,25 +196,24 @@ 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 let Err(err) = conn.send_and_check_request(&x::ChangeWindowAttributes {
if ok {
if let Err(err) = conn.send_and_check_request(&xfixes::ShowCursor {
window: self.blanker_window, window: self.blanker_window,
value_list: &[
x::Cw::Cursor(x::CURSOR_NONE),
],
}) { }) {
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);
}
} }
} }
pub fn hide_cursor(&self, conn: &xcb::Connection) { 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, window: self.blanker_window,
value_list: &[
x::Cw::Cursor(self.blank_cursor),
],
}) { }) {
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);
} }
} }
@ -353,6 +352,37 @@ fn create_windows(conn: &xcb::Connection, screen: &x::Screen, crtc_info: &randr:
Ok((blanker_window, unlock_window)) Ok((blanker_window, unlock_window))
} }
fn create_blank_cursor(conn: &xcb::Connection, screen: &x::Screen) -> xcb::Result<x::Cursor> {
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<Option<BacklightControl>> { fn find_backlight_control(conn: &xcb::Connection, output: randr::Output) -> xcb::Result<Option<BacklightControl>> {
for prop_name in [BACKLIGHT_ATOM_NAME, BACKLIGHT_FALLBACK_ATOM_NAME] { for prop_name in [BACKLIGHT_ATOM_NAME, BACKLIGHT_FALLBACK_ATOM_NAME] {
let property = create_atom(conn, prop_name)?; let property = create_atom(conn, prop_name)?;

View File

@ -32,6 +32,20 @@ pub fn create_atom(conn: &xcb::Connection, name: &[u8]) -> xcb::Result<x::Atom>
Ok(conn.wait_for_reply(cookie)?.atom()) 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<()> { pub fn destroy_gc(conn: &xcb::Connection, gc: x::Gcontext) -> xcb::Result<()> {
conn.send_and_check_request(&x::FreeGc { conn.send_and_check_request(&x::FreeGc {
gc, gc,