The message was sent to two different types of windows, with a different semantic. We can now add parameters to the request without changing the notify parameters semantics.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/mouse.c | 41 ++++++++++++++++++++++++++------------- dlls/winex11.drv/window.c | 4 +++- dlls/winex11.drv/x11drv.h | 4 +++- 3 files changed, 33 insertions(+), 16 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 68e24a320af..add38a95ba7 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -445,7 +445,7 @@ static BOOL grab_clipping_window( const RECT *clip ) if (!data->clip_hwnd) sync_window_cursor( clip_window ); InterlockedExchangePointer( (void **)&cursor_window, msg_hwnd ); data->clip_hwnd = msg_hwnd; - SendNotifyMessageW( GetDesktopWindow(), WM_X11DRV_CLIP_CURSOR, 0, (LPARAM)msg_hwnd ); + SendNotifyMessageW( GetDesktopWindow(), WM_X11DRV_CLIP_CURSOR_NOTIFY, 0, (LPARAM)msg_hwnd ); return TRUE; }
@@ -465,7 +465,7 @@ void ungrab_clipping_window(void) XUnmapWindow( display, clip_window ); if (clipping_cursor) XUngrabPointer( display, CurrentTime ); clipping_cursor = FALSE; - SendNotifyMessageW( GetDesktopWindow(), WM_X11DRV_CLIP_CURSOR, 0, 0 ); + SendNotifyMessageW( GetDesktopWindow(), WM_X11DRV_CLIP_CURSOR_NOTIFY, 0, 0 ); }
/*********************************************************************** @@ -493,12 +493,10 @@ void retry_grab_clipping_window(void) ClipCursor( &last_clip_rect ); }
-BOOL CDECL X11DRV_ClipCursor( const RECT *clip ); - /*********************************************************************** * clip_cursor_notify * - * Notification function called upon receiving a WM_X11DRV_CLIP_CURSOR. + * Notification function called upon receiving a WM_X11DRV_CLIP_CURSOR_NOTIFY. */ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) { @@ -511,7 +509,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_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, (WPARAM)prev, 0 ); + if (prev) SendNotifyMessageW( prev, WM_X11DRV_CLIP_CURSOR_NOTIFY, (WPARAM)prev, 0 ); } else if (hwnd == data->clip_hwnd) /* this is a notification that clipping has been reset */ { @@ -521,13 +519,6 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) disable_xinput2(); DestroyWindow( hwnd ); } - else if (hwnd == GetForegroundWindow()) /* request to clip */ - { - RECT clip; - - GetClipCursor( &clip ); - X11DRV_ClipCursor( &clip ); - } else if (prev_clip_hwnd) { /* This is a notification send by the desktop window to an old @@ -1539,7 +1530,7 @@ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip ) if (tid && tid != GetCurrentThreadId() && pid == GetCurrentProcessId()) { TRACE( "forwarding clip request to %p\n", foreground ); - SendNotifyMessageW( foreground, WM_X11DRV_CLIP_CURSOR, 0, 0 ); + SendNotifyMessageW( foreground, WM_X11DRV_CLIP_CURSOR_REQUEST, 0, 0 ); return TRUE; }
@@ -1563,6 +1554,28 @@ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip ) return TRUE; }
+/*********************************************************************** + * clip_cursor_request + * + * Function called upon receiving a WM_X11DRV_CLIP_CURSOR_REQUEST. + */ +LRESULT clip_cursor_request( HWND hwnd ) +{ + RECT clip; + + if (hwnd == GetDesktopWindow()) + WARN( "ignoring clip cursor request on desktop window.\n" ); + else if (hwnd != GetForegroundWindow()) + WARN( "ignoring clip cursor request on non-foreground window.\n" ); + else + { + GetClipCursor( &clip ); + X11DRV_ClipCursor( &clip ); + } + + return 0; +} + /*********************************************************************** * move_resize_window */ diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 455957264bc..b0312b1a18b 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2781,8 +2781,10 @@ LRESULT CDECL X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) else if (hwnd == x11drv_thread_data()->clip_hwnd) set_window_cursor( x11drv_thread_data()->clip_window, (HCURSOR)lp ); return 0; - case WM_X11DRV_CLIP_CURSOR: + case WM_X11DRV_CLIP_CURSOR_NOTIFY: return clip_cursor_notify( hwnd, (HWND)wp, (HWND)lp ); + case WM_X11DRV_CLIP_CURSOR_REQUEST: + return clip_cursor_request( hwnd ); 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 a92c738a685..d4ee4a7c8df 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -538,7 +538,8 @@ enum x11drv_window_messages WM_X11DRV_SET_WIN_REGION, WM_X11DRV_RESIZE_DESKTOP, WM_X11DRV_SET_CURSOR, - WM_X11DRV_CLIP_CURSOR + WM_X11DRV_CLIP_CURSOR_NOTIFY, + WM_X11DRV_CLIP_CURSOR_REQUEST };
/* _NET_WM_STATE properties that we keep track of */ @@ -627,6 +628,7 @@ 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 prev_clip_hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN; +extern LRESULT clip_cursor_request( HWND 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;
If the current thread isn't the foreground thread. Otherwise we may clip the cursor in the wrong thread, that isn't expecting mouse messages or may not be checking its messages.
Red Faction has some race condition where this can happen for instance, with clip_fullscreen_window called from X11DRV_DisplayDevices_Update callback in a background thread. This thread starts clipping the cursor, and the foreground thread isn't receiving MotionNotify events anymore.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: Only forward the call done in update_windows_on_display_change, from X11DRV_DisplayDevices_Update. The other calls should already be in the correct thread and guarded with foreground window checks.
Doing in clip_fullscreen_window made the returned value confusing.
dlls/winex11.drv/display.c | 11 +++++++++-- dlls/winex11.drv/mouse.c | 6 ++++-- dlls/winex11.drv/window.c | 2 +- dlls/winex11.drv/x11drv.h | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c index 3e9e4474d4c..78fb922df60 100644 --- a/dlls/winex11.drv/display.c +++ b/dlls/winex11.drv/display.c @@ -370,14 +370,14 @@ static BOOL CALLBACK update_windows_on_display_change(HWND hwnd, LPARAM lparam) XReconfigureWMWindow(data->display, data->whole_window, data->vis.screen, mask, &changes); } release_win_data(data); - if (hwnd == GetForegroundWindow()) - clip_fullscreen_window(hwnd, TRUE); return TRUE; }
void X11DRV_DisplayDevices_Update(BOOL send_display_change) { RECT old_virtual_rect, new_virtual_rect; + DWORD tid, pid; + HWND foreground; UINT mask = 0;
old_virtual_rect = get_virtual_screen_rect(); @@ -392,6 +392,13 @@ void X11DRV_DisplayDevices_Update(BOOL send_display_change)
X11DRV_resize_desktop(send_display_change); EnumWindows(update_windows_on_display_change, (LPARAM)mask); + + /* forward clip_fullscreen_window request to the foreground window */ + if ((foreground = GetForegroundWindow()) && (tid = GetWindowThreadProcessId( foreground, &pid )) && pid == GetCurrentProcessId()) + { + if (tid == GetCurrentThreadId()) clip_fullscreen_window( foreground, TRUE ); + else SendNotifyMessageW( foreground, WM_X11DRV_CLIP_CURSOR_REQUEST, TRUE, TRUE ); + } }
/* Initialize a GPU instance. diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index add38a95ba7..dd25f8b172c 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1530,7 +1530,7 @@ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip ) if (tid && tid != GetCurrentThreadId() && pid == GetCurrentProcessId()) { TRACE( "forwarding clip request to %p\n", foreground ); - SendNotifyMessageW( foreground, WM_X11DRV_CLIP_CURSOR_REQUEST, 0, 0 ); + SendNotifyMessageW( foreground, WM_X11DRV_CLIP_CURSOR_REQUEST, FALSE, FALSE ); return TRUE; }
@@ -1559,7 +1559,7 @@ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip ) * * Function called upon receiving a WM_X11DRV_CLIP_CURSOR_REQUEST. */ -LRESULT clip_cursor_request( HWND hwnd ) +LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) { RECT clip;
@@ -1567,6 +1567,8 @@ LRESULT clip_cursor_request( HWND hwnd ) WARN( "ignoring clip cursor request on desktop window.\n" ); else if (hwnd != GetForegroundWindow()) WARN( "ignoring clip cursor request on non-foreground window.\n" ); + else if (fullscreen) + clip_fullscreen_window( hwnd, reset ); else { GetClipCursor( &clip ); diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index b0312b1a18b..457173964eb 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2784,7 +2784,7 @@ LRESULT CDECL X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) case WM_X11DRV_CLIP_CURSOR_NOTIFY: return clip_cursor_notify( hwnd, (HWND)wp, (HWND)lp ); case WM_X11DRV_CLIP_CURSOR_REQUEST: - return clip_cursor_request( hwnd ); + return clip_cursor_request( hwnd, (BOOL)wp, (BOOL)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 d4ee4a7c8df..173d94b9efa 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -628,7 +628,7 @@ 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 prev_clip_hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN; -extern LRESULT clip_cursor_request( HWND hwnd ) DECLSPEC_HIDDEN; +extern LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) 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;