wayland: Improve cursor (#10516)
Fixes the cursor not updating when (a) switching windows from another program via a shortcut and (b) when cursor updates were triggered by something other than moving the mouse (e.g. when scrolling or pressing a key). Release Notes: - N/A
This commit is contained in:
parent
58f57491b1
commit
3eb8464d19
2 changed files with 33 additions and 12 deletions
|
@ -95,6 +95,7 @@ impl Globals {
|
||||||
|
|
||||||
pub(crate) struct WaylandClientState {
|
pub(crate) struct WaylandClientState {
|
||||||
globals: Globals,
|
globals: Globals,
|
||||||
|
wl_pointer: Option<wl_pointer::WlPointer>,
|
||||||
// Surface to Window mapping
|
// Surface to Window mapping
|
||||||
windows: HashMap<ObjectId, WaylandWindowStatePtr>,
|
windows: HashMap<ObjectId, WaylandWindowStatePtr>,
|
||||||
// Output to scale mapping
|
// Output to scale mapping
|
||||||
|
@ -240,6 +241,7 @@ impl WaylandClient {
|
||||||
|
|
||||||
let mut state = Rc::new(RefCell::new(WaylandClientState {
|
let mut state = Rc::new(RefCell::new(WaylandClientState {
|
||||||
globals,
|
globals,
|
||||||
|
wl_pointer: None,
|
||||||
output_scales: outputs,
|
output_scales: outputs,
|
||||||
windows: HashMap::default(),
|
windows: HashMap::default(),
|
||||||
common,
|
common,
|
||||||
|
@ -343,7 +345,15 @@ impl LinuxClient for WaylandClient {
|
||||||
}
|
}
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
self.0.borrow_mut().cursor_icon_name = cursor_icon_name;
|
let mut state = self.0.borrow_mut();
|
||||||
|
state.cursor_icon_name = cursor_icon_name.clone();
|
||||||
|
if state.mouse_focused_window.is_some() {
|
||||||
|
let wl_pointer = state
|
||||||
|
.wl_pointer
|
||||||
|
.clone()
|
||||||
|
.expect("window is focused by pointer");
|
||||||
|
state.cursor.set_icon(&wl_pointer, &cursor_icon_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_common<R>(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R {
|
fn with_common<R>(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R {
|
||||||
|
@ -403,6 +413,7 @@ impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientStat
|
||||||
version,
|
version,
|
||||||
} => match &interface[..] {
|
} => match &interface[..] {
|
||||||
"wl_seat" => {
|
"wl_seat" => {
|
||||||
|
state.wl_pointer = None;
|
||||||
registry.bind::<wl_seat::WlSeat, _, _>(name, wl_seat_version(version), qh, ());
|
registry.bind::<wl_seat::WlSeat, _, _>(name, wl_seat_version(version), qh, ());
|
||||||
}
|
}
|
||||||
"wl_output" => {
|
"wl_output" => {
|
||||||
|
@ -582,7 +593,9 @@ impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientStatePtr {
|
||||||
seat.get_keyboard(qh, ());
|
seat.get_keyboard(qh, ());
|
||||||
}
|
}
|
||||||
if capabilities.contains(wl_seat::Capability::Pointer) {
|
if capabilities.contains(wl_seat::Capability::Pointer) {
|
||||||
seat.get_pointer(qh, ());
|
let client = state.get_client();
|
||||||
|
let mut state = client.borrow_mut();
|
||||||
|
state.wl_pointer = Some(seat.get_pointer(qh, ()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -789,10 +802,11 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
|
||||||
if let Some(window) = get_window(&mut state, &surface.id()) {
|
if let Some(window) = get_window(&mut state, &surface.id()) {
|
||||||
state.enter_token = Some(());
|
state.enter_token = Some(());
|
||||||
state.mouse_focused_window = Some(window.clone());
|
state.mouse_focused_window = Some(window.clone());
|
||||||
|
state.cursor.mark_dirty();
|
||||||
state.cursor.set_serial_id(serial);
|
state.cursor.set_serial_id(serial);
|
||||||
state
|
state
|
||||||
.cursor
|
.cursor
|
||||||
.set_icon(&wl_pointer, Some(cursor_icon_name.as_str()));
|
.set_icon(&wl_pointer, cursor_icon_name.as_str());
|
||||||
drop(state);
|
drop(state);
|
||||||
window.set_focused(true);
|
window.set_focused(true);
|
||||||
}
|
}
|
||||||
|
@ -823,9 +837,6 @@ impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32)));
|
state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32)));
|
||||||
state
|
|
||||||
.cursor
|
|
||||||
.set_icon(&wl_pointer, Some(cursor_icon_name.as_str()));
|
|
||||||
|
|
||||||
if let Some(window) = state.mouse_focused_window.clone() {
|
if let Some(window) = state.mouse_focused_window.clone() {
|
||||||
let input = PlatformInput::MouseMove(MouseMoveEvent {
|
let input = PlatformInput::MouseMove(MouseMoveEvent {
|
||||||
|
|
|
@ -8,7 +8,7 @@ use wayland_cursor::{CursorImageBuffer, CursorTheme};
|
||||||
|
|
||||||
pub(crate) struct Cursor {
|
pub(crate) struct Cursor {
|
||||||
theme: Option<CursorTheme>,
|
theme: Option<CursorTheme>,
|
||||||
current_icon_name: String,
|
current_icon_name: Option<String>,
|
||||||
surface: WlSurface,
|
surface: WlSurface,
|
||||||
serial_id: u32,
|
serial_id: u32,
|
||||||
}
|
}
|
||||||
|
@ -24,19 +24,29 @@ impl Cursor {
|
||||||
pub fn new(connection: &Connection, globals: &Globals, size: u32) -> Self {
|
pub fn new(connection: &Connection, globals: &Globals, size: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
theme: CursorTheme::load(&connection, globals.shm.clone(), size).log_err(),
|
theme: CursorTheme::load(&connection, globals.shm.clone(), size).log_err(),
|
||||||
current_icon_name: "default".to_string(),
|
current_icon_name: None,
|
||||||
surface: globals.compositor.create_surface(&globals.qh, ()),
|
surface: globals.compositor.create_surface(&globals.qh, ()),
|
||||||
serial_id: 0,
|
serial_id: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mark_dirty(&mut self) {
|
||||||
|
self.current_icon_name = None;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_serial_id(&mut self, serial_id: u32) {
|
pub fn set_serial_id(&mut self, serial_id: u32) {
|
||||||
self.serial_id = serial_id;
|
self.serial_id = serial_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_icon(&mut self, wl_pointer: &WlPointer, mut cursor_icon_name: Option<&str>) {
|
pub fn set_icon(&mut self, wl_pointer: &WlPointer, mut cursor_icon_name: &str) {
|
||||||
let mut cursor_icon_name = cursor_icon_name.unwrap_or("default");
|
let need_update = self
|
||||||
if self.current_icon_name != cursor_icon_name {
|
.current_icon_name
|
||||||
|
.as_ref()
|
||||||
|
.map_or(true, |current_icon_name| {
|
||||||
|
current_icon_name != cursor_icon_name
|
||||||
|
});
|
||||||
|
|
||||||
|
if need_update {
|
||||||
if let Some(theme) = &mut self.theme {
|
if let Some(theme) = &mut self.theme {
|
||||||
let mut buffer: Option<&CursorImageBuffer>;
|
let mut buffer: Option<&CursorImageBuffer>;
|
||||||
|
|
||||||
|
@ -68,7 +78,7 @@ impl Cursor {
|
||||||
self.surface.damage(0, 0, width as i32, height as i32);
|
self.surface.damage(0, 0, width as i32, height as i32);
|
||||||
self.surface.commit();
|
self.surface.commit();
|
||||||
|
|
||||||
self.current_icon_name = cursor_icon_name.to_string();
|
self.current_icon_name = Some(cursor_icon_name.to_string());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Linux: Wayland: Unable to load cursor themes");
|
log::warn!("Linux: Wayland: Unable to load cursor themes");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue