From a9e8f59c95fec1bd653561644c9dce5a7212221d Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 12 Oct 2002 01:24:37 +0000 Subject: [PATCH] Moved mouse capture handling into the server. --- controls/menu.c | 44 ++++++++++---- dlls/x11drv/winpos.c | 32 ++++++++-- include/message.h | 4 -- include/wine/server_protocol.h | 21 ++++++- server/protocol.def | 11 ++++ server/queue.c | 19 ++++++ server/request.h | 2 + server/trace.c | 15 +++++ windows/input.c | 104 +++++++++------------------------ windows/message.c | 18 ++++-- 10 files changed, 168 insertions(+), 102 deletions(-) diff --git a/controls/menu.c b/controls/menu.c index 13f7d85ed42..52742a54c72 100644 --- a/controls/menu.c +++ b/controls/menu.c @@ -39,13 +39,12 @@ #include "wingdi.h" #include "wine/winbase16.h" #include "wine/winuser16.h" +#include "wine/server.h" #include "wine/unicode.h" #include "win.h" #include "controls.h" #include "nonclient.h" #include "user.h" -#include "message.h" - #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(menu); @@ -2365,6 +2364,30 @@ static BOOL MENU_MouseMove( MTRACKER* pmt, HMENU hPtMenu, UINT wFlags ) } +/*********************************************************************** + * MENU_SetCapture + */ +static void MENU_SetCapture( HWND hwnd ) +{ + HWND previous = 0; + + SERVER_START_REQ( set_capture_window ) + { + req->handle = hwnd; + req->flags = CAPTURE_MENU; + if (!wine_server_call_err( req )) + { + previous = reply->previous; + hwnd = reply->full_handle; + } + } + SERVER_END_REQ; + + if (previous && previous != hwnd) + SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd ); +} + + /*********************************************************************** * MENU_DoNextMenu * @@ -2450,9 +2473,8 @@ static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk ) if( hNewWnd != pmt->hOwnerWnd ) { - ReleaseCapture(); pmt->hOwnerWnd = hNewWnd; - EVENT_Capture( pmt->hOwnerWnd, HTMENU ); + MENU_SetCapture( pmt->hOwnerWnd ); } pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */ @@ -2681,7 +2703,7 @@ static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y, fEndMenu = !fRemove; } - EVENT_Capture( mt.hOwnerWnd, HTMENU ); + MENU_SetCapture( mt.hOwnerWnd ); while (!fEndMenu) { @@ -2735,14 +2757,12 @@ static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y, if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST)) { /* - * use the mouse coordinates in lParam instead of those in the MSG - * struct to properly handle synthetic messages. lParam coords are - * relative to client area, so they must be converted; since they can - * be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD. + * Use the mouse coordinates in lParam instead of those in the MSG + * struct to properly handle synthetic messages. They are already + * in screen coordinates. */ mt.pt.x = SLOWORD(msg.lParam); mt.pt.y = SHIWORD(msg.lParam); - ClientToScreen(msg.hwnd,&mt.pt); /* Find a menu for this mouse event */ hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt ); @@ -2911,7 +2931,7 @@ static INT MENU_TrackMenu( HMENU hmenu, UINT wFlags, INT x, INT y, else mt.trackFlags &= ~TF_SKIPREMOVE; } - ReleaseCapture(); + MENU_SetCapture(0); /* release the capture */ /* If dropdown is still painted and the close box is clicked on then the menu will be destroyed as part of the DispatchMessage above. @@ -3967,7 +3987,7 @@ BOOL WINAPI SetMenu( HWND hWnd, HMENU hMenu ) if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE; hWnd = WIN_GetFullHandle( hWnd ); - if (GetCapture() == hWnd) ReleaseCapture(); + if (GetCapture() == hWnd) MENU_SetCapture(0); /* release the capture */ if (hMenu != 0) { diff --git a/dlls/x11drv/winpos.c b/dlls/x11drv/winpos.c index 6f0f9776957..7edeec32e3f 100644 --- a/dlls/x11drv/winpos.c +++ b/dlls/x11drv/winpos.c @@ -41,6 +41,7 @@ #include "nonclient.h" #include "message.h" +#include "wine/server.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(x11drv); @@ -1828,6 +1829,29 @@ static LONG start_size_move( HWND hwnd, WPARAM wParam, POINT *capturePoint, LONG } +/*********************************************************************** + * set_movesize_capture + */ +static void set_movesize_capture( HWND hwnd ) +{ + HWND previous = 0; + + SERVER_START_REQ( set_capture_window ) + { + req->handle = hwnd; + req->flags = CAPTURE_MOVESIZE; + if (!wine_server_call_err( req )) + { + previous = reply->previous; + hwnd = reply->full_handle; + } + } + SERVER_END_REQ; + if (previous && previous != hwnd) + SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd ); +} + + /*********************************************************************** * SysCommandSizeMove (X11DRV.@) * @@ -1874,11 +1898,11 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam ) if ( hittest && hittest != HTSYSMENU ) hittest += 2; else { - SetCapture(hwnd); + set_movesize_capture( hwnd ); hittest = start_size_move( hwnd, wParam, &capturePoint, style ); if (!hittest) { - ReleaseCapture(); + set_movesize_capture(0); return; } } @@ -1938,7 +1962,7 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam ) RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN ); SendMessageA( hwnd, WM_ENTERSIZEMOVE, 0, 0 ); - SetCapture( hwnd ); + set_movesize_capture( hwnd ); /* grab the server only when moving top-level windows without desktop */ grab = (!DragFullWindows && !parent && (root_window == DefaultRootWindow(gdi_display))); @@ -2048,7 +2072,7 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam ) } } - ReleaseCapture(); + set_movesize_capture(0); if( iconic ) { if( moved ) /* restore cursors, show icon title later on */ diff --git a/include/message.h b/include/message.h index e1aa0c19dc4..b01eea15908 100644 --- a/include/message.h +++ b/include/message.h @@ -39,8 +39,4 @@ extern void TIMER_RemoveWindowTimers( HWND hwnd ); extern void TIMER_RemoveQueueTimers( HQUEUE16 hqueue ); extern BOOL TIMER_IsTimerValid( HWND hwnd, UINT id, HWINDOWPROC hProc ); -/* input.c */ - -extern HWND EVENT_Capture( HWND, INT16 ); - #endif /* __WINE_MESSAGE_H */ diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 7e0457d7b48..95e538cd3cb 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2802,6 +2802,22 @@ struct set_active_window_reply }; +struct set_capture_window_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int flags; +}; +struct set_capture_window_reply +{ + struct reply_header __header; + user_handle_t previous; + user_handle_t full_handle; +}; +#define CAPTURE_MENU 0x01 +#define CAPTURE_MOVESIZE 0x02 + + enum request { REQ_new_process, @@ -2965,6 +2981,7 @@ enum request REQ_set_foreground_window, REQ_set_focus_window, REQ_set_active_window, + REQ_set_capture_window, REQ_NB_REQUESTS }; @@ -3133,6 +3150,7 @@ union generic_request struct set_foreground_window_request set_foreground_window_request; struct set_focus_window_request set_focus_window_request; struct set_active_window_request set_active_window_request; + struct set_capture_window_request set_capture_window_request; }; union generic_reply { @@ -3299,8 +3317,9 @@ union generic_reply struct set_foreground_window_reply set_foreground_window_reply; struct set_focus_window_reply set_focus_window_reply; struct set_active_window_reply set_active_window_reply; + struct set_capture_window_reply set_capture_window_reply; }; -#define SERVER_PROTOCOL_VERSION 86 +#define SERVER_PROTOCOL_VERSION 87 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 6e72e97e9c4..3837f39786b 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1955,3 +1955,14 @@ enum message_type @REPLY user_handle_t previous; /* handle to the previous active window */ @END + +/* Set the current thread capture window */ +@REQ(set_capture_window) + user_handle_t handle; /* handle to the capture window */ + unsigned int flags; /* capture flags (see below) */ +@REPLY + user_handle_t previous; /* handle to the previous capture window */ + user_handle_t full_handle; /* full 32-bit handle of new capture window */ +@END +#define CAPTURE_MENU 0x01 /* capture is for a menu */ +#define CAPTURE_MOVESIZE 0x02 /* capture is for moving/resizing */ diff --git a/server/queue.c b/server/queue.c index 5d51e62aec7..5332dcfacb1 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1369,3 +1369,22 @@ DECL_HANDLER(set_active_window) else set_error( STATUS_INVALID_HANDLE ); } } + + +/* set the current thread capture window */ +DECL_HANDLER(set_capture_window) +{ + struct msg_queue *queue = get_current_queue(); + + reply->previous = reply->full_handle = 0; + if (queue && check_queue_input_window( queue, req->handle )) + { + struct thread_input *input = queue->input; + + reply->previous = input->capture; + input->capture = get_user_full_handle( req->handle ); + input->menu_owner = (req->flags & CAPTURE_MENU) ? input->capture : 0; + input->move_size = (req->flags & CAPTURE_MOVESIZE) ? input->capture : 0; + reply->full_handle = input->capture; + } +} diff --git a/server/request.h b/server/request.h index a6076d7fad9..63aea5421b0 100644 --- a/server/request.h +++ b/server/request.h @@ -264,6 +264,7 @@ DECL_HANDLER(get_thread_input); DECL_HANDLER(set_foreground_window); DECL_HANDLER(set_focus_window); DECL_HANDLER(set_active_window); +DECL_HANDLER(set_capture_window); #ifdef WANT_REQUEST_HANDLERS @@ -431,6 +432,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_set_foreground_window, (req_handler)req_set_focus_window, (req_handler)req_set_active_window, + (req_handler)req_set_capture_window, }; #endif /* WANT_REQUEST_HANDLERS */ diff --git a/server/trace.c b/server/trace.c index e680e589f46..9487057d570 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2233,6 +2233,18 @@ static void dump_set_active_window_reply( const struct set_active_window_reply * fprintf( stderr, " previous=%08x", req->previous ); } +static void dump_set_capture_window_request( const struct set_capture_window_request *req ) +{ + fprintf( stderr, " handle=%08x,", req->handle ); + fprintf( stderr, " flags=%08x", req->flags ); +} + +static void dump_set_capture_window_reply( const struct set_capture_window_reply *req ) +{ + fprintf( stderr, " previous=%08x,", req->previous ); + fprintf( stderr, " full_handle=%08x", req->full_handle ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_get_new_process_info_request, @@ -2395,6 +2407,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_foreground_window_request, (dump_func)dump_set_focus_window_request, (dump_func)dump_set_active_window_request, + (dump_func)dump_set_capture_window_request, }; static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -2559,6 +2572,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_foreground_window_reply, (dump_func)dump_set_focus_window_reply, (dump_func)dump_set_active_window_reply, + (dump_func)dump_set_capture_window_reply, }; static const char * const req_names[REQ_NB_REQUESTS] = { @@ -2723,6 +2737,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "set_foreground_window", "set_focus_window", "set_active_window", + "set_capture_window", }; /* ### make_requests end ### */ diff --git a/windows/input.c b/windows/input.c index 8857879de65..a9d63c820d9 100644 --- a/windows/input.c +++ b/windows/input.c @@ -512,84 +512,28 @@ BOOL WINAPI SetCursorPos( INT x, INT y ) } -/********************************************************************** - * EVENT_Capture - * - * We need this to be able to generate double click messages - * when menu code captures mouse in the window without CS_DBLCLK style. - */ -HWND EVENT_Capture(HWND hwnd, INT16 ht) -{ - HWND capturePrev = 0, captureWnd = 0; - MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0; - WND* wndPtr = 0; - INT16 captureHT = 0; - - capturePrev = GetCapture(); - - if (!hwnd) - { - captureWnd = 0; - captureHT = 0; - } - else - { - wndPtr = WIN_FindWndPtr( hwnd ); - if (wndPtr) - { - TRACE_(win)("(0x%04x)\n", hwnd ); - captureWnd = wndPtr->hwndSelf; - captureHT = ht; - } - } - - /* Get the messageQ for the current thread */ - if (!(pCurMsgQ = QUEUE_Current())) - { - WARN_(win)("\tCurrent message queue not found. Exiting!\n" ); - goto CLEANUP; - } - - /* Update the perQ capture window and send messages */ - if( capturePrev != captureWnd ) - { - if (wndPtr) - { - /* Retrieve the message queue associated with this window */ - pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ ); - if ( !pMsgQ ) - { - WARN_(win)("\tMessage queue not found. Exiting!\n" ); - goto CLEANUP; - } - - /* Make sure that message queue for the window we are setting capture to - * shares the same perQ data as the current threads message queue. - */ - if ( pCurMsgQ->pQData != pMsgQ->pQData ) - goto CLEANUP; - } - - PERQDATA_SetCaptureWnd( captureWnd, captureHT ); - if (capturePrev) SendMessageA( capturePrev, WM_CAPTURECHANGED, 0, (LPARAM)hwnd ); - } - -CLEANUP: - /* Unlock the queues before returning */ - if ( pMsgQ ) - QUEUE_Unlock( pMsgQ ); - - WIN_ReleaseWndPtr(wndPtr); - return capturePrev; -} - - /********************************************************************** * SetCapture (USER32.@) */ HWND WINAPI SetCapture( HWND hwnd ) { - return EVENT_Capture( hwnd, HTCLIENT ); + HWND previous = 0; + + SERVER_START_REQ( set_capture_window ) + { + req->handle = hwnd; + req->flags = 0; + if (!wine_server_call_err( req )) + { + previous = reply->previous; + hwnd = reply->full_handle; + } + } + SERVER_END_REQ; + + if (previous && previous != hwnd) + SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd ); + return previous; } @@ -598,7 +542,7 @@ HWND WINAPI SetCapture( HWND hwnd ) */ BOOL WINAPI ReleaseCapture(void) { - return (EVENT_Capture( 0, 0 ) != 0); + return (SetCapture(0) != 0); } @@ -607,10 +551,18 @@ BOOL WINAPI ReleaseCapture(void) */ HWND WINAPI GetCapture(void) { - INT hittest; - return PERQDATA_GetCaptureWnd( &hittest ); + HWND ret = 0; + + SERVER_START_REQ( get_thread_input ) + { + req->tid = GetCurrentThreadId(); + if (!wine_server_call_err( req )) ret = reply->capture; + } + SERVER_END_REQ; + return ret; } + /********************************************************************** * GetAsyncKeyState (USER32.@) * diff --git a/windows/message.c b/windows/message.c index f789f2691c4..5fe885fabe0 100644 --- a/windows/message.c +++ b/windows/message.c @@ -384,12 +384,14 @@ static BOOL process_raw_mouse_message( MSG *msg, ULONG_PTR extra_info ) static MSG clk_msg; POINT pt; - INT ht, hittest; + INT hittest; + GUITHREADINFO info; /* find the window to dispatch this mouse message to */ hittest = HTCLIENT; - if (!(msg->hwnd = PERQDATA_GetCaptureWnd( &ht ))) + GetGUIThreadInfo( GetCurrentThreadId(), &info ); + if (!(msg->hwnd = info.hwndCapture)) { /* If no capture HWND, find window which contains the mouse position. * Also find the position of the cursor hot spot (hittest) */ @@ -398,7 +400,6 @@ static BOOL process_raw_mouse_message( MSG *msg, ULONG_PTR extra_info ) if (!IsWindow(hWndScope)) hWndScope = 0; if (!(msg->hwnd = WINPOS_WindowFromPoint( hWndScope, msg->pt, &hittest ))) msg->hwnd = GetDesktopWindow(); - ht = hittest; } if (HOOK_IsHooked( WH_JOURNALRECORD )) @@ -423,7 +424,9 @@ static BOOL process_raw_mouse_message( MSG *msg, ULONG_PTR extra_info ) * note that ...MOUSEMOVEs can slip in between * ...BUTTONDOWN and ...BUTTONDBLCLK messages */ - if (GetClassLongA( msg->hwnd, GCL_STYLE ) & CS_DBLCLKS || ht != HTCLIENT ) + if ((info.flags & (GUI_INMENUMODE|GUI_INMOVESIZE)) || + hittest != HTCLIENT || + (GetClassLongA( msg->hwnd, GCL_STYLE ) & CS_DBLCLKS)) { if ((msg->message == clk_msg.message) && (msg->hwnd == clk_msg.hwnd) && @@ -447,7 +450,12 @@ static BOOL process_raw_mouse_message( MSG *msg, ULONG_PTR extra_info ) msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE; msg->wParam = hittest; } - else ScreenToClient( msg->hwnd, &pt ); + else + { + /* coordinates don't get translated while tracking a menu */ + /* FIXME: should differentiate popups and top-level menus */ + if (!(info.flags & GUI_INMENUMODE)) ScreenToClient( msg->hwnd, &pt ); + } msg->lParam = MAKELONG( pt.x, pt.y ); return TRUE; }