From 84f085fb91a17e2efe83de0642b757948f4e8a7d Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 28 Apr 2011 13:07:05 +0200 Subject: [PATCH] winex11: Grab the mouse in the thread that owns the foreground window if possible. --- dlls/winex11.drv/mouse.c | 101 ++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 38 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 7f45a2a87a4..96d93e55c7d 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -368,33 +368,6 @@ static HWND create_clipping_msg_window(void) return CreateWindowW( class_name, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, GetModuleHandleW(0), NULL ); } -/*********************************************************************** - * clip_cursor_notify - * - * Notification function called upon receiving a WM_X11DRV_CLIP_CURSOR. - */ -LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) -{ - struct x11drv_thread_data *data = x11drv_thread_data(); - - if (hwnd == GetDesktopWindow()) /* change the clip window stored in the desktop process */ - { - static HWND 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 ); - } - else if (hwnd == data->clip_hwnd) /* this is a notification that clipping has been reset */ - { - data->clip_hwnd = 0; - disable_xinput2(); - DestroyWindow( hwnd ); - } - return 0; -} - /*********************************************************************** * grab_clipping_window * @@ -402,11 +375,12 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) */ static BOOL grab_clipping_window( const RECT *clip ) { - struct x11drv_thread_data *data = x11drv_init_thread_data(); - Window clip_window = init_clip_window(); + struct x11drv_thread_data *data = x11drv_thread_data(); + Window clip_window; HWND msg_hwnd = 0; - if (!clip_window) return TRUE; + if (!data) return FALSE; + if (!(clip_window = init_clip_window())) return TRUE; /* create a clip message window unless we are already clipping */ if (!data->clip_hwnd) @@ -474,6 +448,42 @@ void ungrab_clipping_window(void) SendMessageW( GetDesktopWindow(), WM_X11DRV_CLIP_CURSOR, 0, 0 ); } +/*********************************************************************** + * clip_cursor_notify + * + * Notification function called upon receiving a WM_X11DRV_CLIP_CURSOR. + */ +LRESULT clip_cursor_notify( HWND hwnd, HWND new_clip_hwnd ) +{ + struct x11drv_thread_data *data = x11drv_thread_data(); + + if (hwnd == GetDesktopWindow()) /* change the clip window stored in the desktop process */ + { + static HWND 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 ); + } + else if (hwnd == data->clip_hwnd) /* this is a notification that clipping has been reset */ + { + data->clip_hwnd = 0; + disable_xinput2(); + DestroyWindow( hwnd ); + } + else if (hwnd == GetForegroundWindow()) /* request to clip */ + { + RECT clip; + + GetClipCursor( &clip ); + if (clip.left > virtual_screen_rect.left || clip.right < virtual_screen_rect.right || + clip.top > virtual_screen_rect.top || clip.bottom < virtual_screen_rect.bottom) + return grab_clipping_window( &clip ); + } + return 0; +} + /*********************************************************************** * send_mouse_input * @@ -1191,16 +1201,31 @@ BOOL CDECL X11DRV_GetCursorPos(LPPOINT pos) */ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip ) { - /* we are clipping if the clip rectangle is smaller than the screen */ - if (clip && (clip->left > virtual_screen_rect.left || - clip->right < virtual_screen_rect.right || - clip->top > virtual_screen_rect.top || - clip->bottom < virtual_screen_rect.bottom)) + if (!clip) { - if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId()) - return TRUE; /* don't clip in the desktop process */ + ungrab_clipping_window(); + return TRUE; + } - if (grab_pointer && grab_clipping_window( clip )) return TRUE; + if (X11DRV_get_win_data( GetDesktopWindow() )) return TRUE; /* don't clip in the desktop process */ + + /* we are clipping if the clip rectangle is smaller than the screen */ + if (grab_pointer && (clip->left > virtual_screen_rect.left || + clip->right < virtual_screen_rect.right || + clip->top > virtual_screen_rect.top || + clip->bottom < virtual_screen_rect.bottom)) + { + DWORD tid, pid; + HWND foreground = GetForegroundWindow(); + + /* forward request to the foreground window if it's in a different thread */ + tid = GetWindowThreadProcessId( foreground, &pid ); + if (tid && tid != GetCurrentThreadId() && pid == GetCurrentProcessId()) + { + TRACE( "forwarding clip request to %p\n", foreground ); + if (SendMessageW( foreground, WM_X11DRV_CLIP_CURSOR, 0, 0 )) return TRUE; + } + else if (grab_clipping_window( clip )) return TRUE; } ungrab_clipping_window();