From 51aeb27d7e231227c34bc822da3e7f27b42b54f4 Mon Sep 17 00:00:00 2001 From: Emilio Cobos Álvarez Date: Sun, 17 Apr 2016 17:32:34 +0200 Subject: x11: Add cursor hiding The created cursor could be cached and whatnot, but I'm not sure it deserves the complexity. --- src/api/x11/window.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/api/x11/window.rs b/src/api/x11/window.rs index b524795..85ad70d 100644 --- a/src/api/x11/window.rs +++ b/src/api/x11/window.rs @@ -11,6 +11,7 @@ use std::sync::{Arc, Mutex}; use std::os::raw::c_long; use std::thread; use std::time::Duration; +use x11_dl::xlib; use Api; use ContextError; @@ -902,8 +903,7 @@ impl Window { MouseCursor::ZoomIn => load("zoom-in"), MouseCursor::ZoomOut => load("zoom-out"), - // TODO: Hide cursor - MouseCursor::NoneCursor => 0, + MouseCursor::NoneCursor => self.create_empty_cursor(), }; (self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, xcursor); @@ -914,6 +914,34 @@ impl Window { } } + // TODO: This could maybe be cached. I don't think it's worth + // the complexity, since cursor changes are not so common, + // and this is just allocating a 1x1 pixmap... + fn create_empty_cursor(&self) -> xlib::Cursor { + use std::mem; + + let data = 0; + + unsafe { + let pixmap = (self.x.display.xlib.XCreateBitmapFromData)(self.x.display.display, self.x.window, &data, 1, 1); + if pixmap == 0 { + // Failed to allocate + return 0; + } + + // We don't care about this color, since it only fills bytes + // in the pixmap which are not 0 in the mask. + let dummy_color: xlib::XColor = mem::uninitialized(); + let cursor = (self.x.display.xlib.XCreatePixmapCursor)(self.x.display.display, + pixmap, + pixmap, + &dummy_color as *const _ as *mut _, + &dummy_color as *const _ as *mut _, 0, 0); + (self.x.display.xlib.XFreePixmap)(self.x.display.display, pixmap); + cursor + } + } + pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> { use CursorState::{ Grab, Normal, Hide }; -- cgit v1.2.3 From 0918fe4d9c3639d1fa5fdfae0aad8c229d40ddc0 Mon Sep 17 00:00:00 2001 From: Emilio Cobos Álvarez Date: Sun, 17 Apr 2016 18:14:53 +0200 Subject: x11: Refactor NoneCursor logic so it applies to CursorState::Hide too --- src/api/x11/window.rs | 66 ++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/src/api/x11/window.rs b/src/api/x11/window.rs index 85ad70d..dc7fa62 100644 --- a/src/api/x11/window.rs +++ b/src/api/x11/window.rs @@ -11,7 +11,6 @@ use std::sync::{Arc, Mutex}; use std::os::raw::c_long; use std::thread; use std::time::Duration; -use x11_dl::xlib; use Api; use ContextError; @@ -841,20 +840,14 @@ impl Window { pub fn set_cursor(&self, cursor: MouseCursor) { unsafe { - use std::ffi::CString; - let load = |name :&str| { - let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); - return (self.x.display.xcursor.XcursorLibraryLoadCursor)(self.x.display.display, c_string.as_ptr()); + let load = |name: &str| { + self.load_cursor(name) }; - let loadn = |names :&[&str]| { - for name in names.iter() { - let xcursor = load(*name); - if xcursor != 0 { - return xcursor; - } - } - return 0; + + let loadn = |names: &[&str]| { + self.load_first_existing_cursor(names) }; + // Try multiple names in some cases where the name // differs on the desktop environments or themes. // @@ -914,14 +907,31 @@ impl Window { } } + fn load_cursor(&self, name: &str) -> ffi::Cursor { + use std::ffi::CString; + unsafe { + let c_string = CString::new(name.as_bytes()).unwrap(); + (self.x.display.xcursor.XcursorLibraryLoadCursor)(self.x.display.display, c_string.as_ptr()) + } + } + + fn load_first_existing_cursor(&self, names :&[&str]) -> ffi::Cursor { + for name in names.iter() { + let xcursor = self.load_cursor(name); + if xcursor != 0 { + return xcursor; + } + } + 0 + } + // TODO: This could maybe be cached. I don't think it's worth // the complexity, since cursor changes are not so common, // and this is just allocating a 1x1 pixmap... - fn create_empty_cursor(&self) -> xlib::Cursor { + fn create_empty_cursor(&self) -> ffi::Cursor { use std::mem; let data = 0; - unsafe { let pixmap = (self.x.display.xlib.XCreateBitmapFromData)(self.x.display.display, self.x.window, &data, 1, 1); if pixmap == 0 { @@ -931,7 +941,7 @@ impl Window { // We don't care about this color, since it only fills bytes // in the pixmap which are not 0 in the mask. - let dummy_color: xlib::XColor = mem::uninitialized(); + let dummy_color: ffi::XColor = mem::uninitialized(); let cursor = (self.x.display.xlib.XCreatePixmapCursor)(self.x.display.display, pixmap, pixmap, @@ -960,13 +970,10 @@ impl Window { }, Normal => {}, Hide => { + // NB: Calling XDefineCursor with None (aka 0) + // as a value resets the cursor to the default. unsafe { - let xcursor = (self.x.display.xlib.XCreateFontCursor)(self.x.display.display, 68/*XC_left_ptr*/); - self.x.display.check_errors().expect("Failed to call XCreateFontCursor"); - (self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, xcursor); - self.x.display.check_errors().expect("Failed to call XDefineCursor"); - (self.x.display.xlib.XFlush)(self.x.display.display); - (self.x.display.xlib.XFreeCursor)(self.x.display.display, xcursor); + (self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, 0); } }, } @@ -975,18 +982,13 @@ impl Window { match state { Normal => Ok(()), Hide => { - let data = &[0, 0, 0, 0, 0, 0, 0, 0]; unsafe { - let mut black = ffi::XColor { - red: 0, green: 0, blue: 0, - pad: 0, pixel: 0, flags: 0, - }; - let bitmap = (self.x.display.xlib.XCreateBitmapFromData)(self.x.display.display, self.x.window, data.as_ptr(), 8, 8); - let cursor = (self.x.display.xlib.XCreatePixmapCursor)(self.x.display.display, bitmap, bitmap, &mut black, &mut black, 0, 0); + let cursor = self.create_empty_cursor(); (self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, cursor); - self.x.display.check_errors().expect("Failed to call XDefineCursor"); - (self.x.display.xlib.XFreeCursor)(self.x.display.display, cursor); - (self.x.display.xlib.XFreePixmap)(self.x.display.display, bitmap); + if cursor != 0 { + (self.x.display.xlib.XFreeCursor)(self.x.display.display, cursor); + } + self.x.display.check_errors().expect("Failed to call XDefineCursor or free the empty cursor"); } Ok(()) }, -- cgit v1.2.3