From e9327b1a25ae34a6fccfc8cc6119dc99f35cc751 Mon Sep 17 00:00:00 2001 From: koalefant Date: Tue, 30 Dec 2025 23:47:13 +0100 Subject: [PATCH] linux_wayland, linux_x11: Fixed cursor flickering when show_mouse() is used with a non-default cursor. This addresses cursor flickering in egui-miniquad-0.16.0. NOTE: This changes behavior of set_cursor(), it won't show reveal a hidden cursor on X11 and Wayland anymore. But the new behavior is consistent with Windows. The problem is that neither Wayland nor X11 backend tracks cusor visibility separately from the icon. Every time the cursor is shown it is being reset to default cursor. And whenever cursor is changed it is being shown. This is different from Windows, where SetCursor() is independent from ShowCursor(). To address I track these states explicitly in native::linux_wayland::run() and X11Display. Test steps: * Run X11 session * Run demo example from egui-miniquad-0.16.0 * Try resizing an egui window and observe cursor not flickering anymore. * Run Wayland session in Plasma 6.5.3 * Modify conf of demo to run on Wayland (default is X11) * Try resizing an egui window and observe cursor not flickering anymore. --- src/native/linux_wayland.rs | 15 ++++++++++----- src/native/linux_x11.rs | 24 ++++++++++++------------ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/native/linux_wayland.rs b/src/native/linux_wayland.rs index 3b8ff0b4..94a2fe40 100644 --- a/src/native/linux_wayland.rs +++ b/src/native/linux_wayland.rs @@ -1205,6 +1205,10 @@ where let mut event_handler = (f.take().unwrap())(); + // track cursor visibility and icon separately, so that we can show/hide cursor without resetting icon + let mut cursor_icon = crate::CursorIcon::Default; + let mut cursor_visible = true; + while !crate::native_display().try_lock().unwrap().quit_ordered { while let Ok(request) = rx.try_recv() { match request { @@ -1213,19 +1217,20 @@ where } Request::ScheduleUpdate => display.update_requested = true, Request::SetMouseCursor(icon) => { + cursor_icon = icon; display .pointer_context - .set_cursor(&mut display.client, Some(icon)); + .set_cursor(&mut display.client, cursor_visible.then_some(cursor_icon)); } Request::SetCursorGrab(grab) => { let payload = &mut display as *mut _ as _; display.pointer_context.set_grab(payload, grab); } Request::ShowMouse(show) => { - display.pointer_context.set_cursor( - &mut display.client, - show.then_some(crate::CursorIcon::Default), - ); + cursor_visible = show; + display + .pointer_context + .set_cursor(&mut display.client, cursor_visible.then_some(cursor_icon)); } // TODO: implement the other events _ => (), diff --git a/src/native/linux_x11.rs b/src/native/linux_x11.rs index 7f756c16..9e2b0b53 100644 --- a/src/native/linux_x11.rs +++ b/src/native/linux_x11.rs @@ -49,6 +49,8 @@ pub struct X11Display { repeated_keycodes: [bool; 256], empty_cursor: libx11::Cursor, cursor_cache: HashMap, + cursor_icon: CursorIcon, + cursor_visible: bool, update_requested: bool, drag_n_drop: drag_n_drop::X11DnD, } @@ -329,16 +331,6 @@ impl X11Display { (self.libx11.XMoveWindow)(self.display, window, new_x, new_y); } - fn show_mouse(&mut self, shown: bool) { - unsafe { - if shown { - self.set_cursor(self.window, Some(CursorIcon::Default)); - } else { - self.set_cursor(self.window, None); - } - } - } - pub unsafe fn set_cursor_grab(&mut self, window: Window, grab: bool) { (self.libx11.XUngrabPointer)(self.display, 0); @@ -407,8 +399,14 @@ impl X11Display { self.update_requested = true; } SetCursorGrab(grab) => self.set_cursor_grab(self.window, grab), - ShowMouse(show) => self.show_mouse(show), - SetMouseCursor(icon) => self.set_cursor(self.window, Some(icon)), + ShowMouse(show) => { + self.cursor_visible = show; + self.set_cursor(self.window, self.cursor_visible.then_some(self.cursor_icon)); + } + SetMouseCursor(icon) => { + self.cursor_icon = icon; + self.set_cursor(self.window, self.cursor_visible.then_some(self.cursor_icon)); + } SetWindowSize { new_width, new_height, @@ -680,6 +678,8 @@ where cursor_cache: HashMap::new(), update_requested: true, drag_n_drop: Default::default(), + cursor_icon: CursorIcon::Default, + cursor_visible: true, }; display