[PATCH] winex11.drv: Wait for XGrabPointer to succeed on FocusIn events.

Rémi Bernon rbernon at codeweavers.com
Wed Sep 18 07:13:05 CDT 2019


Because on X11 we cannot accurately reproduce the proper non-client
messages sequence when using decorated windows, applications sometimes
assume it is safe to call ClipCursor with a rectangle that matches the
current window position as soon as they receive a WM_ACTIVATE message.
When the WM finishes moving the window, and since commit
92177b0b161e91f1d609615d89d8e3199feea33f we would retry to clip the
cursor with an incorrect rectangle.

Before the WM starts moving a window, an active pointer grab is usually
initiated and we can use the result of XGrabPointer to decide whether
the window is really focused or if we should wait until the WM has
finished.

This adds a pseudo modal loop that waits for XGrabPointer to succeed -
without any confine window to avoid spurious cursor movements - before
notifying the applications of FocusIn events.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

Not sure at all how the modal loop should be, I mostly reproduced the
one that is in move_resize_window, so if anyone has a better idea
I'll be happy to take it.

If this is too hackish, I believe it would be good to revert
92177b0b161e91f1d609615d89d8e3199feea33f, as it causes weird grabbing
issues when moving windows in several games.

 dlls/winex11.drv/event.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index f79f40c2323..e6190c56b1f 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -760,6 +760,33 @@ static const char * const focus_modes[] =
     "NotifyWhileGrabbed"
 };

+static void wait_for_pointer_ungrab( Display *display )
+{
+    struct x11drv_thread_data *thread_data = x11drv_thread_data();
+    XEvent *event;
+
+    while (XGrabPointer( display, DefaultRootWindow( display ), False,
+                         PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+                         GrabModeAsync, GrabModeAsync, None, None, CurrentTime ) != GrabSuccess)
+    {
+        MSG msg;
+
+        while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ))
+        {
+            TranslateMessage( &msg );
+            DispatchMessageW( &msg );
+        }
+
+        /* we still need to process the ConfigureNotify events while delaying the FocusIn */
+        event = thread_data->current_event;
+        thread_data->current_event = NULL;
+        MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
+        thread_data->current_event = event;
+    }
+
+    XUngrabPointer( display, CurrentTime );
+}
+
 /**********************************************************************
  *              X11DRV_FocusIn
  */
@@ -784,9 +811,11 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
         keyboard_grabbed = TRUE;
         break;
     case NotifyNormal:
+        wait_for_pointer_ungrab( event->display );
         keyboard_grabbed = FALSE;
         break;
     case NotifyUngrab:
+        wait_for_pointer_ungrab( event->display );
         keyboard_grabbed = FALSE;
         retry_grab_clipping_window();
         return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
--
2.23.0




More information about the wine-devel mailing list