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. --- dlls/winex11.drv/mouse.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f737a306a56..bb07e289a2d 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -499,6 +499,14 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) GetClipCursor( &clip ); X11DRV_ClipCursor( &clip ); } + else if (hwnd) + { + /* This is a notification send by the desktop window to an old + * dangling clip window. + */ + TRACE( "destroying old clip hwnd %p\n", hwnd ); + DestroyWindow( hwnd ); + } return 0; }