Skip to content

Commit a028fd7

Browse files
committed
switch from xcb crate to x11rb
1 parent 998ced8 commit a028fd7

File tree

5 files changed

+323
-399
lines changed

5 files changed

+323
-399
lines changed

Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ keyboard-types = { version = "0.6.1", default-features = false }
2323
raw-window-handle = "0.5"
2424

2525
[target.'cfg(target_os="linux")'.dependencies]
26-
xcb = { version = "0.9", features = ["thread", "xlib_xcb", "dri2"] }
27-
x11 = { version = "2.18", features = ["xlib", "xcursor"] }
28-
xcb-util = { version = "0.3", features = ["icccm"] }
26+
x11rb = { version = "0.13.0", features = ["cursor", "resource_manager", "allow-unsafe-code"] }
27+
x11 = { version = "2.21", features = ["xlib", "xcursor", "xlib_xcb"] }
2928
nix = "0.22.0"
3029

3130
[target.'cfg(target_os="windows")'.dependencies]

src/x11/cursor.rs

Lines changed: 81 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,100 @@
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;
27

38
use crate::MouseCursor;
49

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)?;
1217

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)
3519
}
3620

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))
4327
} else {
44-
Some(xcursor as u32)
28+
Ok(None)
4529
}
4630
}
4731

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)
5443
}
5544

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);
5950

6051
let cursor = match cursor {
6152
MouseCursor::Default => None, // catch this in the fallback case below
6253

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"])?,
10293
};
10394

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+
}
105100
}

src/x11/keyboard.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
//! X11 keyboard handling
2020
21-
use xcb::xproto;
21+
use x11rb::protocol::xproto::{KeyButMask, KeyPressEvent, KeyReleaseEvent};
2222

2323
use keyboard_types::*;
2424

@@ -361,43 +361,43 @@ fn hardware_keycode_to_code(hw_keycode: u16) -> Code {
361361
}
362362

363363
// Extracts the keyboard modifiers from, e.g., the `state` field of
364-
// `xcb::xproto::ButtonPressEvent`
365-
pub(super) fn key_mods(mods: u16) -> Modifiers {
364+
// `x11rb::protocol::xproto::ButtonPressEvent`
365+
pub(super) fn key_mods(mods: KeyButMask) -> Modifiers {
366366
let mut ret = Modifiers::default();
367-
let mut key_masks = [
368-
(xproto::MOD_MASK_SHIFT, Modifiers::SHIFT),
369-
(xproto::MOD_MASK_CONTROL, Modifiers::CONTROL),
367+
let key_masks = [
368+
(KeyButMask::SHIFT, Modifiers::SHIFT),
369+
(KeyButMask::CONTROL, Modifiers::CONTROL),
370370
// X11's mod keys are configurable, but this seems
371371
// like a reasonable default for US keyboards, at least,
372372
// where the "windows" key seems to be MOD_MASK_4.
373-
(xproto::MOD_MASK_1, Modifiers::ALT),
374-
(xproto::MOD_MASK_2, Modifiers::NUM_LOCK),
375-
(xproto::MOD_MASK_4, Modifiers::META),
376-
(xproto::MOD_MASK_LOCK, Modifiers::CAPS_LOCK),
373+
(KeyButMask::BUTTON1, Modifiers::ALT),
374+
(KeyButMask::BUTTON2, Modifiers::NUM_LOCK),
375+
(KeyButMask::BUTTON4, Modifiers::META),
376+
(KeyButMask::LOCK, Modifiers::CAPS_LOCK),
377377
];
378-
for (mask, modifiers) in &mut key_masks {
379-
if mods & (*mask as u16) != 0 {
378+
for (mask, modifiers) in &key_masks {
379+
if mods.contains(*mask) {
380380
ret |= *modifiers;
381381
}
382382
}
383383
ret
384384
}
385385

386-
pub(super) fn convert_key_press_event(key_press: &xcb::KeyPressEvent) -> KeyboardEvent {
387-
let hw_keycode = key_press.detail();
386+
pub(super) fn convert_key_press_event(key_press: &KeyPressEvent) -> KeyboardEvent {
387+
let hw_keycode = key_press.detail;
388388
let code = hardware_keycode_to_code(hw_keycode.into());
389-
let modifiers = key_mods(key_press.state());
389+
let modifiers = key_mods(key_press.state);
390390
let key = code_to_key(code, modifiers);
391391
let location = code_to_location(code);
392392
let state = KeyState::Down;
393393

394394
KeyboardEvent { code, key, modifiers, location, state, repeat: false, is_composing: false }
395395
}
396396

397-
pub(super) fn convert_key_release_event(key_release: &xcb::KeyReleaseEvent) -> KeyboardEvent {
398-
let hw_keycode = key_release.detail();
397+
pub(super) fn convert_key_release_event(key_release: &KeyReleaseEvent) -> KeyboardEvent {
398+
let hw_keycode = key_release.detail;
399399
let code = hardware_keycode_to_code(hw_keycode.into());
400-
let modifiers = key_mods(key_release.state());
400+
let modifiers = key_mods(key_release.state);
401401
let key = code_to_key(code, modifiers);
402402
let location = code_to_location(code);
403403
let state = KeyState::Up;

0 commit comments

Comments
 (0)