Commit 9f55ae6f authored by Alexandre Julliard's avatar Alexandre Julliard

- Remove cooked hardware messages when they are dropped (reported by

Gerard Patel). - Convert all posted 32-bit messages to Unicode before storing them in the queue. - Faster implementation of MSG_IsPointerMessage. - Moved a couple of functions from queue.c to message.c.
parent ed2f19a6
......@@ -14,21 +14,6 @@
#include "thread.h"
/* Message as stored in the queue (contains the extraInfo field) */
typedef struct tagQMSG
{
int kind; /* message kind (sent,posted,hardware) */
int type;
MSG msg;
DWORD extraInfo; /* Only in 3.1 */
} QMSG;
#define QMSG_WIN16 0
#define QMSG_WIN32A 1
#define QMSG_WIN32W 2
#define QMSG_HARDWARE 3
/* Per-queue data for the message queue
* Note that we currently only store the current values for
* Active, Capture and Focus windows currently.
......@@ -82,10 +67,8 @@ extern MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue );
extern void QUEUE_Unlock( MESSAGEQUEUE *queue );
extern BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue );
extern void QUEUE_SetExitingQueue( HQUEUE16 hQueue );
extern int QUEUE_WaitBits( WORD bits, DWORD timeout );
extern BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue );
extern HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue );
extern BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove, QMSG *msg );
extern void QUEUE_CleanupWindow( HWND hwnd );
extern HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags );
......
......@@ -1379,7 +1379,7 @@ struct get_message_request
};
#define GET_MSG_REMOVE 1 /* remove the message */
#define GET_MSG_SENT_ONLY 2 /* only get sent messages */
#define GET_MSG_REMOVE_LAST 4 /* remove last message returned before checking for a new one */
/* Reply to a sent message */
struct reply_message_request
......
......@@ -73,6 +73,8 @@ struct msg_queue
struct message_list msg_list[NB_MSG_KINDS]; /* lists of messages */
struct message_result *send_result; /* stack of sent messages waiting for result */
struct message_result *recv_result; /* stack of received messages waiting for result */
struct message *last_msg; /* last msg returned to the app and not removed */
enum message_kind last_msg_kind; /* message kind of last_msg */
struct timer *first_timer; /* head of timer list */
struct timer *last_timer; /* tail of timer list */
struct timer *next_timer; /* next timer to expire */
......@@ -118,6 +120,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread )
queue->paint_count = 0;
queue->send_result = NULL;
queue->recv_result = NULL;
queue->last_msg = NULL;
queue->first_timer = NULL;
queue->last_timer = NULL;
queue->next_timer = NULL;
......@@ -208,6 +211,7 @@ static void remove_queue_message( struct msg_queue *queue, struct message *msg,
int clr_bit;
struct message *other;
if (queue->last_msg == msg) queue->last_msg = NULL;
unlink_message( &queue->msg_list[kind], msg );
switch(kind)
{
......@@ -708,6 +712,26 @@ inline static void put_req_message( struct get_message_request *req, const struc
req->info = msg->info;
}
/* return a message to the application, removing it from the queue if needed */
static void return_message_to_app( struct msg_queue *queue, struct get_message_request *req,
struct message *msg, enum message_kind kind )
{
req->kind = kind;
put_req_message( req, msg );
/* raw messages always get removed */
if ((kind == RAW_HW_MESSAGE) || (req->flags & GET_MSG_REMOVE))
{
queue->last_msg = NULL;
remove_queue_message( queue, msg, kind );
}
else /* remember it as the last returned message */
{
queue->last_msg = msg;
queue->last_msg_kind = kind;
}
}
inline static struct message *find_matching_message( const struct message_list *list, handle_t win,
unsigned int first, unsigned int last )
{
......@@ -716,6 +740,7 @@ inline static struct message *find_matching_message( const struct message_list *
for (msg = list->first; msg; msg = msg->next)
{
/* check against the filters */
if (msg->msg == WM_QUIT) break; /* WM_QUIT is never filtered */
if (win && msg->win && msg->win != win) continue;
if (msg->msg < first) continue;
if (msg->msg > last) continue;
......@@ -744,13 +769,19 @@ DECL_HANDLER(get_message)
}
if (req->flags & GET_MSG_SENT_ONLY) goto done; /* nothing else to check */
/* if requested, remove the last returned but not yet removed message */
if ((req->flags & GET_MSG_REMOVE_LAST) && queue->last_msg)
remove_queue_message( queue, queue->last_msg, queue->last_msg_kind );
queue->last_msg = NULL;
/* clear changed bits so we can wait on them if we don't find a message */
queue->changed_bits = 0;
/* then check for posted messages */
if ((msg = find_matching_message( &queue->msg_list[POST_MESSAGE], req->get_win,
req->get_first, req->get_last )))
{
req->kind = POST_MESSAGE;
put_req_message( req, msg );
if (req->flags & GET_MSG_REMOVE) remove_queue_message( queue, msg, POST_MESSAGE );
return_message_to_app( queue, req, msg, POST_MESSAGE );
return;
}
......@@ -758,19 +789,14 @@ DECL_HANDLER(get_message)
if ((msg = find_matching_message( &queue->msg_list[COOKED_HW_MESSAGE], req->get_win,
req->get_first, req->get_last )))
{
req->kind = COOKED_HW_MESSAGE;
put_req_message( req, msg );
if (req->flags & GET_MSG_REMOVE) remove_queue_message( queue, msg, COOKED_HW_MESSAGE );
return_message_to_app( queue, req, msg, COOKED_HW_MESSAGE );
return;
}
/* then check for any raw hardware message */
if ((msg = queue->msg_list[RAW_HW_MESSAGE].first))
{
req->kind = RAW_HW_MESSAGE;
put_req_message( req, msg );
/* raw messages always get removed */
remove_queue_message( queue, msg, RAW_HW_MESSAGE );
return_message_to_app( queue, req, msg, RAW_HW_MESSAGE );
return;
}
......
......@@ -88,7 +88,7 @@ static void queue_raw_hardware_message( UINT message, WPARAM wParam, LPARAM lPar
{
req->kind = RAW_HW_MESSAGE;
req->id = (void *)GetCurrentThreadId();
req->type = QMSG_HARDWARE;
req->type = 0;
req->win = 0;
req->msg = message;
req->wparam = wParam;
......
......@@ -417,210 +417,6 @@ BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
/***********************************************************************
* handle_sent_message
*
* Handle the reception of a sent message by calling the corresponding window proc
*/
static void handle_sent_message( QMSG *msg )
{
LRESULT result = 0;
MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
WND *wndPtr = WIN_FindWndPtr( msg->msg.hwnd );
TRACE( "got hwnd %x msg %x (%s) wp %x lp %lx\n",
msg->msg.hwnd, msg->msg.message, SPY_GetMsgName(msg->msg.message),
msg->msg.wParam, msg->msg.lParam );
queue->GetMessageExtraInfoVal = msg->extraInfo;
/* call the right version of CallWindowProcXX */
switch(msg->type)
{
case QMSG_WIN16:
result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
(HWND16) msg->msg.hwnd,
(UINT16) msg->msg.message,
LOWORD(msg->msg.wParam),
msg->msg.lParam );
break;
case QMSG_WIN32A:
result = CallWindowProcA( wndPtr->winproc, msg->msg.hwnd, msg->msg.message,
msg->msg.wParam, msg->msg.lParam );
break;
case QMSG_WIN32W:
result = CallWindowProcW( wndPtr->winproc, msg->msg.hwnd, msg->msg.message,
msg->msg.wParam, msg->msg.lParam );
break;
}
queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */
WIN_ReleaseWndPtr(wndPtr);
QUEUE_Unlock( queue );
SERVER_START_REQ( reply_message )
{
req->result = result;
req->remove = 1;
SERVER_CALL();
}
SERVER_END_REQ;
}
/***********************************************************************
* process_sent_messages
*
* Process all pending sent messages
*/
static void process_sent_messages(void)
{
QMSG msg;
unsigned int res;
for (;;)
{
SERVER_START_REQ( get_message )
{
req->flags = GET_MSG_REMOVE | GET_MSG_SENT_ONLY;
req->get_win = 0;
req->get_first = 0;
req->get_last = ~0;
if (!(res = SERVER_CALL()))
{
msg.type = req->type;
msg.msg.hwnd = req->win;
msg.msg.message = req->msg;
msg.msg.wParam = req->wparam;
msg.msg.lParam = req->lparam;
msg.msg.time = req->time;
msg.msg.pt.x = req->x;
msg.msg.pt.y = req->y;
msg.extraInfo = req->info;
}
}
SERVER_END_REQ;
if (res) break;
handle_sent_message( &msg );
}
}
/***********************************************************************
* QUEUE_WaitBits
*
* See "Windows Internals", p.447
*
* return values:
* 0 if exit with timeout
* 1 otherwise
*/
int QUEUE_WaitBits( WORD bits, DWORD timeout )
{
MESSAGEQUEUE *queue;
HQUEUE16 hQueue;
TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits);
hQueue = GetFastQueue16();
if (!(queue = QUEUE_Lock( hQueue ))) return 0;
for (;;)
{
unsigned int wake_bits = 0, changed_bits = 0;
DWORD dwlc;
SERVER_START_REQ( set_queue_mask )
{
req->wake_mask = QS_SENDMESSAGE;
req->changed_mask = bits | QS_SENDMESSAGE;
req->skip_wait = 1;
if (!SERVER_CALL())
{
wake_bits = req->wake_bits;
changed_bits = req->changed_bits;
}
}
SERVER_END_REQ;
if (changed_bits & bits)
{
/* One of the bits is set; we can return */
QUEUE_Unlock( queue );
return 1;
}
if (wake_bits & QS_SENDMESSAGE)
{
/* Process the sent message immediately */
process_sent_messages();
continue; /* nested sm crux */
}
TRACE_(msg)("(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n",
queue->self, bits, wake_bits, changed_bits );
ReleaseThunkLock( &dwlc );
if (dwlc) TRACE_(msg)("had win16 lock\n");
if (USER_Driver.pMsgWaitForMultipleObjectsEx)
USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, timeout, 0, 0 );
else
WaitForSingleObject( queue->server_queue, timeout );
if (dwlc) RestoreThunkLock( dwlc );
}
}
/***********************************************************************
* QUEUE_FindMsg
*
* Find a message matching the given parameters. Return FALSE if none available.
*/
BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove, QMSG *msg )
{
BOOL ret = FALSE;
if (!first && !last) last = ~0;
for (;;)
{
SERVER_START_REQ( get_message )
{
req->flags = remove ? GET_MSG_REMOVE : 0;
req->get_win = hwnd;
req->get_first = first;
req->get_last = last;
if ((ret = !SERVER_CALL()))
{
msg->kind = req->kind;
msg->type = req->type;
msg->msg.hwnd = req->win;
msg->msg.message = req->msg;
msg->msg.wParam = req->wparam;
msg->msg.lParam = req->lparam;
msg->msg.time = req->time;
msg->msg.pt.x = req->x;
msg->msg.pt.y = req->y;
msg->extraInfo = req->info;
}
}
SERVER_END_REQ;
if (!ret || (msg->kind != SEND_MESSAGE)) break;
handle_sent_message( msg );
}
if (ret) TRACE( "got hwnd %x msg %x (%s) wp %x lp %lx\n",
msg->msg.hwnd, msg->msg.message, SPY_GetMsgName(msg->msg.message),
msg->msg.wParam, msg->msg.lParam );
return ret;
}
/***********************************************************************
* QUEUE_CleanupWindow
*
* Cleanup the queue to account for a window being deleted.
......@@ -836,66 +632,6 @@ BOOL WINAPI GetInputState(void)
}
/***********************************************************************
* WaitForInputIdle (USER32.@)
*/
DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
{
DWORD cur_time, ret;
HANDLE idle_event = -1;
SERVER_START_REQ( wait_input_idle )
{
req->handle = hProcess;
req->timeout = dwTimeOut;
if (!(ret = SERVER_CALL_ERR())) idle_event = req->event;
}
SERVER_END_REQ;
if (ret) return 0xffffffff; /* error */
if (!idle_event) return 0; /* no event to wait on */
cur_time = GetTickCount();
TRACE_(msg)("waiting for %x\n", idle_event );
while ( dwTimeOut > GetTickCount() - cur_time || dwTimeOut == INFINITE )
{
ret = MsgWaitForMultipleObjects ( 1, &idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE );
if ( ret == ( WAIT_OBJECT_0 + 1 ))
{
process_sent_messages();
continue;
}
if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF )
{
TRACE_(msg)("timeout or error\n");
return ret;
}
else
{
TRACE_(msg)("finished\n");
return 0;
}
}
return WAIT_TIMEOUT;
}
/***********************************************************************
* UserYield (USER.332)
* UserYield16 (USER32.@)
*/
void WINAPI UserYield16(void)
{
/* Handle sent messages */
process_sent_messages();
/* Yield */
OldYield16();
/* Handle sent messages again */
process_sent_messages();
}
/***********************************************************************
* GetMessagePos (USER.119) (USER32.@)
*
* The GetMessagePos() function returns a long value representing a
......
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