From adc8fe0974560a07e3869cb5f2b335dbdb421ca6 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sun, 13 Sep 2020 09:19:05 -0500 Subject: [PATCH 1/8] Add mouse cursor to Window --- src/mouse_cursor.rs | 1 + src/x11/window.rs | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/mouse_cursor.rs b/src/mouse_cursor.rs index 0fdcf78..4460397 100644 --- a/src/mouse_cursor.rs +++ b/src/mouse_cursor.rs @@ -9,6 +9,7 @@ pub enum MouseCursor { Grabbing, ResizingHorizontally, ResizingVertically, + Hidden, } impl Default for MouseCursor { diff --git a/src/x11/window.rs b/src/x11/window.rs index 325aae6..4ad84b4 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -7,14 +7,15 @@ use raw_window_handle::{unix::XlibHandle, HasRawWindowHandle, RawWindowHandle}; use super::XcbConnection; use crate::{ - Event, KeyboardEvent, MouseButton, MouseEvent, Parent, ScrollDelta, WindowEvent, WindowHandler, - WindowInfo, WindowOpenOptions, + Event, KeyboardEvent, MouseButton, MouseCursor, MouseEvent, Parent, ScrollDelta, WindowEvent, + WindowHandler,WindowInfo, WindowOpenOptions, }; pub struct Window { xcb_connection: XcbConnection, window_id: u32, window_info: WindowInfo, + mouse_cursor: MouseCursor, frame_interval: Duration, event_loop_running: bool, @@ -145,6 +146,7 @@ impl Window { xcb_connection, window_id, window_info, + mouse_cursor: MouseCursor::default(), frame_interval: Duration::from_millis(15), event_loop_running: false, @@ -162,6 +164,33 @@ impl Window { &self.window_info } + /* + pub fn set_mouse_cursor(&mut self, mouse_cursor: MouseCursor) { + if self.mouse_cursor != mouse_cursor { + if mouse_cursor == MouseCursor::Hidden { + xcb::change_cursor(&self.xcb_connection.conn, xcb::CW_CURSOR, xcb::CURSOR_NONE); + } else { + let cursor_name = match mouse_cursor { + MouseCursor::Idle => "pointer", + MouseCursor::Pointer => "pointer", + MouseCursor::Grab => "hand1", + MouseCursor::Text => "xterm", + MouseCursor::Crosshair => "crosshair", + MouseCursor::Working => "watch", + MouseCursor::Grabbing => "hand2", + MouseCursor::ResizingHorizontally => "sizing", + MouseCursor::ResizingVertically => "sizing", + _ => "pointer", + }; + } + + + + self.mouse_cursor = mouse_cursor; + } + } + */ + #[inline] fn drain_xcb_events(&mut self, handler: &mut H) { while let Some(event) = self.xcb_connection.conn.poll_for_event() { From d84a1fde44383c7f7a37591960b2cef903b43662 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sun, 13 Sep 2020 18:23:51 -0500 Subject: [PATCH 2/8] Add set_mouse_cursor method to X11 Window --- Cargo.toml | 3 +- examples/open_window.rs | 4 +- src/mouse_cursor.rs | 52 +++++++++++---- src/x11/window.rs | 139 ++++++++++++++++++++++++++++++++++------ 4 files changed, 164 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1b0453c..e5cc3ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,9 @@ raw-window-handle = "0.3.3" [target.'cfg(target_os="linux")'.dependencies] xcb = { version = "0.9", features = ["thread", "xlib_xcb", "dri2"] } -x11 = { version = "2.18", features = ["xlib"] } +x11 = { version = "2.18", features = ["xlib", "xcursor"] } xcb-util = { version = "0.3", features = ["icccm"] } +maybe-uninit = "2.0" libc = "0.2" nix = "0.18" diff --git a/examples/open_window.rs b/examples/open_window.rs index 911a039..6a1ac72 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -13,7 +13,9 @@ impl WindowHandler for MyProgram { fn on_event(&mut self, _window: &mut Window, event: Event) { match event { - Event::Mouse(e) => println!("Mouse event: {:?}", e), + Event::Mouse(e) => { + println!("Mouse event: {:?}", e); + }, Event::Keyboard(e) => println!("Keyboard event: {:?}", e), Event::Window(e) => println!("Window event: {:?}", e), } diff --git a/src/mouse_cursor.rs b/src/mouse_cursor.rs index 4460397..16fc199 100644 --- a/src/mouse_cursor.rs +++ b/src/mouse_cursor.rs @@ -1,19 +1,49 @@ -#[derive(Debug, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)] +#[derive(Debug, Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash)] pub enum MouseCursor { - Idle, - Pointer, - Grab, - Text, - Crosshair, - Working, - Grabbing, - ResizingHorizontally, - ResizingVertically, + Default, + Hand, + HandGrabbing, + Help, + Hidden, + + Text, + VerticalText, + + Working, + PtrWorking, + + NotAllowed, + PtrNotAllowed, + + ZoomIn, + ZoomOut, + + Alias, + Copy, + Move, + AllScroll, + Cell, + Crosshair, + + EResize, + NResize, + NeResize, + NwResize, + SResize, + SeResize, + SwResize, + WResize, + EwResize, + NsResize, + NwseResize, + NeswResize, + ColResize, + RowResize, } impl Default for MouseCursor { fn default() -> Self { - Self::Idle + Self::Default } } diff --git a/src/x11/window.rs b/src/x11/window.rs index ef4e00b..2336b78 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -1,7 +1,8 @@ -use std::os::raw::{c_ulong, c_void}; -use std::sync::mpsc; +use std::os::raw::{c_ulong, c_void, c_char}; +use std::sync::{mpsc, Mutex}; use std::time::*; use std::thread; +use std::collections::HashMap; use raw_window_handle::{ unix::XlibHandle, @@ -20,6 +21,7 @@ pub struct Window { window_id: u32, window_info: WindowInfo, mouse_cursor: MouseCursor, + cursor_cache: HashMap, frame_interval: Duration, event_loop_running: bool, @@ -157,6 +159,7 @@ impl Window { window_id, window_info, mouse_cursor: MouseCursor::default(), + cursor_cache: HashMap::new(), frame_interval: Duration::from_millis(15), event_loop_running: false, @@ -176,32 +179,25 @@ impl Window { &self.window_info } - /* pub fn set_mouse_cursor(&mut self, mouse_cursor: MouseCursor) { if self.mouse_cursor != mouse_cursor { - if mouse_cursor == MouseCursor::Hidden { - xcb::change_cursor(&self.xcb_connection.conn, xcb::CW_CURSOR, xcb::CURSOR_NONE); - } else { - let cursor_name = match mouse_cursor { - MouseCursor::Idle => "pointer", - MouseCursor::Pointer => "pointer", - MouseCursor::Grab => "hand1", - MouseCursor::Text => "xterm", - MouseCursor::Crosshair => "crosshair", - MouseCursor::Working => "watch", - MouseCursor::Grabbing => "hand2", - MouseCursor::ResizingHorizontally => "sizing", - MouseCursor::ResizingVertically => "sizing", - _ => "pointer", - }; - } + let display = self.xcb_connection.conn.get_raw_dpy(); - + let cursor = *self + .cursor_cache + .entry(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; } } - */ #[inline] fn drain_xcb_events(&mut self, handler: &mut H) { @@ -430,3 +426,104 @@ fn mouse_id(id: u8) -> MouseButton { 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 + } +} \ No newline at end of file From fea93a419211480ee9e2a29afa9f169a7410b782 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sun, 13 Sep 2020 18:32:38 -0500 Subject: [PATCH 3/8] Add libxcursor dependency --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 871b27a..3988a06 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -14,7 +14,7 @@ jobs: - name: Install XCB and GL dependencies run: | sudo apt update - sudo apt install libx11-xcb-dev libxcb-dri2-0-dev libgl1-mesa-dev libxcb-icccm4-dev + sudo apt install libx11-xcb-dev libxcb-dri2-0-dev libgl1-mesa-dev libxcb-icccm4-dev libxcursor if: contains(matrix.os, 'ubuntu') - name: Install rust stable uses: actions-rs/toolchain@v1 From ec174d0b9be28af4430472dbb8324ebecf64b5e4 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sun, 13 Sep 2020 18:33:51 -0500 Subject: [PATCH 4/8] Change dependency libxcursor to libxcursor-dev --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 3988a06..b4c7ea9 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -14,7 +14,7 @@ jobs: - name: Install XCB and GL dependencies run: | sudo apt update - sudo apt install libx11-xcb-dev libxcb-dri2-0-dev libgl1-mesa-dev libxcb-icccm4-dev libxcursor + sudo apt install libx11-xcb-dev libxcb-dri2-0-dev libgl1-mesa-dev libxcb-icccm4-dev libxcursor-dev if: contains(matrix.os, 'ubuntu') - name: Install rust stable uses: actions-rs/toolchain@v1 From 53debfc7064cdb9091c17f896f905ba8ce27eee9 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sun, 13 Sep 2020 18:39:13 -0500 Subject: [PATCH 5/8] remove unused Mutex import --- src/x11/window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x11/window.rs b/src/x11/window.rs index 2336b78..7063685 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -1,5 +1,5 @@ use std::os::raw::{c_ulong, c_void, c_char}; -use std::sync::{mpsc, Mutex}; +use std::sync::mpsc; use std::time::*; use std::thread; use std::collections::HashMap; From 225cbab22aee7dad355fea88bfd5b16b98d1aad7 Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sun, 13 Sep 2020 18:44:53 -0500 Subject: [PATCH 6/8] format example --- examples/open_window.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/open_window.rs b/examples/open_window.rs index 6a1ac72..e67e14e 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -13,9 +13,7 @@ impl WindowHandler for MyProgram { fn on_event(&mut self, _window: &mut Window, event: Event) { match event { - Event::Mouse(e) => { - println!("Mouse event: {:?}", e); - }, + Event::Mouse(e) => { println!("Mouse event: {:?}", e); }, Event::Keyboard(e) => println!("Keyboard event: {:?}", e), Event::Window(e) => println!("Window event: {:?}", e), } From 3ff8a471f3cce10df31c2dc2886d87319f6bdb1b Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sun, 13 Sep 2020 18:48:18 -0500 Subject: [PATCH 7/8] format example again --- examples/open_window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/open_window.rs b/examples/open_window.rs index e67e14e..911a039 100644 --- a/examples/open_window.rs +++ b/examples/open_window.rs @@ -13,7 +13,7 @@ impl WindowHandler for MyProgram { fn on_event(&mut self, _window: &mut Window, event: Event) { match event { - Event::Mouse(e) => { println!("Mouse event: {:?}", e); }, + Event::Mouse(e) => println!("Mouse event: {:?}", e), Event::Keyboard(e) => println!("Keyboard event: {:?}", e), Event::Window(e) => println!("Window event: {:?}", e), } From d156d42e69ddcab73b7e077d3d930883493f8e3a Mon Sep 17 00:00:00 2001 From: Billy Messenger Date: Sun, 13 Sep 2020 19:01:18 -0500 Subject: [PATCH 8/8] refactor x11 cursor changing code into x11/cursor.rs --- src/x11/cursor.rs | 125 ++++++++++++++++++++++++++++++++++++++++++++++ src/x11/mod.rs | 2 + src/x11/window.rs | 122 +++----------------------------------------- 3 files changed, 134 insertions(+), 115 deletions(-) create mode 100644 src/x11/cursor.rs diff --git a/src/x11/cursor.rs b/src/x11/cursor.rs new file mode 100644 index 0000000..3a7142e --- /dev/null +++ b/src/x11/cursor.rs @@ -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, + 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 + } +} \ No newline at end of file diff --git a/src/x11/mod.rs b/src/x11/mod.rs index 9d56388..ecf4080 100644 --- a/src/x11/mod.rs +++ b/src/x11/mod.rs @@ -3,3 +3,5 @@ use xcb_connection::XcbConnection; mod window; pub use window::*; + +mod cursor; \ No newline at end of file diff --git a/src/x11/window.rs b/src/x11/window.rs index 7063685..7501871 100644 --- a/src/x11/window.rs +++ b/src/x11/window.rs @@ -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::time::*; use std::thread; @@ -181,19 +181,12 @@ impl Window { pub fn set_mouse_cursor(&mut self, mouse_cursor: MouseCursor) { if self.mouse_cursor != mouse_cursor { - let display = self.xcb_connection.conn.get_raw_dpy(); - - let cursor = *self - .cursor_cache - .entry(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); - } + crate::x11::cursor::set_cursor( + &mut self.xcb_connection, + self.window_id, + &mut self.cursor_cache, + mouse_cursor + ); self.mouse_cursor = mouse_cursor; } @@ -425,105 +418,4 @@ fn mouse_id(id: u8) -> MouseButton { 7 => MouseButton::Forward, 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 - } } \ No newline at end of file