diff --git a/CHANGELOG.md b/CHANGELOG.md index ce16fb7913..9c082bb69a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Added `Window::focus_window`to bring the window to the front and set input focus. - On Wayland and X11, implement `is_maximized` method on `Window`. - On macOS, fix issue where `ReceivedCharacter` was not being emitted during some key repeat events. +- On X11 retry cursor grab on failure (up to 10 times / 500ms) # 0.25.0 (2021-05-15) diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 9f3d573695..2430529557 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -1225,31 +1225,41 @@ impl UnownedWindow { (self.xconn.xlib.XUngrabPointer)(self.xconn.display, ffi::CurrentTime); } let result = if grab { - let result = unsafe { - (self.xconn.xlib.XGrabPointer)( - self.xconn.display, - self.xwindow, - ffi::True, - (ffi::ButtonPressMask - | ffi::ButtonReleaseMask - | ffi::EnterWindowMask - | ffi::LeaveWindowMask - | ffi::PointerMotionMask - | ffi::PointerMotionHintMask - | ffi::Button1MotionMask - | ffi::Button2MotionMask - | ffi::Button3MotionMask - | ffi::Button4MotionMask - | ffi::Button5MotionMask - | ffi::ButtonMotionMask - | ffi::KeymapStateMask) as c_uint, - ffi::GrabModeAsync, - ffi::GrabModeAsync, - self.xwindow, - 0, - ffi::CurrentTime, - ) - }; + let mut result = -1; + // Retry XGrabPointer a couple of times (up to 500ms) if it failes + // This can happen if we try to grab the pointer right after we created the window + for _ in 0..10 { + result = unsafe { + (self.xconn.xlib.XGrabPointer)( + self.xconn.display, + self.xwindow, + ffi::True, + (ffi::ButtonPressMask + | ffi::ButtonReleaseMask + | ffi::EnterWindowMask + | ffi::LeaveWindowMask + | ffi::PointerMotionMask + | ffi::PointerMotionHintMask + | ffi::Button1MotionMask + | ffi::Button2MotionMask + | ffi::Button3MotionMask + | ffi::Button4MotionMask + | ffi::Button5MotionMask + | ffi::ButtonMotionMask + | ffi::KeymapStateMask) as c_uint, + ffi::GrabModeAsync, + ffi::GrabModeAsync, + self.xwindow, + 0, + ffi::CurrentTime, + ) + }; + + if result == ffi::GrabSuccess { + break; + } + std::thread::sleep(std::time::Duration::from_millis(50)); + } match result { ffi::GrabSuccess => Ok(()),