[PATCH v3 6/6] winex11.drv: Retry last ClipCursor when grab is released

Rémi Bernon rbernon at codeweavers.com
Thu Jun 27 09:30:15 CDT 2019


As we ignore these NotifyGrab / NotifyUngrab w.r.t focus decisions,
some applications are unaware of mouse grabs being lost and sometimes
cursor clipping is lost. We have to keep the last clip rectangle and
restore it when grab is released.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/winex11.drv/event.c  |  8 ++++++++
 dlls/winex11.drv/mouse.c  | 22 ++++++++++++++++++++++
 dlls/winex11.drv/x11drv.h |  1 +
 3 files changed, 31 insertions(+)

diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index 21ee2aa084e..10b61482e82 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -788,6 +788,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
         break;
     case NotifyUngrab:
         keyboard_grabbed = FALSE;
+        retry_grab_clipping_window();
         return FALSE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
     }
 
@@ -888,6 +889,13 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev )
         break;
     case NotifyGrab:
         keyboard_grabbed = TRUE;
+
+        /* This will do nothing due to keyboard_grabbed == TRUE, but it
+         * will save the current clipping rect so we can restore it on
+         * FocusIn with NotifyUngrab mode.
+         */
+        retry_grab_clipping_window();
+
         return FALSE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */
     }
 
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index fa976cae7fb..3bf6582c9db 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -125,6 +125,8 @@ XContext cursor_context = 0;
 static HWND cursor_window;
 static HCURSOR last_cursor;
 static DWORD last_cursor_change;
+static RECT last_clip_rect;
+static BOOL last_clip_refused;
 static RECT clip_rect;
 static Cursor create_cursor( HANDLE handle );
 
@@ -395,8 +397,14 @@ static BOOL grab_clipping_window( const RECT *clip )
     if (keyboard_grabbed)
     {
         WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) );
+        last_clip_refused = TRUE;
+        last_clip_rect = *clip;
         return FALSE;
     }
+    else
+    {
+        last_clip_refused = FALSE;
+    }
 
     /* enable XInput2 unless we are already clipping */
     if (!data->clip_hwnd) enable_xinput2();
@@ -470,6 +478,20 @@ void reset_clipping_window(void)
     ClipCursor( NULL );  /* make sure the clip rectangle is reset too */
 }
 
+/***********************************************************************
+ *      retry_grab_clipping_window
+ *
+ * Restore the current clip rectangle or retry the last one if it has
+ * been refused because of an active keyboard grab.
+ */
+void retry_grab_clipping_window(void)
+{
+    if (clipping_cursor)
+        ClipCursor( &clip_rect );
+    else if (last_clip_refused)
+        ClipCursor( &last_clip_rect );
+}
+
 BOOL CDECL X11DRV_ClipCursor( const RECT *clip );
 
 /***********************************************************************
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 2dfa2a20ce9..582f802be84 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -624,6 +624,7 @@ extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN;
 extern LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN;
 extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN;
 extern void reset_clipping_window(void) DECLSPEC_HIDDEN;
+extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN;
 extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN;
 extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN;
 extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN;
-- 
2.20.1




More information about the wine-devel mailing list