1
0
Fork 0

Merge pull request #46 from BillyDM/master

Add set_mouse_cursor method to X11 Window
This commit is contained in:
william light 2020-09-14 02:13:00 +02:00 committed by GitHub
commit ad3dfce97d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 191 additions and 14 deletions

View file

@ -14,7 +14,7 @@ jobs:
- name: Install XCB and GL dependencies - name: Install XCB and GL dependencies
run: | run: |
sudo apt update 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-dev
if: contains(matrix.os, 'ubuntu') if: contains(matrix.os, 'ubuntu')
- name: Install rust stable - name: Install rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1

View file

@ -16,8 +16,9 @@ raw-window-handle = "0.3.3"
[target.'cfg(target_os="linux")'.dependencies] [target.'cfg(target_os="linux")'.dependencies]
xcb = { version = "0.9", features = ["thread", "xlib_xcb", "dri2"] } 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"] } xcb-util = { version = "0.3", features = ["icccm"] }
maybe-uninit = "2.0"
libc = "0.2" libc = "0.2"
nix = "0.18" nix = "0.18"

View file

@ -1,18 +1,49 @@
#[derive(Debug, Eq, PartialEq, Clone, Copy, PartialOrd, Ord)] #[derive(Debug, Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash)]
pub enum MouseCursor { pub enum MouseCursor {
Idle, Default,
Pointer, Hand,
Grab, HandGrabbing,
Help,
Hidden,
Text, Text,
Crosshair, VerticalText,
Working, Working,
Grabbing, PtrWorking,
ResizingHorizontally,
ResizingVertically, 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 { impl Default for MouseCursor {
fn default() -> Self { fn default() -> Self {
Self::Idle Self::Default
} }
} }

125
src/x11/cursor.rs Normal file
View file

@ -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<MouseCursor, c_ulong>,
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
}
}

View file

@ -3,3 +3,5 @@ use xcb_connection::XcbConnection;
mod window; mod window;
pub use window::*; pub use window::*;
mod cursor;

View file

@ -2,6 +2,7 @@ use std::os::raw::{c_ulong, c_void};
use std::sync::mpsc; use std::sync::mpsc;
use std::time::*; use std::time::*;
use std::thread; use std::thread;
use std::collections::HashMap;
use raw_window_handle::{ use raw_window_handle::{
unix::XlibHandle, unix::XlibHandle,
@ -11,14 +12,16 @@ use raw_window_handle::{
use super::XcbConnection; use super::XcbConnection;
use crate::{ use crate::{
Event, KeyboardEvent, MouseButton, MouseEvent, Parent, ScrollDelta, WindowEvent, WindowHandler, Event, KeyboardEvent, MouseButton, MouseCursor, MouseEvent, Parent, ScrollDelta, WindowEvent,
WindowInfo, WindowOpenOptions, WindowHandler,WindowInfo, WindowOpenOptions,
}; };
pub struct Window { pub struct Window {
xcb_connection: XcbConnection, xcb_connection: XcbConnection,
window_id: u32, window_id: u32,
window_info: WindowInfo, window_info: WindowInfo,
mouse_cursor: MouseCursor,
cursor_cache: HashMap<MouseCursor, c_ulong>,
frame_interval: Duration, frame_interval: Duration,
event_loop_running: bool, event_loop_running: bool,
@ -155,6 +158,8 @@ impl Window {
xcb_connection, xcb_connection,
window_id, window_id,
window_info, window_info,
mouse_cursor: MouseCursor::default(),
cursor_cache: HashMap::new(),
frame_interval: Duration::from_millis(15), frame_interval: Duration::from_millis(15),
event_loop_running: false, event_loop_running: false,
@ -174,6 +179,19 @@ impl Window {
&self.window_info &self.window_info
} }
pub fn set_mouse_cursor(&mut self, mouse_cursor: MouseCursor) {
if self.mouse_cursor != mouse_cursor {
crate::x11::cursor::set_cursor(
&mut self.xcb_connection,
self.window_id,
&mut self.cursor_cache,
mouse_cursor
);
self.mouse_cursor = mouse_cursor;
}
}
#[inline] #[inline]
fn drain_xcb_events<H: WindowHandler>(&mut self, handler: &mut H) { fn drain_xcb_events<H: WindowHandler>(&mut self, handler: &mut H) {
// the X server has a tendency to send spurious/extraneous configure notify events when a // the X server has a tendency to send spurious/extraneous configure notify events when a
@ -400,4 +418,4 @@ fn mouse_id(id: u8) -> MouseButton {
7 => MouseButton::Forward, 7 => MouseButton::Forward,
id => MouseButton::Other(id), id => MouseButton::Other(id),
} }
} }