Merge pull request #767 from emilio/x11-cursor-hide

x11: Add cursor hiding
This commit is contained in:
tomaka 2016-04-17 19:36:34 +02:00
commit e467819794

View file

@ -840,20 +840,14 @@ impl Window {
pub fn set_cursor(&self, cursor: MouseCursor) { pub fn set_cursor(&self, cursor: MouseCursor) {
unsafe { unsafe {
use std::ffi::CString;
let load = |name: &str| { let load = |name: &str| {
let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); self.load_cursor(name)
return (self.x.display.xcursor.XcursorLibraryLoadCursor)(self.x.display.display, c_string.as_ptr());
}; };
let loadn = |names: &[&str]| { let loadn = |names: &[&str]| {
for name in names.iter() { self.load_first_existing_cursor(names)
let xcursor = load(*name);
if xcursor != 0 {
return xcursor;
}
}
return 0;
}; };
// Try multiple names in some cases where the name // Try multiple names in some cases where the name
// differs on the desktop environments or themes. // differs on the desktop environments or themes.
// //
@ -902,8 +896,7 @@ impl Window {
MouseCursor::ZoomIn => load("zoom-in"), MouseCursor::ZoomIn => load("zoom-in"),
MouseCursor::ZoomOut => load("zoom-out"), MouseCursor::ZoomOut => load("zoom-out"),
// TODO: Hide cursor MouseCursor::NoneCursor => self.create_empty_cursor(),
MouseCursor::NoneCursor => 0,
}; };
(self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, xcursor); (self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, xcursor);
@ -914,6 +907,51 @@ 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) -> 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 {
// 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: ffi::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> { pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
use CursorState::{ Grab, Normal, Hide }; use CursorState::{ Grab, Normal, Hide };
@ -932,13 +970,10 @@ impl Window {
}, },
Normal => {}, Normal => {},
Hide => { Hide => {
// NB: Calling XDefineCursor with None (aka 0)
// as a value resets the cursor to the default.
unsafe { unsafe {
let xcursor = (self.x.display.xlib.XCreateFontCursor)(self.x.display.display, 68/*XC_left_ptr*/); (self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, 0);
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);
} }
}, },
} }
@ -947,18 +982,13 @@ impl Window {
match state { match state {
Normal => Ok(()), Normal => Ok(()),
Hide => { Hide => {
let data = &[0, 0, 0, 0, 0, 0, 0, 0];
unsafe { unsafe {
let mut black = ffi::XColor { let cursor = self.create_empty_cursor();
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);
(self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, cursor); (self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, cursor);
self.x.display.check_errors().expect("Failed to call XDefineCursor"); if cursor != 0 {
(self.x.display.xlib.XFreeCursor)(self.x.display.display, cursor); (self.x.display.xlib.XFreeCursor)(self.x.display.display, cursor);
(self.x.display.xlib.XFreePixmap)(self.x.display.display, bitmap); }
self.x.display.check_errors().expect("Failed to call XDefineCursor or free the empty cursor");
} }
Ok(()) Ok(())
}, },