From 7fb6450d17388097619bfb1e675e17c7bc2e3eaa Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 16 Apr 2016 20:37:53 +0200 Subject: [PATCH] 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. --- src/api/x11/window.rs | 102 ++++++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 38 deletions(-) diff --git a/src/api/x11/window.rs b/src/api/x11/window.rs index b84dc09e..b5247955 100644 --- a/src/api/x11/window.rs +++ b/src/api/x11/window.rs @@ -841,50 +841,76 @@ impl Window { pub fn set_cursor(&self, cursor: MouseCursor) { unsafe { use std::ffi::CString; - let cursor_name = match cursor { - MouseCursor::Alias => "link", - MouseCursor::Arrow => "arrow", - MouseCursor::Cell => "plus", - MouseCursor::Copy => "copy", - MouseCursor::Crosshair => "crosshair", - MouseCursor::Default => "left_ptr", - MouseCursor::Grabbing => "grabbing", - MouseCursor::Hand | MouseCursor::Grab => "hand", - MouseCursor::Help => "question_arrow", - MouseCursor::Move => "move", - MouseCursor::NoDrop => "circle", - MouseCursor::NotAllowed => "crossed_circle", - MouseCursor::Progress => "left_ptr_watch", + let load = |name :&str| { + let c_string = CString::new(name.as_bytes().to_vec()).unwrap(); + return (self.x.display.xcursor.XcursorLibraryLoadCursor)(self.x.display.display, c_string.as_ptr()); + }; + let loadn = |names :&[&str]| { + for name in names.iter() { + let xcursor = load(*name); + if xcursor != 0 { + return xcursor; + } + } + return 0; + }; + // 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 - MouseCursor::EResize => "right_side", - MouseCursor::NResize => "top_side", - MouseCursor::NeResize => "top_right_corner", - MouseCursor::NwResize => "top_left_corner", - MouseCursor::SResize => "bottom_side", - MouseCursor::SeResize => "bottom_right_corner", - MouseCursor::SwResize => "bottom_left_corner", - MouseCursor::WResize => "left_side", - MouseCursor::EwResize | MouseCursor::ColResize => "h_double_arrow", - MouseCursor::NsResize | MouseCursor::RowResize => "v_double_arrow", - MouseCursor::NwseResize => "bd_double_arrow", - MouseCursor::NeswResize => "fd_double_arrow", + MouseCursor::EResize => load("right_side"), + MouseCursor::NResize => load("top_side"), + MouseCursor::NeResize => load("top_right_corner"), + MouseCursor::NwResize => load("top_left_corner"), + MouseCursor::SResize => load("bottom_side"), + MouseCursor::SeResize => load("bottom_right_corner"), + MouseCursor::SwResize => load("bottom_left_corner"), + MouseCursor::WResize => load("left_side"), + MouseCursor::EwResize => load("h_double_arrow"), + MouseCursor::NsResize => load("v_double_arrow"), + MouseCursor::NwseResize => loadn(&["bd_double_arrow", "size_bdiag"]), + 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::Wait => "watch", + MouseCursor::Text => loadn(&["text", "xterm"]), + MouseCursor::VerticalText => load("vertical-text"), - /// TODO: Find matching X11 cursors - MouseCursor::ContextMenu | MouseCursor::NoneCursor | - MouseCursor::AllScroll | MouseCursor::ZoomIn | - MouseCursor::ZoomOut => "left_ptr", + MouseCursor::Wait => load("watch"), + + MouseCursor::ZoomIn => load("zoom-in"), + 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.XFlush)(self.x.display.display); - (self.x.display.xlib.XFreeCursor)(self.x.display.display, xcursor); - self.x.display.check_errors().expect("Failed to call XDefineCursor"); + if xcursor != 0 { + (self.x.display.xlib.XFreeCursor)(self.x.display.display, xcursor); + } + self.x.display.check_errors().expect("Failed to set or free the cursor"); } }