1 use crate::window::CursorIcon; 2 3 use super::*; 4 5 impl XConnection { set_cursor_icon(&self, window: ffi::Window, cursor: Option<CursorIcon>)6 pub fn set_cursor_icon(&self, window: ffi::Window, cursor: Option<CursorIcon>) { 7 let cursor = *self 8 .cursor_cache 9 .lock() 10 .entry(cursor) 11 .or_insert_with(|| self.get_cursor(cursor)); 12 13 self.update_cursor(window, cursor); 14 } 15 create_empty_cursor(&self) -> ffi::Cursor16 fn create_empty_cursor(&self) -> ffi::Cursor { 17 let data = 0; 18 let pixmap = unsafe { 19 let screen = (self.xlib.XDefaultScreen)(self.display); 20 let window = (self.xlib.XRootWindow)(self.display, screen); 21 (self.xlib.XCreateBitmapFromData)(self.display, window, &data, 1, 1) 22 }; 23 24 if pixmap == 0 { 25 panic!("failed to allocate pixmap for cursor"); 26 } 27 28 unsafe { 29 // We don't care about this color, since it only fills bytes 30 // in the pixmap which are not 0 in the mask. 31 let mut dummy_color = MaybeUninit::uninit(); 32 let cursor = (self.xlib.XCreatePixmapCursor)( 33 self.display, 34 pixmap, 35 pixmap, 36 dummy_color.as_mut_ptr(), 37 dummy_color.as_mut_ptr(), 38 0, 39 0, 40 ); 41 (self.xlib.XFreePixmap)(self.display, pixmap); 42 43 cursor 44 } 45 } 46 load_cursor(&self, name: &[u8]) -> ffi::Cursor47 fn load_cursor(&self, name: &[u8]) -> ffi::Cursor { 48 unsafe { 49 (self.xcursor.XcursorLibraryLoadCursor)(self.display, name.as_ptr() as *const c_char) 50 } 51 } 52 load_first_existing_cursor(&self, names: &[&[u8]]) -> ffi::Cursor53 fn load_first_existing_cursor(&self, names: &[&[u8]]) -> ffi::Cursor { 54 for name in names.iter() { 55 let xcursor = self.load_cursor(name); 56 if xcursor != 0 { 57 return xcursor; 58 } 59 } 60 0 61 } 62 get_cursor(&self, cursor: Option<CursorIcon>) -> ffi::Cursor63 fn get_cursor(&self, cursor: Option<CursorIcon>) -> ffi::Cursor { 64 let cursor = match cursor { 65 Some(cursor) => cursor, 66 None => return self.create_empty_cursor(), 67 }; 68 69 let load = |name: &[u8]| self.load_cursor(name); 70 71 let loadn = |names: &[&[u8]]| self.load_first_existing_cursor(names); 72 73 // Try multiple names in some cases where the name 74 // differs on the desktop environments or themes. 75 // 76 // Try the better looking (or more suiting) names first. 77 match cursor { 78 CursorIcon::Alias => load(b"link\0"), 79 CursorIcon::Arrow => load(b"arrow\0"), 80 CursorIcon::Cell => load(b"plus\0"), 81 CursorIcon::Copy => load(b"copy\0"), 82 CursorIcon::Crosshair => load(b"crosshair\0"), 83 CursorIcon::Default => load(b"left_ptr\0"), 84 CursorIcon::Hand => loadn(&[b"hand2\0", b"hand1\0"]), 85 CursorIcon::Help => load(b"question_arrow\0"), 86 CursorIcon::Move => load(b"move\0"), 87 CursorIcon::Grab => loadn(&[b"openhand\0", b"grab\0"]), 88 CursorIcon::Grabbing => loadn(&[b"closedhand\0", b"grabbing\0"]), 89 CursorIcon::Progress => load(b"left_ptr_watch\0"), 90 CursorIcon::AllScroll => load(b"all-scroll\0"), 91 CursorIcon::ContextMenu => load(b"context-menu\0"), 92 93 CursorIcon::NoDrop => loadn(&[b"no-drop\0", b"circle\0"]), 94 CursorIcon::NotAllowed => load(b"crossed_circle\0"), 95 96 // Resize cursors 97 CursorIcon::EResize => load(b"right_side\0"), 98 CursorIcon::NResize => load(b"top_side\0"), 99 CursorIcon::NeResize => load(b"top_right_corner\0"), 100 CursorIcon::NwResize => load(b"top_left_corner\0"), 101 CursorIcon::SResize => load(b"bottom_side\0"), 102 CursorIcon::SeResize => load(b"bottom_right_corner\0"), 103 CursorIcon::SwResize => load(b"bottom_left_corner\0"), 104 CursorIcon::WResize => load(b"left_side\0"), 105 CursorIcon::EwResize => load(b"h_double_arrow\0"), 106 CursorIcon::NsResize => load(b"v_double_arrow\0"), 107 CursorIcon::NwseResize => loadn(&[b"bd_double_arrow\0", b"size_bdiag\0"]), 108 CursorIcon::NeswResize => loadn(&[b"fd_double_arrow\0", b"size_fdiag\0"]), 109 CursorIcon::ColResize => loadn(&[b"split_h\0", b"h_double_arrow\0"]), 110 CursorIcon::RowResize => loadn(&[b"split_v\0", b"v_double_arrow\0"]), 111 112 CursorIcon::Text => loadn(&[b"text\0", b"xterm\0"]), 113 CursorIcon::VerticalText => load(b"vertical-text\0"), 114 115 CursorIcon::Wait => load(b"watch\0"), 116 117 CursorIcon::ZoomIn => load(b"zoom-in\0"), 118 CursorIcon::ZoomOut => load(b"zoom-out\0"), 119 } 120 } 121 update_cursor(&self, window: ffi::Window, cursor: ffi::Cursor)122 fn update_cursor(&self, window: ffi::Window, cursor: ffi::Cursor) { 123 unsafe { 124 (self.xlib.XDefineCursor)(self.display, window, cursor); 125 126 self.flush_requests().expect("Failed to set the cursor"); 127 } 128 } 129 } 130