1#![deny(missing_docs)]
19#![doc(html_root_url = "https://docs.rs/xcb-util-cursor/")]
20
21use std::{ffi::CString, fmt, marker, ptr};
22
23use xcb::{x, Xid, XidNew};
24use xcb_util_cursor_sys as ffi;
25
26pub enum Cursor {
28 XCursor,
30 Arrow,
32 BaseArrowDown,
34 BasedArrowUp,
36 Boat,
38 Bogosity,
40 BottomLeftCorner,
42 BottomRightCorner,
44 BottomSide,
46 BottomTee,
48 BoxSpiral,
50 CenterPtr,
52 Circle,
54 Clock,
56 CoffeeMug,
58 Cross,
60 CrossReverse,
62 Crosshair,
64 DiamongCross,
66 Dot,
68 Dotbox,
70 DoubleArrow,
72 DraftLarge,
74 DrawftSmall,
76 DrapedBox,
78 Exchange,
80 Fleur,
82 Gobbler,
84 Gumby,
86 Hand1,
88 Hand2,
90 Heart,
92 Icon,
94 IronCross,
96 LeftPtr,
98 LeftSide,
100 LeftTee,
102 Leftbutton,
104 LlAngle,
106 LrAngle,
108 Man,
110 Middlebutton,
112 Mouse,
114 Pencil,
116 Pirate,
118 Plus,
120 QuestionArrow,
122 RightPtr,
124 RightSide,
126 RightTee,
128 Rightbutton,
130 RtlLogo,
132 Sailboat,
134 SbDownArrow,
136 SbHDoubleArrow,
138 SbLeftArrow,
140 SbRightArrow,
142 SbUpArrow,
144 SbVDoubleArrow,
146 Shuttle,
148 Sizing,
150 Spider,
152 Spraycan,
154 Star,
156 Target,
158 Tcross,
160 TopLeftArrow,
162 TopLeftCorner,
164 TopRightCorner,
166 TopSide,
168 TopTee,
170 Trek,
172 UlAngle,
174 Umbrella,
176 UrAngle,
178 Watch,
180 Xterm,
182 Custom(String),
184}
185
186impl fmt::Display for Cursor {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 let s = match self {
189 Cursor::XCursor => "X_cursor",
190 Cursor::Arrow => "arrow",
191 Cursor::BaseArrowDown => "based_arrow_down",
192 Cursor::BasedArrowUp => "based_arrow_up",
193 Cursor::Boat => "boat",
194 Cursor::Bogosity => "bogosity",
195 Cursor::BottomLeftCorner => "bottom_left_corner",
196 Cursor::BottomRightCorner => "bottom_right_corner",
197 Cursor::BottomSide => "bottom_side",
198 Cursor::BottomTee => "bottom_tee",
199 Cursor::BoxSpiral => "box_spiral",
200 Cursor::CenterPtr => "center_ptr",
201 Cursor::Circle => "circle",
202 Cursor::Clock => "clock",
203 Cursor::CoffeeMug => "coffee_mug",
204 Cursor::Cross => "cross",
205 Cursor::CrossReverse => "cross_reverse",
206 Cursor::Crosshair => "crosshair",
207 Cursor::DiamongCross => "diamond_cross",
208 Cursor::Dot => "dot",
209 Cursor::Dotbox => "dotbox",
210 Cursor::DoubleArrow => "double_arrow",
211 Cursor::DraftLarge => "draft_large",
212 Cursor::DrawftSmall => "draft_small",
213 Cursor::DrapedBox => "draped_box",
214 Cursor::Exchange => "exchange",
215 Cursor::Fleur => "fleur",
216 Cursor::Gobbler => "gobbler",
217 Cursor::Gumby => "gumby",
218 Cursor::Hand1 => "hand1",
219 Cursor::Hand2 => "hand2",
220 Cursor::Heart => "heart",
221 Cursor::Icon => "icon",
222 Cursor::IronCross => "iron_cross",
223 Cursor::LeftPtr => "left_ptr",
224 Cursor::LeftSide => "left_side",
225 Cursor::LeftTee => "left_tee",
226 Cursor::Leftbutton => "leftbutton",
227 Cursor::LlAngle => "ll_angle",
228 Cursor::LrAngle => "lr_angle",
229 Cursor::Man => "man",
230 Cursor::Middlebutton => "middlebutton",
231 Cursor::Mouse => "mouse",
232 Cursor::Pencil => "pencil",
233 Cursor::Pirate => "pirate",
234 Cursor::Plus => "plus",
235 Cursor::QuestionArrow => "question_arrow",
236 Cursor::RightPtr => "right_ptr",
237 Cursor::RightSide => "right_side",
238 Cursor::RightTee => "right_tee",
239 Cursor::Rightbutton => "rightbutton",
240 Cursor::RtlLogo => "rtl_logo",
241 Cursor::Sailboat => "sailboat",
242 Cursor::SbDownArrow => "sb_down_arrow",
243 Cursor::SbHDoubleArrow => "sb_h_double_arrow",
244 Cursor::SbLeftArrow => "sb_left_arrow",
245 Cursor::SbRightArrow => "sb_right_arrow",
246 Cursor::SbUpArrow => "sb_up_arrow",
247 Cursor::SbVDoubleArrow => "sb_v_double_arrow",
248 Cursor::Shuttle => "shuttle",
249 Cursor::Sizing => "sizing",
250 Cursor::Spider => "spider",
251 Cursor::Spraycan => "spraycan",
252 Cursor::Star => "star",
253 Cursor::Target => "target",
254 Cursor::Tcross => "tcross",
255 Cursor::TopLeftArrow => "top_left_arrow",
256 Cursor::TopLeftCorner => "top_left_corner",
257 Cursor::TopRightCorner => "top_right_corner",
258 Cursor::TopSide => "top_side",
259 Cursor::TopTee => "top_tee",
260 Cursor::Trek => "trek",
261 Cursor::UlAngle => "ul_angle",
262 Cursor::Umbrella => "umbrella",
263 Cursor::UrAngle => "ur_angle",
264 Cursor::Watch => "watch",
265 Cursor::Xterm => "xterm",
266 Cursor::Custom(s) => s,
267 };
268
269 write!(f, "{s}")
270 }
271}
272
273pub struct CursorContext<'a> {
275 ctx: *mut ffi::xcb_cursor_context_t,
276 phantom: marker::PhantomData<&'a xcb::Connection>,
277}
278
279impl<'a> CursorContext<'a> {
280 pub fn new(connection: &'a xcb::Connection, screen: &x::Screen) -> Option<Self> {
282 let mut screen = ffi::xcb_screen_t {
283 root: screen.root().resource_id(),
284 default_colormap: screen.default_colormap().resource_id(),
285 white_pixel: screen.white_pixel(),
286 black_pixel: screen.black_pixel(),
287 current_input_masks: screen.current_input_masks().bits(),
288 width_in_pixels: screen.width_in_pixels(),
289 height_in_pixels: screen.height_in_pixels(),
290 width_in_millimeters: screen.width_in_millimeters(),
291 height_in_millimeters: screen.height_in_millimeters(),
292 min_installed_maps: screen.min_installed_maps(),
293 max_installed_maps: screen.max_installed_maps(),
294 root_visual: screen.root_visual(),
295 backing_stores: screen.backing_stores() as u8,
296 save_unders: screen.save_unders() as u8,
297 root_depth: screen.root_depth(),
298 allowed_depths_len: screen.allowed_depths().count() as u8,
299 };
300
301 let mut ctx = ptr::null_mut();
302
303 let res = unsafe {
304 ffi::xcb_cursor_context_new(connection.get_raw_conn(), &mut screen, &mut ctx)
305 };
306
307 if res != 0 {
308 None
309 } else {
310 Some(Self {
311 ctx,
312 phantom: marker::PhantomData,
313 })
314 }
315 }
316
317 pub fn load_cursor(&self, cursor: Cursor) -> x::Cursor {
319 let c_str = CString::new(cursor.to_string()).unwrap();
320
321 unsafe {
322 let cursor = ffi::xcb_cursor_load_cursor(self.ctx, c_str.as_ptr());
323 x::Cursor::new(cursor)
324 }
325 }
326}
327
328impl<'a> Drop for CursorContext<'a> {
329 fn drop(&mut self) {
330 unsafe {
331 ffi::xcb_cursor_context_free(self.ctx);
332 }
333 }
334}