refactor x11 cursor changing code into x11/cursor.rs
This commit is contained in:
parent
3ff8a471f3
commit
d156d42e69
125
src/x11/cursor.rs
Normal file
125
src/x11/cursor.rs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
use std::os::raw::{c_ulong, c_char};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::MouseCursor;
|
||||||
|
|
||||||
|
pub fn set_cursor(
|
||||||
|
xcb_connection: &mut crate::x11::XcbConnection,
|
||||||
|
window_id: u32,
|
||||||
|
cursor_cache: &mut HashMap<MouseCursor, c_ulong>,
|
||||||
|
mouse_cursor: MouseCursor,
|
||||||
|
) {
|
||||||
|
let display = xcb_connection.conn.get_raw_dpy();
|
||||||
|
|
||||||
|
let cursor = *cursor_cache
|
||||||
|
.entry(mouse_cursor)
|
||||||
|
.or_insert_with(|| get_cursor(display, mouse_cursor));
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if cursor != 0 {
|
||||||
|
x11::xlib::XDefineCursor(display, window_id as c_ulong, cursor);
|
||||||
|
}
|
||||||
|
x11::xlib::XFlush(display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cursor(display: *mut x11::xlib::Display, cursor: MouseCursor) -> c_ulong {
|
||||||
|
let load = |name: &[u8]| load_cursor(display, name);
|
||||||
|
let loadn = |names: &[&[u8]]| load_first_existing_cursor(display, names);
|
||||||
|
|
||||||
|
let mut cursor = match cursor {
|
||||||
|
MouseCursor::Default => load(b"left_ptr\0"),
|
||||||
|
MouseCursor::Hand => loadn(&[b"hand2\0", b"hand1\0"]),
|
||||||
|
MouseCursor::HandGrabbing => loadn(&[b"closedhand\0", b"grabbing\0"]),
|
||||||
|
MouseCursor::Help => load(b"question_arrow\0"),
|
||||||
|
|
||||||
|
MouseCursor::Hidden => create_empty_cursor(display),
|
||||||
|
|
||||||
|
MouseCursor::Text => loadn(&[b"text\0", b"xterm\0"]),
|
||||||
|
MouseCursor::VerticalText => load(b"vertical-text\0"),
|
||||||
|
|
||||||
|
MouseCursor::Working => load(b"watch\0"),
|
||||||
|
MouseCursor::PtrWorking => load(b"left_ptr_watch\0"),
|
||||||
|
|
||||||
|
MouseCursor::NotAllowed => load(b"crossed_circle\0"),
|
||||||
|
MouseCursor::PtrNotAllowed => loadn(&[b"no-drop\0", b"crossed_circle\0"]),
|
||||||
|
|
||||||
|
MouseCursor::ZoomIn => load(b"zoom-in\0"),
|
||||||
|
MouseCursor::ZoomOut => load(b"zoom-out\0"),
|
||||||
|
|
||||||
|
MouseCursor::Alias => load(b"link\0"),
|
||||||
|
MouseCursor::Copy => load(b"copy\0"),
|
||||||
|
MouseCursor::Move => load(b"move\0"),
|
||||||
|
MouseCursor::AllScroll => load(b"all-scroll\0"),
|
||||||
|
MouseCursor::Cell => load(b"plus\0"),
|
||||||
|
MouseCursor::Crosshair => load(b"crosshair\0"),
|
||||||
|
|
||||||
|
MouseCursor::EResize => load(b"right_side\0"),
|
||||||
|
MouseCursor::NResize => load(b"top_side\0"),
|
||||||
|
MouseCursor::NeResize => load(b"top_right_corner\0"),
|
||||||
|
MouseCursor::NwResize => load(b"top_left_corner\0"),
|
||||||
|
MouseCursor::SResize => load(b"bottom_side\0"),
|
||||||
|
MouseCursor::SeResize => load(b"bottom_right_corner\0"),
|
||||||
|
MouseCursor::SwResize => load(b"bottom_left_corner\0"),
|
||||||
|
MouseCursor::WResize => load(b"left_side\0"),
|
||||||
|
MouseCursor::EwResize => load(b"h_double_arrow\0"),
|
||||||
|
MouseCursor::NsResize => load(b"v_double_arrow\0"),
|
||||||
|
MouseCursor::NwseResize => loadn(&[b"bd_double_arrow\0", b"size_bdiag\0"]),
|
||||||
|
MouseCursor::NeswResize => loadn(&[b"fd_double_arrow\0", b"size_fdiag\0"]),
|
||||||
|
MouseCursor::ColResize => loadn(&[b"split_h\0", b"h_double_arrow\0"]),
|
||||||
|
MouseCursor::RowResize => loadn(&[b"split_v\0", b"v_double_arrow\0"]),
|
||||||
|
};
|
||||||
|
|
||||||
|
if cursor == 0 {
|
||||||
|
cursor = load(b"left_ptr\0")
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_cursor(display: *mut x11::xlib::Display, name: &[u8]) -> c_ulong {
|
||||||
|
unsafe {
|
||||||
|
x11::xcursor::XcursorLibraryLoadCursor(display, name.as_ptr() as *const c_char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_first_existing_cursor(display: *mut x11::xlib::Display, names: &[&[u8]]) -> c_ulong {
|
||||||
|
for name in names.iter() {
|
||||||
|
let xcursor = load_cursor(display, name);
|
||||||
|
if xcursor != 0 {
|
||||||
|
return xcursor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_empty_cursor(display: *mut x11::xlib::Display,) -> c_ulong {
|
||||||
|
let data = 0;
|
||||||
|
let pixmap = unsafe {
|
||||||
|
let screen = x11::xlib::XDefaultScreen(display);
|
||||||
|
let window = x11::xlib::XRootWindow(display, screen);
|
||||||
|
x11::xlib::XCreateBitmapFromData(display, window, &data, 1, 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
if pixmap == 0 {
|
||||||
|
panic!("failed to allocate pixmap for cursor");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// We don't care about this color, since it only fills bytes
|
||||||
|
// in the pixmap which are not 0 in the mask.
|
||||||
|
let mut dummy_color = maybe_uninit::MaybeUninit::uninit();
|
||||||
|
let cursor = x11::xlib::XCreatePixmapCursor(
|
||||||
|
display,
|
||||||
|
pixmap,
|
||||||
|
pixmap,
|
||||||
|
dummy_color.as_mut_ptr(),
|
||||||
|
dummy_color.as_mut_ptr(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
x11::xlib::XFreePixmap(display, pixmap);
|
||||||
|
|
||||||
|
cursor
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,3 +3,5 @@ use xcb_connection::XcbConnection;
|
||||||
|
|
||||||
mod window;
|
mod window;
|
||||||
pub use window::*;
|
pub use window::*;
|
||||||
|
|
||||||
|
mod cursor;
|
|
@ -1,4 +1,4 @@
|
||||||
use std::os::raw::{c_ulong, c_void, c_char};
|
use std::os::raw::{c_ulong, c_void};
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::time::*;
|
use std::time::*;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
@ -181,19 +181,12 @@ impl Window {
|
||||||
|
|
||||||
pub fn set_mouse_cursor(&mut self, mouse_cursor: MouseCursor) {
|
pub fn set_mouse_cursor(&mut self, mouse_cursor: MouseCursor) {
|
||||||
if self.mouse_cursor != mouse_cursor {
|
if self.mouse_cursor != mouse_cursor {
|
||||||
let display = self.xcb_connection.conn.get_raw_dpy();
|
crate::x11::cursor::set_cursor(
|
||||||
|
&mut self.xcb_connection,
|
||||||
let cursor = *self
|
self.window_id,
|
||||||
.cursor_cache
|
&mut self.cursor_cache,
|
||||||
.entry(mouse_cursor)
|
mouse_cursor
|
||||||
.or_insert_with(|| get_cursor(display, mouse_cursor));
|
);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
if cursor != 0 {
|
|
||||||
x11::xlib::XDefineCursor(display, self.window_id as c_ulong, cursor);
|
|
||||||
}
|
|
||||||
x11::xlib::XFlush(display);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mouse_cursor = mouse_cursor;
|
self.mouse_cursor = mouse_cursor;
|
||||||
}
|
}
|
||||||
|
@ -426,104 +419,3 @@ fn mouse_id(id: u8) -> MouseButton {
|
||||||
id => MouseButton::Other(id),
|
id => MouseButton::Other(id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_cursor(display: *mut x11::xlib::Display, name: &[u8]) -> c_ulong {
|
|
||||||
unsafe {
|
|
||||||
x11::xcursor::XcursorLibraryLoadCursor(display, name.as_ptr() as *const c_char)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_first_existing_cursor(display: *mut x11::xlib::Display, names: &[&[u8]]) -> c_ulong {
|
|
||||||
for name in names.iter() {
|
|
||||||
let xcursor = load_cursor(display, name);
|
|
||||||
if xcursor != 0 {
|
|
||||||
return xcursor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_cursor(display: *mut x11::xlib::Display, cursor: MouseCursor) -> c_ulong {
|
|
||||||
let load = |name: &[u8]| load_cursor(display, name);
|
|
||||||
let loadn = |names: &[&[u8]]| load_first_existing_cursor(display, names);
|
|
||||||
|
|
||||||
let mut cursor = match cursor {
|
|
||||||
MouseCursor::Default => load(b"left_ptr\0"),
|
|
||||||
MouseCursor::Hand => loadn(&[b"hand2\0", b"hand1\0"]),
|
|
||||||
MouseCursor::HandGrabbing => loadn(&[b"closedhand\0", b"grabbing\0"]),
|
|
||||||
MouseCursor::Help => load(b"question_arrow\0"),
|
|
||||||
|
|
||||||
MouseCursor::Hidden => create_empty_cursor(display),
|
|
||||||
|
|
||||||
MouseCursor::Text => loadn(&[b"text\0", b"xterm\0"]),
|
|
||||||
MouseCursor::VerticalText => load(b"vertical-text\0"),
|
|
||||||
|
|
||||||
MouseCursor::Working => load(b"watch\0"),
|
|
||||||
MouseCursor::PtrWorking => load(b"left_ptr_watch\0"),
|
|
||||||
|
|
||||||
MouseCursor::NotAllowed => load(b"crossed_circle\0"),
|
|
||||||
MouseCursor::PtrNotAllowed => loadn(&[b"no-drop\0", b"crossed_circle\0"]),
|
|
||||||
|
|
||||||
MouseCursor::ZoomIn => load(b"zoom-in\0"),
|
|
||||||
MouseCursor::ZoomOut => load(b"zoom-out\0"),
|
|
||||||
|
|
||||||
MouseCursor::Alias => load(b"link\0"),
|
|
||||||
MouseCursor::Copy => load(b"copy\0"),
|
|
||||||
MouseCursor::Move => load(b"move\0"),
|
|
||||||
MouseCursor::AllScroll => load(b"all-scroll\0"),
|
|
||||||
MouseCursor::Cell => load(b"plus\0"),
|
|
||||||
MouseCursor::Crosshair => load(b"crosshair\0"),
|
|
||||||
|
|
||||||
MouseCursor::EResize => load(b"right_side\0"),
|
|
||||||
MouseCursor::NResize => load(b"top_side\0"),
|
|
||||||
MouseCursor::NeResize => load(b"top_right_corner\0"),
|
|
||||||
MouseCursor::NwResize => load(b"top_left_corner\0"),
|
|
||||||
MouseCursor::SResize => load(b"bottom_side\0"),
|
|
||||||
MouseCursor::SeResize => load(b"bottom_right_corner\0"),
|
|
||||||
MouseCursor::SwResize => load(b"bottom_left_corner\0"),
|
|
||||||
MouseCursor::WResize => load(b"left_side\0"),
|
|
||||||
MouseCursor::EwResize => load(b"h_double_arrow\0"),
|
|
||||||
MouseCursor::NsResize => load(b"v_double_arrow\0"),
|
|
||||||
MouseCursor::NwseResize => loadn(&[b"bd_double_arrow\0", b"size_bdiag\0"]),
|
|
||||||
MouseCursor::NeswResize => loadn(&[b"fd_double_arrow\0", b"size_fdiag\0"]),
|
|
||||||
MouseCursor::ColResize => loadn(&[b"split_h\0", b"h_double_arrow\0"]),
|
|
||||||
MouseCursor::RowResize => loadn(&[b"split_v\0", b"v_double_arrow\0"]),
|
|
||||||
};
|
|
||||||
|
|
||||||
if cursor == 0 {
|
|
||||||
cursor = load(b"left_ptr\0")
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_empty_cursor(display: *mut x11::xlib::Display,) -> c_ulong {
|
|
||||||
let data = 0;
|
|
||||||
let pixmap = unsafe {
|
|
||||||
let screen = x11::xlib::XDefaultScreen(display);
|
|
||||||
let window = x11::xlib::XRootWindow(display, screen);
|
|
||||||
x11::xlib::XCreateBitmapFromData(display, window, &data, 1, 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
if pixmap == 0 {
|
|
||||||
panic!("failed to allocate pixmap for cursor");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// We don't care about this color, since it only fills bytes
|
|
||||||
// in the pixmap which are not 0 in the mask.
|
|
||||||
let mut dummy_color = maybe_uninit::MaybeUninit::uninit();
|
|
||||||
let cursor = x11::xlib::XCreatePixmapCursor(
|
|
||||||
display,
|
|
||||||
pixmap,
|
|
||||||
pixmap,
|
|
||||||
dummy_color.as_mut_ptr(),
|
|
||||||
dummy_color.as_mut_ptr(),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
x11::xlib::XFreePixmap(display, pixmap);
|
|
||||||
|
|
||||||
cursor
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue