Commit a9e8f59c authored by Alexandre Julliard's avatar Alexandre Julliard

Moved mouse capture handling into the server.

parent 0b850f9f
......@@ -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);
......@@ -2366,6 +2365,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
*
* NOTE: WM_NEXTMENU documented in Win32 is a bit different.
......@@ -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)
{
......
......@@ -41,6 +41,7 @@
#include "nonclient.h"
#include "message.h"
#include "wine/server.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
......@@ -1829,6 +1830,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.@)
*
* Perform SC_MOVE and SC_SIZE commands.
......@@ -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 */
......
......@@ -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 */
......@@ -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 */
......@@ -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 */
......@@ -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;
}
}
......@@ -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 */
......
......@@ -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 ### */
......
......@@ -513,83 +513,27 @@ 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.
* SetCapture (USER32.@)
*/
HWND EVENT_Capture(HWND hwnd, INT16 ht)
HWND WINAPI SetCapture( HWND hwnd )
{
HWND capturePrev = 0, captureWnd = 0;
MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
WND* wndPtr = 0;
INT16 captureHT = 0;
HWND previous = 0;
capturePrev = GetCapture();
if (!hwnd)
SERVER_START_REQ( set_capture_window )
{
captureWnd = 0;
captureHT = 0;
}
else
{
wndPtr = WIN_FindWndPtr( hwnd );
if (wndPtr)
req->handle = hwnd;
req->flags = 0;
if (!wine_server_call_err( req ))
{
TRACE_(win)("(0x%04x)\n", hwnd );
captureWnd = wndPtr->hwndSelf;
captureHT = ht;
previous = reply->previous;
hwnd = reply->full_handle;
}
}
SERVER_END_REQ;
/* 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 );
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.@)
*
......
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment