[PATCH v4] winex11.drv: Destroy old clipping message window if it has been replaced

Rémi Bernon rbernon at codeweavers.com
Tue Aug 13 07:17:15 CDT 2019


When the same thread repeatedly calls ClipCursor, a message window is
created for every call, then stored in x11drv_thread_data->clip_hwnd.

The WM_X11DRV_CLIP_CURSOR notification is then sent to the desktop
window, then to the previous clipping thread in order for it to destroy
its clip_hwnd. But as the clipping thread is the same, and because
x11drv_thread_data->clip_hwnd has been overwritten, it does not satisfy
the "hwnd == data->clip_hwnd" condition and the window leaked.

This was causing exhaustion of user handles, and ultimately, failures to
create new clipping message windows, which then in turn makes the
pointer grab be lost.

This change makes sure that any dangling clipping message window is
properly destroyed.

Note: Implementing this by avoiding the re-creation of clipping message
window leads to a race condition when ClipCursor rect is reset then
restored: the desktop process sends reset notification which may be
processed after the clipping rect has already been restored.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/winex11.drv/mouse.c  | 12 ++++++++++--
 dlls/winex11.drv/window.c |  2 +-
 dlls/winex11.drv/x11drv.h |  2 +-
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index f737a306a56..75e3167e5f9 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -471,7 +471,7 @@ BOOL CDECL X11DRV_ClipCursor( const RECT *clip );
  *
  * Notification function called upon receiving a WM_X11DRV_CLIP_CURSOR.
  */
-LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd )
+LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd )
 {
     struct x11drv_thread_data *data = x11drv_init_thread_data();

@@ -482,7 +482,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd )
         HWND prev = clip_hwnd;
         clip_hwnd = new_clip_hwnd;
         if (prev || new_clip_hwnd) TRACE( "clip hwnd changed from %p to %p\n", prev, new_clip_hwnd );
-        if (prev) SendNotifyMessageW( prev, WM_X11DRV_CLIP_CURSOR, 0, 0 );
+        if (prev) SendNotifyMessageW( prev, WM_X11DRV_CLIP_CURSOR, (WPARAM)prev, 0 );
     }
     else if (hwnd == data->clip_hwnd)  /* this is a notification that clipping has been reset */
     {
@@ -499,6 +499,14 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd )
         GetClipCursor( &clip );
         X11DRV_ClipCursor( &clip );
     }
+    else if (prev_clip_hwnd)
+    {
+        /* This is a notification send by the desktop window to an old
+         * dangling clip window.
+         */
+        TRACE( "destroying old clip hwnd %p\n", prev_clip_hwnd );
+        DestroyWindow( prev_clip_hwnd );
+    }
     return 0;
 }

diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index fb97ec5a0d4..73aa78a17fc 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -2727,7 +2727,7 @@ LRESULT CDECL X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
             set_window_cursor( x11drv_thread_data()->clip_window, (HCURSOR)lp );
         return 0;
     case WM_X11DRV_CLIP_CURSOR:
-        return clip_cursor_notify( hwnd, (HWND)lp );
+        return clip_cursor_notify( hwnd, (HWND)wp, (HWND)lp );
     default:
         FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp );
         return 0;
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 0d3695bdcf8..aa01f2c3830 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -620,7 +620,7 @@ extern void X11DRV_InitClipboard(void) DECLSPEC_HIDDEN;
 extern void CDECL X11DRV_SetFocus( HWND hwnd ) DECLSPEC_HIDDEN;
 extern void set_window_cursor( Window window, HCURSOR handle ) DECLSPEC_HIDDEN;
 extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN;
-extern LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN;
+extern LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN;
 extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN;
 extern void reset_clipping_window(void) DECLSPEC_HIDDEN;
 extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN;
--
2.23.0.rc1




More information about the wine-devel mailing list