Improve X11 cursor symbols handling

1. Make it non failing. Before we tried to call XFreeCursor with a
   cursor of 0 if we couldn't find a cursor. This has then caused a panic.

2. Introduce a system where multiple special cursors are tried
   in order to work with different themes and desktop environments.
   This way we get less often into the situation where we have to use a
   default cursor.

3. Also set names for some cursors that previously only had a placeholder.

Fixes #765.
Will fix https://github.com/servo/servo/issues/10475 as well.
This commit is contained in:
est31 2016-04-16 20:37:53 +02:00
parent b9065f56ba
commit 7fb6450d17

View file

@ -841,50 +841,76 @@ impl Window {
pub fn set_cursor(&self, cursor: MouseCursor) { pub fn set_cursor(&self, cursor: MouseCursor) {
unsafe { unsafe {
use std::ffi::CString; use std::ffi::CString;
let cursor_name = match cursor { let load = |name :&str| {
MouseCursor::Alias => "link", let c_string = CString::new(name.as_bytes().to_vec()).unwrap();
MouseCursor::Arrow => "arrow", return (self.x.display.xcursor.XcursorLibraryLoadCursor)(self.x.display.display, c_string.as_ptr());
MouseCursor::Cell => "plus", };
MouseCursor::Copy => "copy", let loadn = |names :&[&str]| {
MouseCursor::Crosshair => "crosshair", for name in names.iter() {
MouseCursor::Default => "left_ptr", let xcursor = load(*name);
MouseCursor::Grabbing => "grabbing", if xcursor != 0 {
MouseCursor::Hand | MouseCursor::Grab => "hand", return xcursor;
MouseCursor::Help => "question_arrow", }
MouseCursor::Move => "move", }
MouseCursor::NoDrop => "circle", return 0;
MouseCursor::NotAllowed => "crossed_circle", };
MouseCursor::Progress => "left_ptr_watch", // Try multiple names in some cases where the name
// differs on the desktop environments or themes.
//
// Try the better looking (or more suiting) names first.
let mut xcursor = match cursor {
MouseCursor::Alias => load("link"),
MouseCursor::Arrow => load("arrow"),
MouseCursor::Cell => load("plus"),
MouseCursor::Copy => load("copy"),
MouseCursor::Crosshair => load("crosshair"),
MouseCursor::Default => load("left_ptr"),
MouseCursor::Hand => load("hand1"),
MouseCursor::Help => load("question_arrow"),
MouseCursor::Move => load("move"),
MouseCursor::Grab => loadn(&["openhand", "grab"]),
MouseCursor::Grabbing => loadn(&["closedhand", "grabbing"]),
MouseCursor::Progress => load("left_ptr_watch"),
MouseCursor::AllScroll => load("all-scroll"),
MouseCursor::ContextMenu => load("context-menu"),
MouseCursor::NoDrop => loadn(&["no-drop", "circle"]),
MouseCursor::NotAllowed => load("crossed_circle"),
/// Resize cursors /// Resize cursors
MouseCursor::EResize => "right_side", MouseCursor::EResize => load("right_side"),
MouseCursor::NResize => "top_side", MouseCursor::NResize => load("top_side"),
MouseCursor::NeResize => "top_right_corner", MouseCursor::NeResize => load("top_right_corner"),
MouseCursor::NwResize => "top_left_corner", MouseCursor::NwResize => load("top_left_corner"),
MouseCursor::SResize => "bottom_side", MouseCursor::SResize => load("bottom_side"),
MouseCursor::SeResize => "bottom_right_corner", MouseCursor::SeResize => load("bottom_right_corner"),
MouseCursor::SwResize => "bottom_left_corner", MouseCursor::SwResize => load("bottom_left_corner"),
MouseCursor::WResize => "left_side", MouseCursor::WResize => load("left_side"),
MouseCursor::EwResize | MouseCursor::ColResize => "h_double_arrow", MouseCursor::EwResize => load("h_double_arrow"),
MouseCursor::NsResize | MouseCursor::RowResize => "v_double_arrow", MouseCursor::NsResize => load("v_double_arrow"),
MouseCursor::NwseResize => "bd_double_arrow", MouseCursor::NwseResize => loadn(&["bd_double_arrow", "size_bdiag"]),
MouseCursor::NeswResize => "fd_double_arrow", MouseCursor::NeswResize => loadn(&["fd_double_arrow", "size_fdiag"]),
MouseCursor::ColResize => loadn(&["split_h", "h_double_arrow"]),
MouseCursor::RowResize => loadn(&["split_v", "v_double_arrow"]),
MouseCursor::Text | MouseCursor::VerticalText => "xterm", MouseCursor::Text => loadn(&["text", "xterm"]),
MouseCursor::Wait => "watch", MouseCursor::VerticalText => load("vertical-text"),
/// TODO: Find matching X11 cursors MouseCursor::Wait => load("watch"),
MouseCursor::ContextMenu | MouseCursor::NoneCursor |
MouseCursor::AllScroll | MouseCursor::ZoomIn | MouseCursor::ZoomIn => load("zoom-in"),
MouseCursor::ZoomOut => "left_ptr", MouseCursor::ZoomOut => load("zoom-out"),
// TODO: Hide cursor
MouseCursor::NoneCursor => 0,
}; };
let c_string = CString::new(cursor_name.as_bytes().to_vec()).unwrap();
let xcursor = (self.x.display.xcursor.XcursorLibraryLoadCursor)(self.x.display.display, c_string.as_ptr());
self.x.display.check_errors().expect("Failed to call XcursorLibraryLoadCursor");
(self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, xcursor); (self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, xcursor);
(self.x.display.xlib.XFlush)(self.x.display.display); if xcursor != 0 {
(self.x.display.xlib.XFreeCursor)(self.x.display.display, xcursor); (self.x.display.xlib.XFreeCursor)(self.x.display.display, xcursor);
self.x.display.check_errors().expect("Failed to call XDefineCursor"); }
self.x.display.check_errors().expect("Failed to set or free the cursor");
} }
} }