Moved mouse capture handling into the server.

This commit is contained in:
Alexandre Julliard 2002-10-12 01:24:37 +00:00
parent 0b850f9f74
commit a9e8f59c95
10 changed files with 168 additions and 102 deletions

View File

@ -39,13 +39,12 @@
#include "wingdi.h" #include "wingdi.h"
#include "wine/winbase16.h" #include "wine/winbase16.h"
#include "wine/winuser16.h" #include "wine/winuser16.h"
#include "wine/server.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#include "win.h" #include "win.h"
#include "controls.h" #include "controls.h"
#include "nonclient.h" #include "nonclient.h"
#include "user.h" #include "user.h"
#include "message.h"
#include "wine/debug.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(menu); 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 * MENU_DoNextMenu
* *
@ -2450,9 +2473,8 @@ static LRESULT MENU_DoNextMenu( MTRACKER* pmt, UINT vk )
if( hNewWnd != pmt->hOwnerWnd ) if( hNewWnd != pmt->hOwnerWnd )
{ {
ReleaseCapture();
pmt->hOwnerWnd = hNewWnd; pmt->hOwnerWnd = hNewWnd;
EVENT_Capture( pmt->hOwnerWnd, HTMENU ); MENU_SetCapture( pmt->hOwnerWnd );
} }
pmt->hTopMenu = pmt->hCurrentMenu = hNewMenu; /* all subpopups are hidden */ 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; fEndMenu = !fRemove;
} }
EVENT_Capture( mt.hOwnerWnd, HTMENU ); MENU_SetCapture( mt.hOwnerWnd );
while (!fEndMenu) 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)) if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
{ {
/* /*
* use the mouse coordinates in lParam instead of those in the MSG * Use the mouse coordinates in lParam instead of those in the MSG
* struct to properly handle synthetic messages. lParam coords are * struct to properly handle synthetic messages. They are already
* relative to client area, so they must be converted; since they can * in screen coordinates.
* be negative, we must use SLOWORD/SHIWORD instead of LOWORD/HIWORD.
*/ */
mt.pt.x = SLOWORD(msg.lParam); mt.pt.x = SLOWORD(msg.lParam);
mt.pt.y = SHIWORD(msg.lParam); mt.pt.y = SHIWORD(msg.lParam);
ClientToScreen(msg.hwnd,&mt.pt);
/* Find a menu for this mouse event */ /* Find a menu for this mouse event */
hmenu = MENU_PtMenu( mt.hTopMenu, mt.pt ); 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; else mt.trackFlags &= ~TF_SKIPREMOVE;
} }
ReleaseCapture(); MENU_SetCapture(0); /* release the capture */
/* If dropdown is still painted and the close box is clicked on /* If dropdown is still painted and the close box is clicked on
then the menu will be destroyed as part of the DispatchMessage above. 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; if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_CHILD) return FALSE;
hWnd = WIN_GetFullHandle( hWnd ); hWnd = WIN_GetFullHandle( hWnd );
if (GetCapture() == hWnd) ReleaseCapture(); if (GetCapture() == hWnd) MENU_SetCapture(0); /* release the capture */
if (hMenu != 0) if (hMenu != 0)
{ {

View File

@ -41,6 +41,7 @@
#include "nonclient.h" #include "nonclient.h"
#include "message.h" #include "message.h"
#include "wine/server.h"
#include "wine/debug.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(x11drv); 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.@) * SysCommandSizeMove (X11DRV.@)
* *
@ -1874,11 +1898,11 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
if ( hittest && hittest != HTSYSMENU ) hittest += 2; if ( hittest && hittest != HTSYSMENU ) hittest += 2;
else else
{ {
SetCapture(hwnd); set_movesize_capture( hwnd );
hittest = start_size_move( hwnd, wParam, &capturePoint, style ); hittest = start_size_move( hwnd, wParam, &capturePoint, style );
if (!hittest) if (!hittest)
{ {
ReleaseCapture(); set_movesize_capture(0);
return; return;
} }
} }
@ -1938,7 +1962,7 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN ); RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
SendMessageA( hwnd, WM_ENTERSIZEMOVE, 0, 0 ); SendMessageA( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
SetCapture( hwnd ); set_movesize_capture( hwnd );
/* grab the server only when moving top-level windows without desktop */ /* grab the server only when moving top-level windows without desktop */
grab = (!DragFullWindows && !parent && (root_window == DefaultRootWindow(gdi_display))); 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( iconic )
{ {
if( moved ) /* restore cursors, show icon title later on */ if( moved ) /* restore cursors, show icon title later on */

View File

@ -39,8 +39,4 @@ extern void TIMER_RemoveWindowTimers( HWND hwnd );
extern void TIMER_RemoveQueueTimers( HQUEUE16 hqueue ); extern void TIMER_RemoveQueueTimers( HQUEUE16 hqueue );
extern BOOL TIMER_IsTimerValid( HWND hwnd, UINT id, HWINDOWPROC hProc ); extern BOOL TIMER_IsTimerValid( HWND hwnd, UINT id, HWINDOWPROC hProc );
/* input.c */
extern HWND EVENT_Capture( HWND, INT16 );
#endif /* __WINE_MESSAGE_H */ #endif /* __WINE_MESSAGE_H */

View File

@ -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 enum request
{ {
REQ_new_process, REQ_new_process,
@ -2965,6 +2981,7 @@ enum request
REQ_set_foreground_window, REQ_set_foreground_window,
REQ_set_focus_window, REQ_set_focus_window,
REQ_set_active_window, REQ_set_active_window,
REQ_set_capture_window,
REQ_NB_REQUESTS REQ_NB_REQUESTS
}; };
@ -3133,6 +3150,7 @@ union generic_request
struct set_foreground_window_request set_foreground_window_request; struct set_foreground_window_request set_foreground_window_request;
struct set_focus_window_request set_focus_window_request; struct set_focus_window_request set_focus_window_request;
struct set_active_window_request set_active_window_request; struct set_active_window_request set_active_window_request;
struct set_capture_window_request set_capture_window_request;
}; };
union generic_reply union generic_reply
{ {
@ -3299,8 +3317,9 @@ union generic_reply
struct set_foreground_window_reply set_foreground_window_reply; struct set_foreground_window_reply set_foreground_window_reply;
struct set_focus_window_reply set_focus_window_reply; struct set_focus_window_reply set_focus_window_reply;
struct set_active_window_reply set_active_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 */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -1955,3 +1955,14 @@ enum message_type
@REPLY @REPLY
user_handle_t previous; /* handle to the previous active window */ user_handle_t previous; /* handle to the previous active window */
@END @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 */

View File

@ -1369,3 +1369,22 @@ DECL_HANDLER(set_active_window)
else set_error( STATUS_INVALID_HANDLE ); 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;
}
}

View File

@ -264,6 +264,7 @@ DECL_HANDLER(get_thread_input);
DECL_HANDLER(set_foreground_window); DECL_HANDLER(set_foreground_window);
DECL_HANDLER(set_focus_window); DECL_HANDLER(set_focus_window);
DECL_HANDLER(set_active_window); DECL_HANDLER(set_active_window);
DECL_HANDLER(set_capture_window);
#ifdef WANT_REQUEST_HANDLERS #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_foreground_window,
(req_handler)req_set_focus_window, (req_handler)req_set_focus_window,
(req_handler)req_set_active_window, (req_handler)req_set_active_window,
(req_handler)req_set_capture_window,
}; };
#endif /* WANT_REQUEST_HANDLERS */ #endif /* WANT_REQUEST_HANDLERS */

View File

@ -2233,6 +2233,18 @@ static void dump_set_active_window_reply( const struct set_active_window_reply *
fprintf( stderr, " previous=%08x", req->previous ); 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] = { static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request, (dump_func)dump_new_process_request,
(dump_func)dump_get_new_process_info_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_foreground_window_request,
(dump_func)dump_set_focus_window_request, (dump_func)dump_set_focus_window_request,
(dump_func)dump_set_active_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] = { 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_foreground_window_reply,
(dump_func)dump_set_focus_window_reply, (dump_func)dump_set_focus_window_reply,
(dump_func)dump_set_active_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] = { 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_foreground_window",
"set_focus_window", "set_focus_window",
"set_active_window", "set_active_window",
"set_capture_window",
}; };
/* ### make_requests end ### */ /* ### make_requests end ### */

View File

@ -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.@) * SetCapture (USER32.@)
*/ */
HWND WINAPI SetCapture( HWND hwnd ) 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) BOOL WINAPI ReleaseCapture(void)
{ {
return (EVENT_Capture( 0, 0 ) != 0); return (SetCapture(0) != 0);
} }
@ -607,9 +551,17 @@ BOOL WINAPI ReleaseCapture(void)
*/ */
HWND WINAPI GetCapture(void) HWND WINAPI GetCapture(void)
{ {
INT hittest; HWND ret = 0;
return PERQDATA_GetCaptureWnd( &hittest );
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.@) * GetAsyncKeyState (USER32.@)

View File

@ -384,12 +384,14 @@ static BOOL process_raw_mouse_message( MSG *msg, ULONG_PTR extra_info )
static MSG clk_msg; static MSG clk_msg;
POINT pt; POINT pt;
INT ht, hittest; INT hittest;
GUITHREADINFO info;
/* find the window to dispatch this mouse message to */ /* find the window to dispatch this mouse message to */
hittest = HTCLIENT; 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. /* If no capture HWND, find window which contains the mouse position.
* Also find the position of the cursor hot spot (hittest) */ * 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 (!IsWindow(hWndScope)) hWndScope = 0;
if (!(msg->hwnd = WINPOS_WindowFromPoint( hWndScope, msg->pt, &hittest ))) if (!(msg->hwnd = WINPOS_WindowFromPoint( hWndScope, msg->pt, &hittest )))
msg->hwnd = GetDesktopWindow(); msg->hwnd = GetDesktopWindow();
ht = hittest;
} }
if (HOOK_IsHooked( WH_JOURNALRECORD )) 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 * note that ...MOUSEMOVEs can slip in between
* ...BUTTONDOWN and ...BUTTONDBLCLK messages */ * ...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) && if ((msg->message == clk_msg.message) &&
(msg->hwnd == clk_msg.hwnd) && (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->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
msg->wParam = hittest; 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 ); msg->lParam = MAKELONG( pt.x, pt.y );
return TRUE; return TRUE;
} }