[PATCH resend] winex11.drv: Try harder to grab pointer.
Rémi Bernon
rbernon at codeweavers.com
Wed Sep 4 08:00:36 CDT 2019
On 9/4/19 2:09 PM, Zhiyi Zhang wrote:
> Some window managers temporarily grab the pointer during window transition.
> We need to wait a while for window manager to release its grab, otherwise
> XGrabPointer may fail with AlreadyGrabbed, causing cursor clipping to fail.
>
> Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
> ---
> dlls/winex11.drv/mouse.c | 21 ++++++++++++++++++---
> 1 file changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
> index f737a306a5..7501959369 100644
> --- a/dlls/winex11.drv/mouse.c
> +++ b/dlls/winex11.drv/mouse.c
> @@ -378,9 +378,13 @@ static BOOL grab_clipping_window( const RECT *clip )
> {
> static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0};
> struct x11drv_thread_data *data = x11drv_thread_data();
> + static DWORD timeout = 5000;
> + static DWORD step = 100;
> + DWORD time = 0;
> Window clip_window;
> HWND msg_hwnd = 0;
> POINT pos;
> + INT ret;
>
> if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId())
> return TRUE; /* don't clip in the desktop process */
> @@ -416,13 +420,24 @@ static BOOL grab_clipping_window( const RECT *clip )
> clip->right < clip_rect.right || clip->bottom < clip_rect.bottom)
> data->warp_serial = NextRequest( data->display );
>
> - if (!XGrabPointer( data->display, clip_window, False,
> - PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
> - GrabModeAsync, GrabModeAsync, clip_window, None, CurrentTime ))
> + /* Some windows managers temporarily grab the pointer during window transition. Retry grabbing. */
> + do
> + {
> + ret = XGrabPointer( data->display, clip_window, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
> + GrabModeAsync, GrabModeAsync, clip_window, None, CurrentTime );
> + if (ret == AlreadyGrabbed || ret == GrabFrozen)
> + {
> + time += step;
> + Sleep(step);
> + }
> + } while ((ret == AlreadyGrabbed || ret == GrabFrozen) && time < timeout);
> +
> + if (ret == GrabSuccess)
> clipping_cursor = TRUE;
>
> if (!clipping_cursor)
> {
> + ERR("Failed to grab pointer\n");
> disable_xinput2();
> DestroyWindow( msg_hwnd );
> return FALSE;
>
I think this will not fix the issue in a reliable way. If the
application fails to grab the cursor, it's usually because the WM is
already grabbing it. The timeout makes the behavior arbitrarily differ
when the user moves a window for more than 5s, although IMHO we should
aim for consistent behavior - systematically fail to clip the cursor
when the user moves the window for example, XOR retry indefinitely until
it succeeds.
Some games already retry clipping the cursor at every frame, so in this
case they will eventually succeed. Some others don't and expect it to
succeed, but for these I believe we should instead delay and retry to
clip the cursor after the WM releases its grab.
--
Rémi Bernon <rbernon at codeweavers.com>
More information about the wine-devel
mailing list