|
1 | | -use std::os::raw::c_char; |
| 1 | +use std::error::Error; |
| 2 | + |
| 3 | +use x11rb::connection::Connection; |
| 4 | +use x11rb::cursor::Handle as CursorHandle; |
| 5 | +use x11rb::protocol::xproto::{ConnectionExt as _, Cursor}; |
| 6 | +use x11rb::xcb_ffi::XCBConnection; |
2 | 7 |
|
3 | 8 | use crate::MouseCursor; |
4 | 9 |
|
5 | | -fn create_empty_cursor(display: *mut x11::xlib::Display) -> Option<u32> { |
6 | | - let data = 0; |
7 | | - let pixmap = unsafe { |
8 | | - let screen = x11::xlib::XDefaultScreen(display); |
9 | | - let window = x11::xlib::XRootWindow(display, screen); |
10 | | - x11::xlib::XCreateBitmapFromData(display, window, &data, 1, 1) |
11 | | - }; |
| 10 | +fn create_empty_cursor(conn: &XCBConnection, screen: usize) -> Result<Cursor, Box<dyn Error>> { |
| 11 | + let cursor_id = conn.generate_id()?; |
| 12 | + let pixmap_id = conn.generate_id()?; |
| 13 | + let root_window = conn.setup().roots[screen].root; |
| 14 | + conn.create_pixmap(1, pixmap_id, root_window, 1, 1)?; |
| 15 | + conn.create_cursor(cursor_id, pixmap_id, pixmap_id, 0, 0, 0, 0, 0, 0, 0, 0)?; |
| 16 | + conn.free_pixmap(pixmap_id)?; |
12 | 17 |
|
13 | | - if pixmap == 0 { |
14 | | - return None; |
15 | | - } |
16 | | - |
17 | | - unsafe { |
18 | | - // We don't care about this color, since it only fills bytes |
19 | | - // in the pixmap which are not 0 in the mask. |
20 | | - let mut color: x11::xlib::XColor = std::mem::zeroed(); |
21 | | - |
22 | | - let cursor = x11::xlib::XCreatePixmapCursor( |
23 | | - display, |
24 | | - pixmap, |
25 | | - pixmap, |
26 | | - &mut color as *mut _, |
27 | | - &mut color as *mut _, |
28 | | - 0, |
29 | | - 0, |
30 | | - ); |
31 | | - x11::xlib::XFreePixmap(display, pixmap); |
32 | | - |
33 | | - Some(cursor as u32) |
34 | | - } |
| 18 | + Ok(cursor_id) |
35 | 19 | } |
36 | 20 |
|
37 | | -fn load_cursor(display: *mut x11::xlib::Display, name: &[u8]) -> Option<u32> { |
38 | | - let xcursor = |
39 | | - unsafe { x11::xcursor::XcursorLibraryLoadCursor(display, name.as_ptr() as *const c_char) }; |
40 | | - |
41 | | - if xcursor == 0 { |
42 | | - None |
| 21 | +fn load_cursor( |
| 22 | + conn: &XCBConnection, cursor_handle: &CursorHandle, name: &str, |
| 23 | +) -> Result<Option<Cursor>, Box<dyn Error>> { |
| 24 | + let cursor = cursor_handle.load_cursor(conn, name)?; |
| 25 | + if cursor != x11rb::NONE { |
| 26 | + Ok(Some(cursor)) |
43 | 27 | } else { |
44 | | - Some(xcursor as u32) |
| 28 | + Ok(None) |
45 | 29 | } |
46 | 30 | } |
47 | 31 |
|
48 | | -fn load_first_existing_cursor(display: *mut x11::xlib::Display, names: &[&[u8]]) -> Option<u32> { |
49 | | - names |
50 | | - .iter() |
51 | | - .map(|name| load_cursor(display, name)) |
52 | | - .find(|xcursor| xcursor.is_some()) |
53 | | - .unwrap_or(None) |
| 32 | +fn load_first_existing_cursor( |
| 33 | + conn: &XCBConnection, cursor_handle: &CursorHandle, names: &[&str], |
| 34 | +) -> Result<Option<Cursor>, Box<dyn Error>> { |
| 35 | + for name in names { |
| 36 | + let cursor = load_cursor(conn, cursor_handle, name)?; |
| 37 | + if cursor.is_some() { |
| 38 | + return Ok(cursor); |
| 39 | + } |
| 40 | + } |
| 41 | + |
| 42 | + Ok(None) |
54 | 43 | } |
55 | 44 |
|
56 | | -pub(super) fn get_xcursor(display: *mut x11::xlib::Display, cursor: MouseCursor) -> u32 { |
57 | | - let load = |name: &[u8]| load_cursor(display, name); |
58 | | - let loadn = |names: &[&[u8]]| load_first_existing_cursor(display, names); |
| 45 | +pub(super) fn get_xcursor( |
| 46 | + conn: &XCBConnection, screen: usize, cursor_handle: &CursorHandle, cursor: MouseCursor, |
| 47 | +) -> Result<Cursor, Box<dyn Error>> { |
| 48 | + let load = |name: &str| load_cursor(conn, cursor_handle, name); |
| 49 | + let loadn = |names: &[&str]| load_first_existing_cursor(conn, cursor_handle, names); |
59 | 50 |
|
60 | 51 | let cursor = match cursor { |
61 | 52 | MouseCursor::Default => None, // catch this in the fallback case below |
62 | 53 |
|
63 | | - MouseCursor::Hand => loadn(&[b"hand2\0", b"hand1\0"]), |
64 | | - MouseCursor::HandGrabbing => loadn(&[b"closedhand\0", b"grabbing\0"]), |
65 | | - MouseCursor::Help => load(b"question_arrow\0"), |
66 | | - |
67 | | - MouseCursor::Hidden => create_empty_cursor(display), |
68 | | - |
69 | | - MouseCursor::Text => loadn(&[b"text\0", b"xterm\0"]), |
70 | | - MouseCursor::VerticalText => load(b"vertical-text\0"), |
71 | | - |
72 | | - MouseCursor::Working => load(b"watch\0"), |
73 | | - MouseCursor::PtrWorking => load(b"left_ptr_watch\0"), |
74 | | - |
75 | | - MouseCursor::NotAllowed => load(b"crossed_circle\0"), |
76 | | - MouseCursor::PtrNotAllowed => loadn(&[b"no-drop\0", b"crossed_circle\0"]), |
77 | | - |
78 | | - MouseCursor::ZoomIn => load(b"zoom-in\0"), |
79 | | - MouseCursor::ZoomOut => load(b"zoom-out\0"), |
80 | | - |
81 | | - MouseCursor::Alias => load(b"link\0"), |
82 | | - MouseCursor::Copy => load(b"copy\0"), |
83 | | - MouseCursor::Move => load(b"move\0"), |
84 | | - MouseCursor::AllScroll => load(b"all-scroll\0"), |
85 | | - MouseCursor::Cell => load(b"plus\0"), |
86 | | - MouseCursor::Crosshair => load(b"crosshair\0"), |
87 | | - |
88 | | - MouseCursor::EResize => load(b"right_side\0"), |
89 | | - MouseCursor::NResize => load(b"top_side\0"), |
90 | | - MouseCursor::NeResize => load(b"top_right_corner\0"), |
91 | | - MouseCursor::NwResize => load(b"top_left_corner\0"), |
92 | | - MouseCursor::SResize => load(b"bottom_side\0"), |
93 | | - MouseCursor::SeResize => load(b"bottom_right_corner\0"), |
94 | | - MouseCursor::SwResize => load(b"bottom_left_corner\0"), |
95 | | - MouseCursor::WResize => load(b"left_side\0"), |
96 | | - MouseCursor::EwResize => load(b"h_double_arrow\0"), |
97 | | - MouseCursor::NsResize => load(b"v_double_arrow\0"), |
98 | | - MouseCursor::NwseResize => loadn(&[b"bd_double_arrow\0", b"size_bdiag\0"]), |
99 | | - MouseCursor::NeswResize => loadn(&[b"fd_double_arrow\0", b"size_fdiag\0"]), |
100 | | - MouseCursor::ColResize => loadn(&[b"split_h\0", b"h_double_arrow\0"]), |
101 | | - MouseCursor::RowResize => loadn(&[b"split_v\0", b"v_double_arrow\0"]), |
| 54 | + MouseCursor::Hand => loadn(&["hand2", "hand1"])?, |
| 55 | + MouseCursor::HandGrabbing => loadn(&["closedhand", "grabbing"])?, |
| 56 | + MouseCursor::Help => load("question_arrow")?, |
| 57 | + |
| 58 | + MouseCursor::Hidden => Some(create_empty_cursor(conn, screen)?), |
| 59 | + |
| 60 | + MouseCursor::Text => loadn(&["text", "xterm"])?, |
| 61 | + MouseCursor::VerticalText => load("vertical-text")?, |
| 62 | + |
| 63 | + MouseCursor::Working => load("watch")?, |
| 64 | + MouseCursor::PtrWorking => load("left_ptr_watch")?, |
| 65 | + |
| 66 | + MouseCursor::NotAllowed => load("crossed_circle")?, |
| 67 | + MouseCursor::PtrNotAllowed => loadn(&["no-drop", "crossed_circle"])?, |
| 68 | + |
| 69 | + MouseCursor::ZoomIn => load("zoom-in")?, |
| 70 | + MouseCursor::ZoomOut => load("zoom-out")?, |
| 71 | + |
| 72 | + MouseCursor::Alias => load("link")?, |
| 73 | + MouseCursor::Copy => load("copy")?, |
| 74 | + MouseCursor::Move => load("move")?, |
| 75 | + MouseCursor::AllScroll => load("all-scroll")?, |
| 76 | + MouseCursor::Cell => load("plus")?, |
| 77 | + MouseCursor::Crosshair => load("crosshair")?, |
| 78 | + |
| 79 | + MouseCursor::EResize => load("right_side")?, |
| 80 | + MouseCursor::NResize => load("top_side")?, |
| 81 | + MouseCursor::NeResize => load("top_right_corner")?, |
| 82 | + MouseCursor::NwResize => load("top_left_corner")?, |
| 83 | + MouseCursor::SResize => load("bottom_side")?, |
| 84 | + MouseCursor::SeResize => load("bottom_right_corner")?, |
| 85 | + MouseCursor::SwResize => load("bottom_left_corner")?, |
| 86 | + MouseCursor::WResize => load("left_side")?, |
| 87 | + MouseCursor::EwResize => load("h_double_arrow")?, |
| 88 | + MouseCursor::NsResize => load("v_double_arrow")?, |
| 89 | + MouseCursor::NwseResize => loadn(&["bd_double_arrow", "size_bdiag"])?, |
| 90 | + MouseCursor::NeswResize => loadn(&["fd_double_arrow", "size_fdiag"])?, |
| 91 | + MouseCursor::ColResize => loadn(&["split_h", "h_double_arrow"])?, |
| 92 | + MouseCursor::RowResize => loadn(&["split_v", "v_double_arrow"])?, |
102 | 93 | }; |
103 | 94 |
|
104 | | - cursor.or_else(|| load(b"left_ptr\0")).unwrap_or(0) |
| 95 | + if let Some(cursor) = cursor { |
| 96 | + Ok(cursor) |
| 97 | + } else { |
| 98 | + Ok(load("left_ptr")?.unwrap_or(x11rb::NONE)) |
| 99 | + } |
105 | 100 | } |
0 commit comments