On Thu Sep 29 10:36:42 2022 +0000, Rémi Bernon wrote:
Hmm, I think that's the same logic as how it is currently done: `X11DRV_resize_desktop` is already sending a message to the desktop window if it's not called from the desktop thread, so its actual logic is only executed from the desktop thread: https://gitlab.winehq.org/wine/wine/-/blob/master/dlls/winex11.drv/desktop.c...
if (NtUserGetWindowThread( hwnd, NULL ) != GetCurrentThreadId()) { send_message( hwnd, WM_X11DRV_RESIZE_DESKTOP, 0, 0 ); } else { /* ... */ ungrab_clipping_window(); }
From that thread, `ungrab_clipping_window` indeed skips the `XUngrabPointer`, but sends a `WM_X11DRV_CLIP_CURSOR_NOTIFY` message to the desktop window (so the thread itself): https://gitlab.winehq.org/wine/wine/-/blob/master/dlls/winex11.drv/mouse.c#L...
void ungrab_clipping_window(void) { /* ... */ if (clipping_cursor) XUngrabPointer( display, CurrentTime ); clipping_cursor = FALSE; send_notify_message( NtUserGetDesktopWindow(), WM_X11DRV_CLIP_CURSOR_NOTIFY, 0, 0 ); }
Which is later use to reset some desktop clip_hwnd variable, and forwarded to the previously clipping window: https://gitlab.winehq.org/wine/wine/-/blob/master/dlls/winex11.drv/mouse.c#L...
if (hwnd == NtUserGetDesktopWindow()) /* change the clip window stored in the desktop process */ { static HWND clip_hwnd; HWND prev = clip_hwnd; clip_hwnd = new_clip_hwnd; if (prev) send_notify_message( prev, WM_X11DRV_CLIP_CURSOR_NOTIFY, (WPARAM)prev, 0 ); }
This then translates, in the currently clipping thread, to the cursor being ungrabbed and the clipping window being destroyed: https://gitlab.winehq.org/wine/wine/-/blob/master/dlls/winex11.drv/mouse.c#L...
else if (hwnd == data->clip_hwnd) /* this is a notification that clipping has been reset */ { disable_xinput2(); NtUserDestroyWindow( hwnd ); }
**Then however**, I think you're right that the changes can break clipping, but I think it's because of https://gitlab.winehq.org/wine/wine/-/merge_requests/944/diffs?commit_id=1cf... instead: Moving that part to `X11DRV_resize_desktop` makes it likely never match the condition, because the desktop is unlikely to be the foreground process. Instead I think it can simply send the `WM_X11DRV_CLIP_CURSOR_REQUEST` to the foreground window without even checking the thread id / pid.
/* forward clip_fullscreen_window request to the foreground window */ if ((foreground = NtUserGetForegroundWindow()) && (tid = NtUserGetWindowThread( foreground, &pid )) && pid == GetCurrentProcessId()) { if (tid == GetCurrentThreadId()) clip_fullscreen_window( foreground, TRUE ); else send_notify_message( foreground, WM_X11DRV_CLIP_CURSOR_REQUEST, TRUE, TRUE ); }
That should still asynchronously restore clipping from the foreground process if fullscreen clipping is enabled, and always after the reset logic described above.
Yeah, that sounds about right.