Moved the major part of message queue and window timer handling into

the server.
Implemented MsgWaitForMultipleObjectsEx.
This commit is contained in:
Alexandre Julliard 2001-05-18 22:51:56 +00:00
parent cd8d181a0b
commit 51ab43bd13
18 changed files with 1529 additions and 1276 deletions

View File

@ -414,7 +414,7 @@ debug_channels (accel caret class clipboard combo cursor dc ddeml dialog driver
@ stdcall ModifyMenuW(long long long long ptr) ModifyMenuW
@ stdcall MoveWindow(long long long long long long) MoveWindow
@ stdcall MsgWaitForMultipleObjects(long ptr long long long) MsgWaitForMultipleObjects
@ stub MsgWaitForMultipleObjectsEx
@ stdcall MsgWaitForMultipleObjectsEx(long ptr long long long) MsgWaitForMultipleObjectsEx
@ stdcall OemKeyScan(long) OemKeyScan
@ stdcall OemToCharA(ptr ptr) OemToCharA
@ stdcall OemToCharBuffA(ptr ptr long) OemToCharBuffA

View File

@ -88,7 +88,7 @@ static BOOL load_driver(void)
GET_USER_FUNC(DestroyWindow);
GET_USER_FUNC(GetDC);
GET_USER_FUNC(EnableWindow);
GET_USER_FUNC(MsgWaitForMultipleObjects);
GET_USER_FUNC(MsgWaitForMultipleObjectsEx);
GET_USER_FUNC(ScrollWindowEx);
GET_USER_FUNC(SetFocus);
GET_USER_FUNC(SetParent);

View File

@ -31,7 +31,7 @@ debug_channels (bitblt bitmap clipboard cursor dinput event font gdi graphics
@ cdecl DestroyWindow(long) X11DRV_DestroyWindow
@ cdecl GetDC(long long long long) X11DRV_GetDC
@ cdecl EnableWindow(long long) X11DRV_EnableWindow
@ cdecl MsgWaitForMultipleObjects(long ptr long long) X11DRV_MsgWaitForMultipleObjects
@ cdecl MsgWaitForMultipleObjectsEx(long ptr long long long) X11DRV_MsgWaitForMultipleObjectsEx
@ cdecl ScrollWindowEx(long long long ptr ptr long ptr long) X11DRV_ScrollWindowEx
@ cdecl SetFocus(long) X11DRV_SetFocus
@ cdecl SetParent(long long) X11DRV_SetParent

View File

@ -21,8 +21,6 @@ extern BOOL MSG_InternalGetMessage( struct tagMSG *msg, HWND hwnd, HWND hwndOwne
/* timer.c */
extern void TIMER_RemoveWindowTimers( HWND hwnd );
extern void TIMER_RemoveQueueTimers( HQUEUE16 hqueue );
extern BOOL TIMER_GetTimerMsg( struct tagMSG *msg, HWND hwnd,
HQUEUE16 hQueue, BOOL remove );
extern BOOL TIMER_IsTimerValid( HWND hwnd, UINT id, HWINDOWPROC hProc );
/* input.c */

View File

@ -31,43 +31,6 @@ typedef struct tagQMSG
#define QMSG_HARDWARE 3
typedef struct tagSMSG
{
struct tagSMSG *nextProcessing; /* next SMSG in the processing list */
struct tagSMSG *nextPending; /* next SMSG in the pending list */
struct tagSMSG *nextWaiting; /* next SMSG in the waiting list */
HQUEUE16 hSrcQueue; /* sending Queue, (NULL if it didn't wait) */
HQUEUE16 hDstQueue; /* destination Queue */
HWND hWnd; /* destination window */
UINT msg; /* message sent */
WPARAM wParam; /* wParam of the sent message */
LPARAM lParam; /* lParam of the sent message */
LRESULT lResult; /* result of SendMessage */
WORD flags; /* see below SMSG_XXXX */
} SMSG;
/* SMSG -> flags values */
/* set when lResult contains a good value */
#define SMSG_HAVE_RESULT 0x0001
/* protection for multiple call to ReplyMessage16() */
#define SMSG_ALREADY_REPLIED 0x0002
/* use with EARLY_REPLY for forcing the receiver to clean SMSG */
#define SMSG_RECEIVER_CLEANS 0x0010
/* used with EARLY_REPLY to indicate to sender, receiver is done with SMSG */
#define SMSG_RECEIVED 0x0020
/* set in ReceiveMessage() to indicate it's not an early reply */
#define SMSG_SENDING_REPLY 0x0040
/* set when ReplyMessage16() is called by the application */
#define SMSG_EARLY_REPLY 0x0080
/* set when sender is Win32 thread */
#define SMSG_WIN32 0x1000
/* set when sender is a unicode thread */
#define SMSG_UNICODE 0x2000
/* Per-queue data for the message queue
* Note that we currently only store the current values for
* Active, Capture and Focus windows currently.
@ -87,7 +50,6 @@ typedef struct tagPERQUEUEDATA
/* Message queue */
typedef struct tagMESSAGEQUEUE
{
HQUEUE16 next; /* Next queue */
HQUEUE16 self; /* Handle to self (was: reserved) */
TEB* teb; /* Thread owning queue */
HANDLE server_queue; /* Handle to server-side queue */
@ -96,27 +58,17 @@ typedef struct tagMESSAGEQUEUE
DWORD magic; /* magic number should be QUEUE_MAGIC */
DWORD lockCount; /* reference counter */
WORD msgCount; /* Number of waiting messages */
QMSG* firstMsg; /* First message in linked list */
QMSG* lastMsg; /* Last message in linked list */
WORD wPostQMsg; /* PostQuitMessage flag */
WORD wExitCode; /* PostQuitMessage exit code */
WORD wPaintCount; /* Number of WM_PAINT needed */
WORD wTimerCount; /* Number of timers for this task */
WORD changeBits; /* Changed wake-up bits */
WORD wakeBits; /* Queue wake-up bits */
WORD wakeMask; /* Queue wake-up mask */
DWORD GetMessageTimeVal; /* Value for GetMessageTime */
DWORD GetMessagePosVal; /* Value for GetMessagePos */
DWORD GetMessageExtraInfoVal; /* Value for GetMessageExtraInfo */
SMSG* smWaiting; /* SendMessage waiting for reply */
SMSG* smProcessing; /* SendMessage currently being processed */
SMSG* smPending; /* SendMessage waiting to be received */
HANDLE16 hCurHook; /* Current hook */
HANDLE16 hooks[WH_NB_HOOKS]; /* Task hooks list */
@ -125,14 +77,6 @@ typedef struct tagMESSAGEQUEUE
} MESSAGEQUEUE;
/* Extra (undocumented) queue wake bits - see "Undoc. Windows" */
#define QS_SMRESULT 0x8000 /* Queue has a SendMessage() result */
/* Types of SMSG stack */
#define SM_PROCESSING_LIST 1 /* list of SM currently being processed */
#define SM_PENDING_LIST 2 /* list of SM wating to be received */
#define SM_WAITING_LIST 3 /* list of SM waiting for reply */
#define QUEUE_MAGIC 0xD46E80AF
/* Per queue data management methods */
@ -152,28 +96,22 @@ INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT );
extern MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue );
extern void QUEUE_Unlock( MESSAGEQUEUE *queue );
extern void QUEUE_DumpQueue( HQUEUE16 hQueue );
extern void QUEUE_WalkQueues(void);
extern BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue );
extern void QUEUE_SetExitingQueue( HQUEUE16 hQueue );
extern MESSAGEQUEUE *QUEUE_GetSysQueue(void);
extern void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit );
extern void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD set, WORD clear );
extern void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit );
extern WORD QUEUE_TestWakeBit( MESSAGEQUEUE *queue, WORD bit );
extern BOOL QUEUE_ReceiveMessage( MESSAGEQUEUE *queue );
extern int QUEUE_WaitBits( WORD bits, DWORD timeout );
extern void QUEUE_IncPaintCount( HQUEUE16 hQueue );
extern void QUEUE_DecPaintCount( HQUEUE16 hQueue );
extern void QUEUE_IncTimerCount( HQUEUE16 hQueue );
extern void QUEUE_DecTimerCount( HQUEUE16 hQueue );
extern BOOL QUEUE_CreateSysMsgQueue( int size );
extern BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue );
extern HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue );
extern BOOL QUEUE_AddMsg( HQUEUE16 hQueue, int type, MSG * msg, DWORD extraInfo );
extern QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd,
int first, int last );
extern BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove,
BOOL sent_only, QMSG *msg );
extern void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg );
extern SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg );
extern BOOL QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg );
extern void QUEUE_CleanupWindow( HWND hwnd );
extern void hardware_event( UINT message, WPARAM wParam, LPARAM lParam,
int xPos, int yPos, DWORD time, DWORD extraInfo );

View File

@ -1296,14 +1296,41 @@ struct get_msg_queue_request
OUT handle_t handle; /* handle to the queue */
};
/* Wake up a message queue */
struct wake_queue_request
/* Set the message queue wake bits */
struct set_queue_bits_request
{
REQUEST_HEADER; /* request header */
IN handle_t handle; /* handle to the queue */
IN unsigned int bits; /* wake bits */
IN unsigned int set; /* wake bits to set */
IN unsigned int clear; /* wake bits to clear */
IN unsigned int mask_cond; /* mask for conditional bit setting */
OUT unsigned int changed_mask; /* changed bits wake mask */
};
/* Set the current message queue wakeup mask */
struct set_queue_mask_request
{
REQUEST_HEADER; /* request header */
IN unsigned int wake_mask; /* wakeup bits mask */
IN unsigned int changed_mask; /* changed bits mask */
IN int skip_wait; /* will we skip waiting if signaled? */
OUT unsigned int wake_bits; /* current wake bits */
OUT unsigned int changed_bits; /* current changed bits */
};
/* Get the current message queue status */
struct get_queue_status_request
{
REQUEST_HEADER; /* request header */
IN int clear; /* should we clear the change bits? */
OUT unsigned int wake_bits; /* wake bits */
OUT unsigned int changed_bits; /* changed bits since last time */
};
/* Wait for a process to start waiting on input */
struct wait_input_idle_request
{
@ -1313,6 +1340,97 @@ struct wait_input_idle_request
OUT handle_t event; /* handle to idle event */
};
/* Send a message to a thread queue */
struct send_message_request
{
REQUEST_HEADER; /* request header */
IN int posted; /* posted instead of sent message? */
IN void* id; /* thread id */
IN int type; /* message type */
IN handle_t win; /* window handle */
IN unsigned int msg; /* message code */
IN unsigned int wparam; /* parameters */
IN unsigned int lparam; /* parameters */
IN unsigned int info; /* extra info */
};
/* Get a message from the current queue */
struct get_message_request
{
REQUEST_HEADER; /* request header */
IN int remove; /* remove it? */
IN int posted; /* check posted messages too? */
IN handle_t get_win; /* window handle to get */
IN unsigned int get_first; /* first message code to get */
IN unsigned int get_last; /* last message code to get */
OUT int sent; /* it is a sent message */
OUT int type; /* message type */
OUT handle_t win; /* window handle */
OUT unsigned int msg; /* message code */
OUT unsigned int wparam; /* parameters */
OUT unsigned int lparam; /* parameters */
OUT unsigned int info; /* extra info */
};
/* Reply to a sent message */
struct reply_message_request
{
REQUEST_HEADER; /* request header */
IN unsigned int result; /* message result */
IN int remove; /* should we remove the message? */
};
/* Retrieve the reply for the last message sent */
struct get_message_reply_request
{
REQUEST_HEADER; /* request header */
IN int cancel; /* cancel message if not ready? */
OUT unsigned int result; /* message result */
};
/* Check if we are processing a sent message */
struct in_send_message_request
{
REQUEST_HEADER; /* request header */
OUT int flags; /* ISMEX_* flags */
};
/* Cleanup a queue when a window is deleted */
struct cleanup_window_queue_request
{
REQUEST_HEADER; /* request header */
IN handle_t win; /* window handle */
};
/* Set a window timer */
struct set_win_timer_request
{
REQUEST_HEADER; /* request header */
IN handle_t win; /* window handle */
IN unsigned int msg; /* message to post */
IN unsigned int id; /* timer id */
IN unsigned int rate; /* timer rate in ms */
IN unsigned int lparam; /* message lparam (callback proc) */
};
/* Kill a window timer */
struct kill_win_timer_request
{
REQUEST_HEADER; /* request header */
IN handle_t win; /* window handle */
IN unsigned int msg; /* message to post */
IN unsigned int id; /* timer id */
};
struct create_serial_request
{
REQUEST_HEADER; /* request header */
@ -1473,8 +1591,18 @@ enum request
REQ_get_atom_name,
REQ_init_atom_table,
REQ_get_msg_queue,
REQ_wake_queue,
REQ_set_queue_bits,
REQ_set_queue_mask,
REQ_get_queue_status,
REQ_wait_input_idle,
REQ_send_message,
REQ_get_message,
REQ_reply_message,
REQ_get_message_reply,
REQ_in_send_message,
REQ_cleanup_window_queue,
REQ_set_win_timer,
REQ_kill_win_timer,
REQ_create_serial,
REQ_get_serial_info,
REQ_set_serial_info,
@ -1588,15 +1716,25 @@ union generic_request
struct get_atom_name_request get_atom_name;
struct init_atom_table_request init_atom_table;
struct get_msg_queue_request get_msg_queue;
struct wake_queue_request wake_queue;
struct set_queue_bits_request set_queue_bits;
struct set_queue_mask_request set_queue_mask;
struct get_queue_status_request get_queue_status;
struct wait_input_idle_request wait_input_idle;
struct send_message_request send_message;
struct get_message_request get_message;
struct reply_message_request reply_message;
struct get_message_reply_request get_message_reply;
struct in_send_message_request in_send_message;
struct cleanup_window_queue_request cleanup_window_queue;
struct set_win_timer_request set_win_timer;
struct kill_win_timer_request kill_win_timer;
struct create_serial_request create_serial;
struct get_serial_info_request get_serial_info;
struct set_serial_info_request set_serial_info;
struct create_async_request create_async;
};
#define SERVER_PROTOCOL_VERSION 44
#define SERVER_PROTOCOL_VERSION 45
/* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */

View File

@ -73,7 +73,7 @@ typedef struct tagUSER_DRIVER {
BOOL (*pDestroyWindow)(HWND);
BOOL (*pGetDC)(HWND,HDC,HRGN,DWORD);
BOOL (*pEnableWindow)(HWND,BOOL);
DWORD (*pMsgWaitForMultipleObjects)(DWORD,HANDLE*,BOOL,DWORD);
DWORD (*pMsgWaitForMultipleObjectsEx)(DWORD,const HANDLE*,DWORD,DWORD,DWORD);
INT (*pScrollWindowEx)(HWND,INT,INT,const RECT*,const RECT*,HRGN,LPRECT,UINT);
void (*pSetFocus)(HWND);
HWND (*pSetParent)(HWND,HWND);

View File

@ -902,6 +902,10 @@ typedef struct
#define WM_APP 0x8000
/* MsgWaitForMultipleObjectsEx flags */
#define MWMO_WAITALL 0x0001
#define MWMO_ALERTABLE 0x0002
#define MWMO_INPUTAVAILABLE 0x0004
#define DLGC_WANTARROWS 0x0001
#define DLGC_WANTTAB 0x0002
@ -3026,6 +3030,16 @@ typedef struct
#define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY)
#define QS_ALLINPUT (QS_ALLEVENTS | QS_SENDMESSAGE)
/* Extra (undocumented) queue wake bits - see "Undoc. Windows" */
#define QS_SMRESULT 0x8000
/* InSendMessageEx flags */
#define ISMEX_NOSEND 0x00000000
#define ISMEX_SEND 0x00000001
#define ISMEX_NOTIFY 0x00000002
#define ISMEX_CALLBACK 0x00000004
#define ISMEX_REPLIED 0x00000008
#define DDL_READWRITE 0x0000
#define DDL_READONLY 0x0001
#define DDL_HIDDEN 0x0002
@ -3184,10 +3198,11 @@ INT WINAPI MessageBoxExW(HWND,LPCWSTR,LPCWSTR,UINT,WORD);
HMONITOR WINAPI MonitorFromPoint(POINT,DWORD);
HMONITOR WINAPI MonitorFromRect(LPRECT,DWORD);
HMONITOR WINAPI MonitorFromWindow(HWND,DWORD);
DWORD WINAPI MsgWaitForMultipleObjects(DWORD,HANDLE*,BOOL,DWORD,DWORD);
BOOL WINAPI PaintDesktop(HDC);
BOOL WINAPI PostThreadMessageA(DWORD, UINT, WPARAM, LPARAM);
BOOL WINAPI PostThreadMessageW(DWORD, UINT, WPARAM, LPARAM);
DWORD WINAPI MsgWaitForMultipleObjects(DWORD,CONST HANDLE*,BOOL,DWORD,DWORD);
DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD,CONST HANDLE*,DWORD,DWORD,DWORD);
BOOL WINAPI PaintDesktop(HDC);
BOOL WINAPI PostThreadMessageA(DWORD,UINT,WPARAM,LPARAM);
BOOL WINAPI PostThreadMessageW(DWORD,UINT,WPARAM,LPARAM);
#define PostThreadMessage WINELIB_NAME_AW(PostThreadMessage)
BOOL WINAPI RegisterHotKey(HWND,INT,UINT,UINT);
HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE,LPVOID,DWORD);
@ -3229,7 +3244,6 @@ LONG WINAPI GetMessageTime(void);
DWORD WINAPI OemKeyScan(WORD);
BOOL WINAPI ReleaseCapture(void);
BOOL WINAPI SetKeyboardState(LPBYTE);
VOID WINAPI WaitMessage(void);
/* Declarations for functions that change between Win16 and Win32 */
@ -3589,12 +3603,13 @@ BOOL WINAPI GrayStringA(HDC,HBRUSH,GRAYSTRINGPROC,LPARAM,
BOOL WINAPI GrayStringW(HDC,HBRUSH,GRAYSTRINGPROC,LPARAM,
INT,INT,INT,INT,INT);
#define GrayString WINELIB_NAME_AW(GrayString)
BOOL WINAPI HideCaret(HWND);
BOOL WINAPI HiliteMenuItem(HWND,HMENU,UINT,UINT);
BOOL WINAPI InflateRect(LPRECT,INT,INT);
BOOL WINAPI InSendMessage(void);
BOOL WINAPI InsertMenuA(HMENU,UINT,UINT,UINT,LPCSTR);
BOOL WINAPI InsertMenuW(HMENU,UINT,UINT,UINT,LPCWSTR);
BOOL WINAPI HideCaret(HWND);
BOOL WINAPI HiliteMenuItem(HWND,HMENU,UINT,UINT);
BOOL WINAPI InflateRect(LPRECT,INT,INT);
BOOL WINAPI InSendMessage(void);
DWORD WINAPI InSendMessageEx(LPVOID);
BOOL WINAPI InsertMenuA(HMENU,UINT,UINT,UINT,LPCSTR);
BOOL WINAPI InsertMenuW(HMENU,UINT,UINT,UINT,LPCWSTR);
#define InsertMenu WINELIB_NAME_AW(InsertMenu)
BOOL WINAPI InsertMenuItemA(HMENU,UINT,BOOL,const MENUITEMINFOA*);
BOOL WINAPI InsertMenuItemW(HMENU,UINT,BOOL,const MENUITEMINFOW*);
@ -3837,6 +3852,7 @@ WORD WINAPI VkKeyScanW(WCHAR);
WORD WINAPI VkKeyScanExA(CHAR, HKL);
WORD WINAPI VkKeyScanExW(WCHAR, HKL);
#define VkKeyScanEx WINELIB_NAME_AW(VkKeyScanEx)
BOOL WINAPI WaitMessage(void);
HWND WINAPI WindowFromDC(HDC);
HWND WINAPI WindowFromPoint(POINT);
BOOL WINAPI WinHelpA(HWND,LPCSTR,UINT,DWORD);

View File

@ -8,16 +8,72 @@
#include <stdio.h>
#include <stdlib.h>
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "handle.h"
#include "thread.h"
#include "process.h"
#include "request.h"
struct message_result
{
struct message_result *send_next; /* next in sender list */
struct message_result *recv_next; /* next in receiver list */
struct msg_queue *sender; /* sender queue */
struct msg_queue *receiver; /* receiver queue */
int replied; /* has it been replied to? */
unsigned int result; /* reply result */
unsigned int error; /* error code to pass back to sender */
};
struct message
{
struct message *next; /* next message in list */
struct message *prev; /* prev message in list */
int type; /* message type (FIXME) */
handle_t win; /* window handle */
unsigned int msg; /* message code */
unsigned int wparam; /* parameters */
unsigned int lparam; /* parameters */
unsigned int info; /* extra info */
struct message_result *result; /* result in sender queue */
};
struct message_list
{
struct message *first; /* head of list */
struct message *last; /* tail of list */
};
struct timer
{
struct timer *next; /* next timer in list */
struct timer *prev; /* prev timer in list */
struct timeval when; /* next expiration */
unsigned int rate; /* timer rate in ms */
handle_t win; /* window handle */
unsigned int msg; /* message to post */
unsigned int id; /* timer id */
unsigned int lparam; /* lparam for message */
};
struct msg_queue
{
struct object obj; /* object header */
struct thread *thread; /* thread owning this queue */
int signaled; /* queue has been signaled */
struct object obj; /* object header */
unsigned int wake_bits; /* wakeup bits */
unsigned int wake_mask; /* wakeup mask */
unsigned int changed_bits; /* changed wakeup bits */
unsigned int changed_mask; /* changed wakeup mask */
struct message_list send_list; /* list of sent messages */
struct message_list post_list; /* list of posted 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 timer *first_timer; /* head of timer list */
struct timer *last_timer; /* tail of timer list */
struct timer *next_timer; /* next timer to expire */
struct timeout_user *timeout; /* timeout for next timer to expire */
};
static void msg_queue_dump( struct object *obj, int verbose );
@ -25,6 +81,8 @@ static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *ent
static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
static int msg_queue_signaled( struct object *obj, struct thread *thread );
static int msg_queue_satisfied( struct object *obj, struct thread *thread );
static void msg_queue_destroy( struct object *obj );
static void timer_callback( void *private );
static const struct object_ops msg_queue_ops =
{
@ -39,7 +97,7 @@ static const struct object_ops msg_queue_ops =
no_get_fd, /* get_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
no_destroy /* destroy */
msg_queue_destroy /* destroy */
};
@ -49,8 +107,20 @@ static struct msg_queue *create_msg_queue( struct thread *thread )
if ((queue = alloc_object( &msg_queue_ops, -1 )))
{
queue->signaled = 0;
queue->thread = thread;
queue->wake_bits = 0;
queue->wake_mask = 0;
queue->changed_bits = 0;
queue->changed_mask = 0;
queue->send_list.first = NULL;
queue->send_list.last = NULL;
queue->post_list.first = NULL;
queue->post_list.last = NULL;
queue->send_result = NULL;
queue->recv_result = NULL;
queue->first_timer = NULL;
queue->last_timer = NULL;
queue->next_timer = NULL;
queue->timeout = NULL;
thread->queue = queue;
if (!thread->process->queue)
thread->process->queue = (struct msg_queue *)grab_object( queue );
@ -58,13 +128,211 @@ static struct msg_queue *create_msg_queue( struct thread *thread )
return queue;
}
/* check the queue status */
inline static int is_signaled( struct msg_queue *queue )
{
return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask));
}
/* set/clear some queue bits */
inline static void change_queue_bits( struct msg_queue *queue, unsigned int set, unsigned int clear )
{
queue->wake_bits = (queue->wake_bits | set) & ~clear;
queue->changed_bits = (queue->changed_bits | set) & ~clear;
if (is_signaled( queue )) wake_up( &queue->obj, 0 );
}
/* get the current thread queue, creating it if needed */
inline struct msg_queue *get_current_queue(void)
{
struct msg_queue *queue = current->queue;
if (!queue) queue = create_msg_queue( current );
return queue;
}
/* append a message to the end of a list */
inline static void append_message( struct message_list *list, struct message *msg )
{
msg->next = NULL;
if ((msg->prev = list->last)) msg->prev->next = msg;
else list->first = msg;
list->last = msg;
}
/* unlink a message from a list it */
inline static void unlink_message( struct message_list *list, struct message *msg )
{
if (msg->next) msg->next->prev = msg->prev;
else list->last = msg->prev;
if (msg->prev) msg->prev->next = msg->next;
else list->first = msg->next;
}
/* free a message when deleting a queue or window */
static void free_message( struct message *msg )
{
struct message_result *result = msg->result;
if (result)
{
if (result->sender)
{
result->result = 0;
result->error = STATUS_ACCESS_DENIED; /* FIXME */
result->replied = 1;
result->receiver = NULL;
/* wake sender queue if waiting on this result */
if (result->sender->send_result == result)
change_queue_bits( result->sender, QS_SMRESULT, 0 );
}
else free( result );
}
free( msg );
}
/* remove (and free) a message from the sent messages list */
static void remove_sent_message( struct msg_queue *queue, struct message *msg )
{
unlink_message( &queue->send_list, msg );
free_message( msg );
if (!queue->send_list.first) change_queue_bits( queue, 0, QS_SENDMESSAGE );
}
/* remove (and free) a message from the posted messages list */
static void remove_posted_message( struct msg_queue *queue, struct message *msg )
{
unlink_message( &queue->post_list, msg );
free_message( msg );
if (!queue->post_list.first) change_queue_bits( queue, 0, QS_POSTMESSAGE );
}
/* send a message from the sender queue to the receiver queue */
static int send_message( struct msg_queue *send_queue, struct msg_queue *recv_queue,
struct message *msg )
{
struct message_result *result = mem_alloc( sizeof(*result) );
if (!result) return 0;
/* put the result on the sender result stack */
result->sender = send_queue;
result->receiver = recv_queue;
result->replied = 0;
result->send_next = send_queue->send_result;
send_queue->send_result = result;
/* and put the message on the receiver queue */
msg->result = result;
append_message( &recv_queue->send_list, msg );
change_queue_bits( recv_queue, QS_SENDMESSAGE, 0 );
return 1;
}
/* receive a message, removing it from the sent queue */
static void receive_message( struct msg_queue *queue, struct message *msg )
{
struct message_result *result = msg->result;
unlink_message( &queue->send_list, msg );
/* put the result on the receiver result stack */
result->recv_next = queue->recv_result;
queue->recv_result = result;
free( msg );
if (!queue->send_list.first) change_queue_bits( queue, 0, QS_SENDMESSAGE );
}
/* set the result of the current received message */
static void reply_message( struct msg_queue *queue, unsigned int result,
unsigned int error, int remove )
{
struct message_result *res = queue->recv_result;
if (!res) set_error( STATUS_ACCESS_DENIED ); /* FIXME */
if (remove)
{
queue->recv_result = res->recv_next;
res->receiver = NULL;
if (!res->sender) /* no one waiting for it */
{
free( res );
return;
}
}
if (!res->replied)
{
res->result = result;
res->error = error;
res->replied = 1;
/* wake sender queue if waiting on this result */
if (res->sender && res->sender->send_result == res)
change_queue_bits( res->sender, QS_SMRESULT, 0 );
}
}
/* retrieve the reply of the current message being sent */
static unsigned int get_message_reply( struct msg_queue *queue, int cancel )
{
struct message_result *res = queue->send_result;
unsigned int ret = 0;
set_error( STATUS_PENDING );
if (res && (res->replied || cancel))
{
if (res->replied)
{
ret = res->result;
set_error( res->error );
}
queue->send_result = res->send_next;
res->sender = NULL;
if (!res->receiver) free( res );
if (!queue->send_result || !queue->send_result->replied)
change_queue_bits( queue, 0, QS_SMRESULT );
}
return ret;
}
/* empty a message list and free all the messages */
static void empty_msg_list( struct message_list *list )
{
struct message *msg = list->first;
while (msg)
{
struct message *next = msg->next;
free_message( msg );
msg = next;
}
}
/* cleanup all pending results when deleting a queue */
static void cleanup_results( struct msg_queue *queue )
{
struct message_result *result, *next;
result = queue->send_result;
while (result)
{
next = result->send_next;
result->sender = NULL;
if (!result->receiver) free( result );
result = next;
}
while (queue->recv_result) reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1 );
}
static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
{
struct msg_queue *queue = (struct msg_queue *)obj;
struct process *process = entry->thread->process;
/* a thread can only wait on its own queue */
if (entry->thread->queue != queue)
{
set_error( STATUS_ACCESS_DENIED );
return 0;
}
/* if waiting on the main process queue, set the idle event */
if (entry->thread == queue->thread && process->queue == queue)
if (process->queue == queue)
{
if (process->idle_event) set_event( process->idle_event );
}
@ -79,8 +347,10 @@ static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *
remove_queue( obj, entry );
assert( entry->thread->queue == queue );
/* if waiting on the main process queue, reset the idle event */
if (entry->thread == queue->thread && process->queue == queue)
if (process->queue == queue)
{
if (process->idle_event) reset_event( process->idle_event );
}
@ -89,41 +359,438 @@ static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *
static void msg_queue_dump( struct object *obj, int verbose )
{
struct msg_queue *queue = (struct msg_queue *)obj;
fprintf( stderr, "Msg queue signaled=%d owner=%p\n", queue->signaled, queue->thread );
fprintf( stderr, "Msg queue bits=%x mask=%x\n",
queue->wake_bits, queue->wake_mask );
}
static int msg_queue_signaled( struct object *obj, struct thread *thread )
{
struct msg_queue *queue = (struct msg_queue *)obj;
return queue->signaled;
return is_signaled( queue );
}
static int msg_queue_satisfied( struct object *obj, struct thread *thread )
{
struct msg_queue *queue = (struct msg_queue *)obj;
queue->signaled = 0;
queue->wake_mask = 0;
queue->changed_mask = 0;
return 0; /* Not abandoned */
}
static void msg_queue_destroy( struct object *obj )
{
struct msg_queue *queue = (struct msg_queue *)obj;
struct timer *timer = queue->first_timer;
cleanup_results( queue );
empty_msg_list( &queue->send_list );
empty_msg_list( &queue->post_list );
while (timer)
{
struct timer *next = timer->next;
free( timer );
timer = next;
}
if (queue->timeout) remove_timeout_user( queue->timeout );
}
/* set the next timer to expire */
static void set_next_timer( struct msg_queue *queue, struct timer *timer )
{
if (queue->timeout)
{
remove_timeout_user( queue->timeout );
queue->timeout = NULL;
}
if ((queue->next_timer = timer))
queue->timeout = add_timeout_user( &timer->when, timer_callback, queue );
/* set/clear QS_TIMER bit */
if (queue->next_timer == queue->first_timer)
change_queue_bits( queue, 0, QS_TIMER );
else
change_queue_bits( queue, QS_TIMER, 0 );
}
/* callback for the next timer expiration */
static void timer_callback( void *private )
{
struct msg_queue *queue = private;
queue->timeout = NULL;
/* move on to the next timer */
set_next_timer( queue, queue->next_timer->next );
}
/* link a timer at its rightful place in the queue list */
static void link_timer( struct msg_queue *queue, struct timer *timer )
{
struct timer *pos = queue->next_timer;
while (pos && time_before( &pos->when, &timer->when )) pos = pos->next;
if (pos) /* insert before pos */
{
if ((timer->prev = pos->prev)) timer->prev->next = timer;
else queue->first_timer = timer;
timer->next = pos;
pos->prev = timer;
}
else /* insert at end */
{
timer->next = NULL;
timer->prev = queue->last_timer;
if (queue->last_timer) queue->last_timer->next = timer;
else queue->first_timer = timer;
queue->last_timer = timer;
}
/* check if we replaced the next timer */
if (pos == queue->next_timer) set_next_timer( queue, timer );
}
/* remove a timer from the queue timer list */
static void unlink_timer( struct msg_queue *queue, struct timer *timer )
{
if (timer->next) timer->next->prev = timer->prev;
else queue->last_timer = timer->prev;
if (timer->prev) timer->prev->next = timer->next;
else queue->first_timer = timer->next;
/* check if we removed the next timer */
if (queue->next_timer == timer) set_next_timer( queue, timer->next );
}
/* restart an expired timer */
static void restart_timer( struct msg_queue *queue, struct timer *timer )
{
struct timeval now;
unlink_timer( queue, timer );
gettimeofday( &now, 0 );
while (!time_before( &now, &timer->when )) add_timeout( &timer->when, timer->rate );
link_timer( queue, timer );
}
/* find an expired timer matching the filtering parameters */
static struct timer *find_expired_timer( struct msg_queue *queue, handle_t win,
unsigned int get_first, unsigned int get_last,
int remove )
{
struct timer *timer;
for (timer = queue->first_timer; (timer && timer != queue->next_timer); timer = timer->next)
{
if (win && timer->win != win) continue;
if (timer->msg >= get_first && timer->msg <= get_last)
{
if (remove) restart_timer( queue, timer );
return timer;
}
}
return NULL;
}
/* kill a timer */
static int kill_timer( struct msg_queue *queue, handle_t win, unsigned int msg, unsigned int id )
{
struct timer *timer;
for (timer = queue->first_timer; timer; timer = timer->next)
{
if (timer->win != win || timer->msg != msg || timer->id != id) continue;
unlink_timer( queue, timer );
free( timer );
return 1;
}
return 0;
}
/* add a timer */
static struct timer *set_timer( struct msg_queue *queue, unsigned int rate )
{
struct timer *timer = mem_alloc( sizeof(*timer) );
if (timer)
{
timer->rate = rate;
gettimeofday( &timer->when, 0 );
add_timeout( &timer->when, rate );
link_timer( queue, timer );
}
return timer;
}
/* remove all messages and timers belonging to a certain window */
static void cleanup_window( struct msg_queue *queue, handle_t win )
{
struct timer *timer;
struct message *msg;
/* remove timers */
timer = queue->first_timer;
while (timer)
{
struct timer *next = timer->next;
if (timer->win == win)
{
unlink_timer( queue, timer );
free( timer );
}
timer = next;
}
/* remove sent messages */
msg = queue->send_list.first;
while (msg)
{
struct message *next = msg->next;
if (msg->win == win) remove_sent_message( queue, msg );
msg = next;
}
/* remove posted messages */
msg = queue->post_list.first;
while (msg)
{
struct message *next = msg->next;
if (msg->win == win) remove_posted_message( queue, msg );
msg = next;
}
}
/* get the message queue of the current thread */
DECL_HANDLER(get_msg_queue)
{
struct msg_queue *queue = current->queue;
struct msg_queue *queue = get_current_queue();
req->handle = 0;
if (!queue) queue = create_msg_queue( current );
if (queue) req->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 );
}
/* wake up a message queue */
DECL_HANDLER(wake_queue)
/* set the message queue wake bits */
DECL_HANDLER(set_queue_bits)
{
struct msg_queue *queue = (struct msg_queue *)get_handle_obj( current->process, req->handle,
0, &msg_queue_ops );
if (queue)
{
queue->signaled = 1;
wake_up( &queue->obj, 0 );
req->changed_mask = queue->changed_mask;
if (!req->mask_cond || (queue->changed_mask & req->mask_cond))
change_queue_bits( queue, req->set, req->clear );
release_object( queue );
}
}
/* set the current message queue wakeup mask */
DECL_HANDLER(set_queue_mask)
{
struct msg_queue *queue = get_current_queue();
if (queue)
{
queue->wake_mask = req->wake_mask;
queue->changed_mask = req->changed_mask;
req->wake_bits = queue->wake_bits;
req->changed_bits = queue->changed_bits;
if (is_signaled( queue ))
{
/* if skip wait is set, do what would have been done in the subsequent wait */
if (req->skip_wait) msg_queue_satisfied( &queue->obj, current );
else wake_up( &queue->obj, 0 );
}
}
}
/* get the current message queue status */
DECL_HANDLER(get_queue_status)
{
struct msg_queue *queue = current->queue;
if (queue)
{
req->wake_bits = queue->wake_bits;
req->changed_bits = queue->changed_bits;
if (req->clear) queue->changed_bits = 0;
}
else req->wake_bits = req->changed_bits = 0;
}
/* send a message to a thread queue */
DECL_HANDLER(send_message)
{
struct message *msg;
struct msg_queue *send_queue = get_current_queue();
struct msg_queue *recv_queue;
struct thread *thread = get_thread_from_id( req->id );
if (!thread) return;
if (!(recv_queue = thread->queue))
{
set_error( STATUS_INVALID_PARAMETER );
release_object( thread );
return;
}
if ((msg = mem_alloc( sizeof(*msg) )))
{
msg->type = req->type;
msg->win = req->win;
msg->msg = req->msg;
msg->wparam = req->wparam;
msg->lparam = req->lparam;
msg->info = req->info;
msg->result = NULL;
if (!req->posted) send_message( send_queue, recv_queue, msg );
else
{
append_message( &recv_queue->post_list, msg );
change_queue_bits( recv_queue, QS_POSTMESSAGE, 0 );
}
}
release_object( thread );
}
/* get a message from the current queue */
DECL_HANDLER(get_message)
{
struct timer *timer;
struct message *msg;
struct msg_queue *queue = get_current_queue();
if (!queue) return;
/* first check for sent messages */
if ((msg = queue->send_list.first))
{
req->sent = 1;
req->type = msg->type;
req->win = msg->win;
req->msg = msg->msg;
req->wparam = msg->wparam;
req->lparam = msg->lparam;
req->info = msg->info;
receive_message( queue, msg );
return;
}
if (!req->posted) goto done; /* nothing else to check */
/* then try a posted message */
req->sent = 0;
for (msg = queue->post_list.first; msg; msg = msg->next)
{
/* check against the filters */
if (req->get_win && msg->win != req->get_win) continue;
if (req->msg >= req->get_first && req->msg <= req->get_last)
{
/* found one */
req->type = msg->type;
req->win = msg->win;
req->msg = msg->msg;
req->wparam = msg->wparam;
req->lparam = msg->lparam;
req->info = msg->info;
if (req->remove) remove_posted_message( queue, msg );
return;
}
}
/* now check for WM_PAINT */
if (queue->wake_bits & QS_PAINT)
{
req->type = 0;
req->win = 0;
req->msg = WM_PAINT;
req->wparam = 0;
req->lparam = 0;
req->info = 0;
return;
}
/* now check for timer */
if ((timer = find_expired_timer( queue, req->get_win, req->get_first,
req->get_last, req->remove )))
{
req->type = 0;
req->win = timer->win;
req->msg = timer->msg;
req->wparam = timer->id;
req->lparam = timer->lparam;
req->info = 0;
return;
}
done:
set_error( STATUS_PENDING ); /* FIXME */
}
/* reply to a sent message */
DECL_HANDLER(reply_message)
{
if (current->queue) reply_message( current->queue, req->result, 0, req->remove );
else set_error( STATUS_ACCESS_DENIED );
}
/* retrieve the reply for the last message sent */
DECL_HANDLER(get_message_reply)
{
if (current->queue) req->result = get_message_reply( current->queue, req->cancel );
else set_error( STATUS_ACCESS_DENIED );
}
/* check if we are processing a sent message */
DECL_HANDLER(in_send_message)
{
int flags = 0;
if (current->queue)
{
struct message_result *result = current->queue->recv_result;
if (result)
{
flags |= ISMEX_SEND; /* FIXME */
if (result->replied || !result->sender) flags |= ISMEX_REPLIED;
}
}
req->flags = flags;
}
/* cleanup a queue when a window is deleted */
DECL_HANDLER(cleanup_window_queue)
{
if (current->queue) cleanup_window( current->queue, req->win );
}
/* set a window timer */
DECL_HANDLER(set_win_timer)
{
struct timer *timer;
struct msg_queue *queue = get_current_queue();
if (!queue) return;
/* remove it if it existed already */
if (req->win) kill_timer( queue, req->win, req->msg, req->id );
if ((timer = set_timer( queue, req->rate )))
{
timer->win = req->win;
timer->msg = req->msg;
timer->id = req->id;
timer->lparam = req->lparam;
}
}
/* kill a window timer */
DECL_HANDLER(kill_win_timer)
{
struct msg_queue *queue = current->queue;
if (!queue || !kill_timer( queue, req->win, req->msg, req->id ))
set_error( STATUS_INVALID_PARAMETER );
}

View File

@ -170,8 +170,18 @@ DECL_HANDLER(find_atom);
DECL_HANDLER(get_atom_name);
DECL_HANDLER(init_atom_table);
DECL_HANDLER(get_msg_queue);
DECL_HANDLER(wake_queue);
DECL_HANDLER(set_queue_bits);
DECL_HANDLER(set_queue_mask);
DECL_HANDLER(get_queue_status);
DECL_HANDLER(wait_input_idle);
DECL_HANDLER(send_message);
DECL_HANDLER(get_message);
DECL_HANDLER(reply_message);
DECL_HANDLER(get_message_reply);
DECL_HANDLER(in_send_message);
DECL_HANDLER(cleanup_window_queue);
DECL_HANDLER(set_win_timer);
DECL_HANDLER(kill_win_timer);
DECL_HANDLER(create_serial);
DECL_HANDLER(get_serial_info);
DECL_HANDLER(set_serial_info);
@ -284,8 +294,18 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_get_atom_name,
(req_handler)req_init_atom_table,
(req_handler)req_get_msg_queue,
(req_handler)req_wake_queue,
(req_handler)req_set_queue_bits,
(req_handler)req_set_queue_mask,
(req_handler)req_get_queue_status,
(req_handler)req_wait_input_idle,
(req_handler)req_send_message,
(req_handler)req_get_message,
(req_handler)req_reply_message,
(req_handler)req_get_message_reply,
(req_handler)req_in_send_message,
(req_handler)req_cleanup_window_queue,
(req_handler)req_set_win_timer,
(req_handler)req_kill_win_timer,
(req_handler)req_create_serial,
(req_handler)req_get_serial_info,
(req_handler)req_set_serial_info,

View File

@ -169,6 +169,16 @@ static void cleanup_thread( struct thread *thread )
if (thread->reply_fd != -1) close( thread->reply_fd );
if (thread->wait_fd != -1) close( thread->wait_fd );
if (thread->request_fd) release_object( thread->request_fd );
if (thread->queue)
{
if (thread->process->queue == thread->queue)
{
release_object( thread->process->queue );
thread->process->queue = NULL;
}
release_object( thread->queue );
thread->queue = NULL;
}
for (i = 0; i < MAX_INFLIGHT_FDS; i++)
{
if (thread->inflight[i].client != -1)
@ -191,14 +201,13 @@ static void destroy_thread( struct object *obj )
assert( obj->ops == &thread_ops );
assert( !thread->debug_ctx ); /* cannot still be debugging something */
release_object( thread->process );
if (thread->next) thread->next->prev = thread->prev;
if (thread->prev) thread->prev->next = thread->next;
else first_thread = thread->next;
while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc );
if (thread->info) release_object( thread->info );
if (thread->queue) release_object( thread->queue );
cleanup_thread( thread );
release_object( thread->process );
}
/* dump a thread on stdout for debugging purposes */
@ -223,6 +232,7 @@ struct thread *get_thread_from_id( void *id )
struct thread *t = first_thread;
while (t && (t != id)) t = t->next;
if (t) grab_object( t );
else set_error( STATUS_INVALID_PARAMETER );
return t;
}

View File

@ -1414,10 +1414,41 @@ static void dump_get_msg_queue_reply( const struct get_msg_queue_request *req )
fprintf( stderr, " handle=%d", req->handle );
}
static void dump_wake_queue_request( const struct wake_queue_request *req )
static void dump_set_queue_bits_request( const struct set_queue_bits_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " bits=%08x", req->bits );
fprintf( stderr, " set=%08x,", req->set );
fprintf( stderr, " clear=%08x,", req->clear );
fprintf( stderr, " mask_cond=%08x", req->mask_cond );
}
static void dump_set_queue_bits_reply( const struct set_queue_bits_request *req )
{
fprintf( stderr, " changed_mask=%08x", req->changed_mask );
}
static void dump_set_queue_mask_request( const struct set_queue_mask_request *req )
{
fprintf( stderr, " wake_mask=%08x,", req->wake_mask );
fprintf( stderr, " changed_mask=%08x,", req->changed_mask );
fprintf( stderr, " skip_wait=%d", req->skip_wait );
}
static void dump_set_queue_mask_reply( const struct set_queue_mask_request *req )
{
fprintf( stderr, " wake_bits=%08x,", req->wake_bits );
fprintf( stderr, " changed_bits=%08x", req->changed_bits );
}
static void dump_get_queue_status_request( const struct get_queue_status_request *req )
{
fprintf( stderr, " clear=%d", req->clear );
}
static void dump_get_queue_status_reply( const struct get_queue_status_request *req )
{
fprintf( stderr, " wake_bits=%08x,", req->wake_bits );
fprintf( stderr, " changed_bits=%08x", req->changed_bits );
}
static void dump_wait_input_idle_request( const struct wait_input_idle_request *req )
@ -1431,6 +1462,84 @@ static void dump_wait_input_idle_reply( const struct wait_input_idle_request *re
fprintf( stderr, " event=%d", req->event );
}
static void dump_send_message_request( const struct send_message_request *req )
{
fprintf( stderr, " posted=%d,", req->posted );
fprintf( stderr, " id=%p,", req->id );
fprintf( stderr, " type=%d,", req->type );
fprintf( stderr, " win=%d,", req->win );
fprintf( stderr, " msg=%08x,", req->msg );
fprintf( stderr, " wparam=%08x,", req->wparam );
fprintf( stderr, " lparam=%08x,", req->lparam );
fprintf( stderr, " info=%08x", req->info );
}
static void dump_get_message_request( const struct get_message_request *req )
{
fprintf( stderr, " remove=%d,", req->remove );
fprintf( stderr, " posted=%d,", req->posted );
fprintf( stderr, " get_win=%d,", req->get_win );
fprintf( stderr, " get_first=%08x,", req->get_first );
fprintf( stderr, " get_last=%08x", req->get_last );
}
static void dump_get_message_reply( const struct get_message_request *req )
{
fprintf( stderr, " sent=%d,", req->sent );
fprintf( stderr, " type=%d,", req->type );
fprintf( stderr, " win=%d,", req->win );
fprintf( stderr, " msg=%08x,", req->msg );
fprintf( stderr, " wparam=%08x,", req->wparam );
fprintf( stderr, " lparam=%08x,", req->lparam );
fprintf( stderr, " info=%08x", req->info );
}
static void dump_reply_message_request( const struct reply_message_request *req )
{
fprintf( stderr, " result=%08x,", req->result );
fprintf( stderr, " remove=%d", req->remove );
}
static void dump_get_message_reply_request( const struct get_message_reply_request *req )
{
fprintf( stderr, " cancel=%d", req->cancel );
}
static void dump_get_message_reply_reply( const struct get_message_reply_request *req )
{
fprintf( stderr, " result=%08x", req->result );
}
static void dump_in_send_message_request( const struct in_send_message_request *req )
{
}
static void dump_in_send_message_reply( const struct in_send_message_request *req )
{
fprintf( stderr, " flags=%d", req->flags );
}
static void dump_cleanup_window_queue_request( const struct cleanup_window_queue_request *req )
{
fprintf( stderr, " win=%d", req->win );
}
static void dump_set_win_timer_request( const struct set_win_timer_request *req )
{
fprintf( stderr, " win=%d,", req->win );
fprintf( stderr, " msg=%08x,", req->msg );
fprintf( stderr, " id=%08x,", req->id );
fprintf( stderr, " rate=%08x,", req->rate );
fprintf( stderr, " lparam=%08x", req->lparam );
}
static void dump_kill_win_timer_request( const struct kill_win_timer_request *req )
{
fprintf( stderr, " win=%d,", req->win );
fprintf( stderr, " msg=%08x,", req->msg );
fprintf( stderr, " id=%08x", req->id );
}
static void dump_create_serial_request( const struct create_serial_request *req )
{
fprintf( stderr, " access=%08x,", req->access );
@ -1589,8 +1698,18 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_get_atom_name_request,
(dump_func)dump_init_atom_table_request,
(dump_func)dump_get_msg_queue_request,
(dump_func)dump_wake_queue_request,
(dump_func)dump_set_queue_bits_request,
(dump_func)dump_set_queue_mask_request,
(dump_func)dump_get_queue_status_request,
(dump_func)dump_wait_input_idle_request,
(dump_func)dump_send_message_request,
(dump_func)dump_get_message_request,
(dump_func)dump_reply_message_request,
(dump_func)dump_get_message_reply_request,
(dump_func)dump_in_send_message_request,
(dump_func)dump_cleanup_window_queue_request,
(dump_func)dump_set_win_timer_request,
(dump_func)dump_kill_win_timer_request,
(dump_func)dump_create_serial_request,
(dump_func)dump_get_serial_info_request,
(dump_func)dump_set_serial_info_request,
@ -1700,8 +1819,18 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_get_atom_name_reply,
(dump_func)0,
(dump_func)dump_get_msg_queue_reply,
(dump_func)0,
(dump_func)dump_set_queue_bits_reply,
(dump_func)dump_set_queue_mask_reply,
(dump_func)dump_get_queue_status_reply,
(dump_func)dump_wait_input_idle_reply,
(dump_func)0,
(dump_func)dump_get_message_reply,
(dump_func)0,
(dump_func)dump_get_message_reply_reply,
(dump_func)dump_in_send_message_reply,
(dump_func)0,
(dump_func)0,
(dump_func)0,
(dump_func)dump_create_serial_reply,
(dump_func)dump_get_serial_info_reply,
(dump_func)0,
@ -1811,8 +1940,18 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"get_atom_name",
"init_atom_table",
"get_msg_queue",
"wake_queue",
"set_queue_bits",
"set_queue_mask",
"get_queue_status",
"wait_input_idle",
"send_message",
"get_message",
"reply_message",
"get_message_reply",
"in_send_message",
"cleanup_window_queue",
"set_win_timer",
"kill_win_timer",
"create_serial",
"get_serial_info",
"set_serial_info",

View File

@ -131,6 +131,7 @@ BOOL CLIPBOARD_IsLocked()
* by another client. However the handler must have access to the
* clipboard in order to update data in response to this message.
*/
#if 0
MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
if ( queue
@ -141,6 +142,10 @@ BOOL CLIPBOARD_IsLocked()
bIsLocked = FALSE;
QUEUE_Unlock( queue );
#else
/* FIXME: queue check no longer possible */
bIsLocked = FALSE;
#endif
}
return bIsLocked;

View File

@ -13,6 +13,7 @@
#include "wine/winbase16.h"
#include "message.h"
#include "winerror.h"
#include "server.h"
#include "win.h"
#include "heap.h"
#include "hook.h"
@ -24,6 +25,7 @@
#include "winproc.h"
#include "user.h"
#include "thread.h"
#include "task.h"
#include "options.h"
#include "controls.h"
#include "struct32.h"
@ -115,9 +117,9 @@ static DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD first, DWORD last,
POINT16 pt;
HANDLE16 hQ = GetFastQueue16();
MESSAGEQUEUE *queue = QUEUE_Lock(hQ);
BOOL mouseClick = ((message == WM_LBUTTONDOWN) ||
(message == WM_RBUTTONDOWN) ||
(message == WM_MBUTTONDOWN))?1:0;
int mouseClick = ((message == WM_LBUTTONDOWN) ||
(message == WM_RBUTTONDOWN) ||
(message == WM_MBUTTONDOWN));
DWORD retvalue;
/* Find the window to dispatch this mouse message to */
@ -155,7 +157,7 @@ static DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD first, DWORD last,
/* Wake up the other task */
QUEUE_Unlock( queue );
queue = QUEUE_Lock( pWnd->hmemTaskQ );
if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE, 0 );
QUEUE_Unlock( queue );
retvalue = SYSQ_MSG_ABANDON;
@ -387,7 +389,7 @@ static DWORD MSG_TranslateKbdMsg( HWND hTopWnd, DWORD first, DWORD last,
/* Wake up the other task */
queue = QUEUE_Lock( pWnd->hmemTaskQ );
if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
if (queue) QUEUE_SetWakeBit( queue, QS_KEY, 0 );
QUEUE_Unlock( queue );
WIN_ReleaseWndPtr(pWnd);
return SYSQ_MSG_ABANDON;
@ -771,127 +773,59 @@ UINT WINAPI GetDoubleClickTime(void)
static LRESULT MSG_SendMessageInterThread( HQUEUE16 hDestQueue,
HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam,
DWORD timeout, WORD flags,
DWORD timeout, WORD type,
LRESULT *pRes)
{
MESSAGEQUEUE *queue, *destQ;
SMSG *smsg;
LRESULT retVal = 1;
int iWndsLocks;
if (pRes) *pRes = 0;
MESSAGEQUEUE *destQ;
BOOL ret;
int iWndsLocks;
LRESULT result = 0;
if (IsTaskLocked16() || !IsWindow(hwnd))
return 0;
TRACE( "hwnd %x msg %x (%s) wp %x lp %lx\n", hwnd, msg, SPY_GetMsgName(msg), wParam, lParam );
/* create a SMSG structure to hold SendMessage() parameters */
if (! (smsg = (SMSG *) HeapAlloc( GetProcessHeap(), 0, sizeof(SMSG) )) )
return 0;
if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0;
if (!(destQ = QUEUE_Lock( hDestQueue ))) return 0;
if (!(destQ = QUEUE_Lock( hDestQueue )))
SERVER_START_REQ( send_message )
{
QUEUE_Unlock( queue );
return 0;
req->posted = FALSE;
req->id = destQ->teb->tid;
req->type = type;
req->win = hwnd;
req->msg = msg;
req->wparam = wParam;
req->lparam = lParam;
req->info = 0;
ret = !SERVER_CALL_ERR();
}
TRACE_(sendmsg)("SM: %s [%04x] (%04x -> %04x)\n",
SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
/* fill up SMSG structure */
smsg->hWnd = hwnd;
smsg->msg = msg;
smsg->wParam = wParam;
smsg->lParam = lParam;
smsg->lResult = 0;
smsg->hSrcQueue = pRes ? GetFastQueue16() : 0;
smsg->hDstQueue = hDestQueue;
smsg->flags = flags;
if (pRes) {
/* add smsg struct in the processing SM list of the source queue */
QUEUE_AddSMSG(queue, SM_PROCESSING_LIST, smsg);
} else {
/* this is a notification message, we don't need a reply */
smsg->flags |= SMSG_ALREADY_REPLIED | SMSG_RECEIVER_CLEANS;
}
/* add smsg struct in the pending list of the destination queue */
if (QUEUE_AddSMSG(destQ, SM_PENDING_LIST, smsg) == FALSE)
{
retVal = 0;
goto CLEANUP;
}
if (!pRes) goto CLEANUP; /* don't need a reply */
SERVER_END_REQ;
QUEUE_Unlock( destQ );
if (!ret) return 0;
iWndsLocks = WIN_SuspendWndsLock();
/* wait for the result */
while ( TRUE )
QUEUE_WaitBits( QS_SMRESULT, timeout );
SERVER_START_REQ( get_message_reply )
{
/*
* The sequence is crucial to avoid deadlock situations:
* - first, we clear the QS_SMRESULT bit
* - then, we check the SMSG_HAVE_RESULT bit
* - only if this isn't set, we enter the wait state.
*
* As the receiver first sets the SMSG_HAVE_RESULT and then wakes us,
* we are guaranteed that -should we now clear the QS_SMRESULT that
* was signalled already by the receiver- we will not start waiting.
*/
if ( smsg->flags & SMSG_HAVE_RESULT )
{
got:
*pRes = smsg->lResult;
TRACE_(sendmsg)("smResult = %08x\n", (unsigned)*pRes );
break;
}
QUEUE_ClearWakeBit( queue, QS_SMRESULT );
if ( smsg->flags & SMSG_HAVE_RESULT )
goto got;
if( QUEUE_WaitBits( QS_SMRESULT, timeout ) == 0 )
{
/* return with timeout */
SetLastError( 0 );
retVal = 0;
break;
}
req->cancel = 1;
if ((ret = !SERVER_CALL_ERR())) result = req->result;
}
SERVER_END_REQ;
TRACE( "hwnd %x msg %x (%s) wp %x lp %lx got reply %lx (err=%ld)\n",
hwnd, msg, SPY_GetMsgName(msg), wParam, lParam, result, GetLastError() );
if (!ret && (GetLastError() == ERROR_IO_PENDING))
{
if (timeout == INFINITE) ERR("no timeout but no result\n");
SetLastError(0); /* timeout */
}
if (pRes) *pRes = result;
WIN_RestoreWndsLock(iWndsLocks);
/* remove the smsg from the processing list of the source queue */
QUEUE_RemoveSMSG( queue, SM_PROCESSING_LIST, smsg );
/* Note: the destination thread is in charge of removing the smsg from
the pending list */
/* In the case of an early reply (or a timeout), sender thread will
released the smsg structure if the receiver thread is done
(SMSG_RECEIVED set). If the receiver thread isn't done,
SMSG_RECEIVER_CLEANS_UP flag is set, and it will be the receiver
responsibility to release smsg */
EnterCriticalSection( &queue->cSection );
if (smsg->flags & SMSG_RECEIVED)
HeapFree(GetProcessHeap(), 0, smsg);
else
smsg->flags |= SMSG_RECEIVER_CLEANS;
LeaveCriticalSection( &queue->cSection );
CLEANUP:
QUEUE_Unlock( queue );
QUEUE_Unlock( destQ );
TRACE_(sendmsg)("done!\n");
return retVal;
return ret;
}
@ -908,77 +842,14 @@ void WINAPI ReplyMessage16( LRESULT result )
*/
BOOL WINAPI ReplyMessage( LRESULT result )
{
MESSAGEQUEUE *senderQ = 0;
MESSAGEQUEUE *queue = 0;
SMSG *smsg;
BOOL ret = FALSE;
if (!(queue = QUEUE_Lock( GetFastQueue16() )))
return FALSE;
TRACE_(sendmsg)("ReplyMessage, queue %04x\n", queue->self);
if ( !(smsg = queue->smWaiting)
|| !( (senderQ = QUEUE_Lock( smsg->hSrcQueue ))
|| (smsg->flags & SMSG_ALREADY_REPLIED)) )
goto ReplyMessageEnd;
if ( !(smsg->flags & SMSG_ALREADY_REPLIED) )
BOOL ret;
SERVER_START_REQ( reply_message )
{
/* This is the first reply, so pass result to sender */
TRACE_(sendmsg)("\trpm: smResult = %08lx\n", (long) result );
EnterCriticalSection(&senderQ->cSection);
smsg->lResult = result;
smsg->flags |= SMSG_ALREADY_REPLIED;
/* check if it's an early reply (called by the application) or
a regular reply (called by ReceiveMessage) */
if ( !(smsg->flags & SMSG_SENDING_REPLY) )
smsg->flags |= SMSG_EARLY_REPLY;
smsg->flags |= SMSG_HAVE_RESULT;
LeaveCriticalSection(&senderQ->cSection);
/* tell the sending task that its reply is ready */
QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
ret = TRUE;
req->result = result;
req->remove = 0;
ret = !SERVER_CALL_ERR();
}
if (smsg->flags & SMSG_SENDING_REPLY)
{
/* remove msg from the waiting list, since this is the last
ReplyMessage */
QUEUE_RemoveSMSG( queue, SM_WAITING_LIST, smsg );
if (senderQ) EnterCriticalSection(&senderQ->cSection);
/* tell the sender we're all done with smsg structure */
smsg->flags |= SMSG_RECEIVED;
/* sender will set SMSG_RECEIVER_CLEANS_UP if it wants the
receiver to clean up smsg, it could only happen when there is
an early reply or a timeout */
if ( smsg->flags & SMSG_RECEIVER_CLEANS )
{
TRACE_(sendmsg)("Receiver cleans up!\n" );
HeapFree( GetProcessHeap(), 0, smsg );
}
if (senderQ) LeaveCriticalSection(&senderQ->cSection);
}
ReplyMessageEnd:
if ( senderQ )
QUEUE_Unlock( senderQ );
if ( queue )
QUEUE_Unlock( queue );
SERVER_END_REQ;
return ret;
}
@ -1116,9 +987,9 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd,
iWndsLocks = WIN_SuspendWndsLock();
while(1)
{
QMSG *qmsg;
{
WORD wakeBits = HIWORD(GetQueueStatus( mask ));
hQueue = GetFastQueue16();
msgQueue = QUEUE_Lock( hQueue );
if (!msgQueue)
@ -1127,10 +998,7 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd,
return FALSE;
}
EnterCriticalSection( &msgQueue->cSection );
msgQueue->changeBits = 0;
LeaveCriticalSection( &msgQueue->cSection );
#if 0
/* First handle a message put by SendMessage() */
while ( QUEUE_ReceiveMessage( msgQueue ) )
@ -1152,36 +1020,69 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd,
break;
}
LeaveCriticalSection( &msgQueue->cSection );
#endif
/* Now find a normal message */
retry:
if ((QUEUE_TestWakeBit(msgQueue, mask & QS_POSTMESSAGE)) &&
((qmsg = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != 0))
if (wakeBits & (QS_POSTMESSAGE|QS_TIMER|QS_PAINT))
{
/* Try to convert message to requested type */
MSG tmpMsg = qmsg->msg;
if ( !MSG_ConvertMsg( &tmpMsg, qmsg->type, type ) )
QMSG qmsg;
if (QUEUE_FindMsg( hwnd, first, last, flags & PM_REMOVE, FALSE, &qmsg ))
{
ERR( "Message %s of wrong type contains pointer parameters. Skipped!\n",
SPY_GetMsgName(tmpMsg.message));
QUEUE_RemoveMsg( msgQueue, qmsg );
goto retry;
/* Try to convert message to requested type */
MSG tmpMsg = qmsg.msg;
if ( !MSG_ConvertMsg( &tmpMsg, qmsg.type, type ) )
{
ERR( "Message %s of wrong type contains pointer parameters. Skipped!\n",
SPY_GetMsgName(tmpMsg.message));
/* remove it (FIXME) */
if (!(flags & PM_REMOVE)) QUEUE_FindMsg( hwnd, first, last, TRUE, FALSE, &qmsg );
goto retry;
}
msg = tmpMsg;
msgQueue->GetMessageTimeVal = msg.time;
msgQueue->GetMessagePosVal = MAKELONG( (INT16)msg.pt.x, (INT16)msg.pt.y );
msgQueue->GetMessageExtraInfoVal = qmsg.extraInfo;
/* need to fill the window handle for WM_PAINT message */
if (msg.message == WM_PAINT)
{
WND* wndPtr;
msg.hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
if ((wndPtr = WIN_FindWndPtr(msg.hwnd)))
{
if( wndPtr->dwStyle & WS_MINIMIZE &&
(HICON) GetClassLongA(wndPtr->hwndSelf, GCL_HICON) )
{
msg.message = WM_PAINTICON;
msg.wParam = 1;
}
if( !hwnd || msg.hwnd == hwnd || IsChild16(hwnd,msg.hwnd) )
{
if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
{
wndPtr->flags &= ~WIN_INTERNAL_PAINT;
QUEUE_DecPaintCount( hQueue );
}
WIN_ReleaseWndPtr(wndPtr);
break;
}
WIN_ReleaseWndPtr(wndPtr);
}
}
else break;
}
msg = tmpMsg;
msgQueue->GetMessageTimeVal = msg.time;
msgQueue->GetMessagePosVal = MAKELONG( (INT16)msg.pt.x, (INT16)msg.pt.y );
msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, qmsg );
break;
}
changeBits = MSG_JournalPlayBackMsg();
#if 0 /* FIXME */
EnterCriticalSection( &msgQueue->cSection );
msgQueue->changeBits |= changeBits;
LeaveCriticalSection( &msgQueue->cSection );
#endif
/* Now find a hardware event */
@ -1194,68 +1095,14 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd,
break;
}
/* Check again for SendMessage */
while ( QUEUE_ReceiveMessage( msgQueue ) )
;
/* Now find a WM_PAINT message */
if (QUEUE_TestWakeBit(msgQueue, mask & QS_PAINT))
{
WND* wndPtr;
msg.hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
msg.message = WM_PAINT;
msg.wParam = 0;
msg.lParam = 0;
if ((wndPtr = WIN_FindWndPtr(msg.hwnd)))
{
if( wndPtr->dwStyle & WS_MINIMIZE &&
(HICON) GetClassLongA(wndPtr->hwndSelf, GCL_HICON) )
{
msg.message = WM_PAINTICON;
msg.wParam = 1;
}
if( !hwnd || msg.hwnd == hwnd || IsChild16(hwnd,msg.hwnd) )
{
if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
{
wndPtr->flags &= ~WIN_INTERNAL_PAINT;
QUEUE_DecPaintCount( hQueue );
}
WIN_ReleaseWndPtr(wndPtr);
break;
}
WIN_ReleaseWndPtr(wndPtr);
}
}
/* Check for timer messages, but yield first */
#if 0 /* FIXME */
if (!(flags & PM_NOYIELD))
{
UserYield16();
while ( QUEUE_ReceiveMessage( msgQueue ) )
;
}
#endif
if (QUEUE_TestWakeBit(msgQueue, mask & QS_TIMER))
{
if (TIMER_GetTimerMsg(&msg, hwnd, hQueue, flags & PM_REMOVE)) break;
}
if (peek)
{
#if 0 /* FIXME */
if (!(flags & PM_NOYIELD)) UserYield16();
#endif
/* check for graphics events */
if (USER_Driver.pMsgWaitForMultipleObjects)
USER_Driver.pMsgWaitForMultipleObjects( 0, NULL, FALSE, 0 );
if (USER_Driver.pMsgWaitForMultipleObjectsEx)
USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
QUEUE_Unlock( msgQueue );
WIN_RestoreWndsLock(iWndsLocks);
@ -1556,23 +1403,38 @@ BOOL WINAPI GetMessageW(
/***********************************************************************
* MSG_PostToQueue
*/
static BOOL MSG_PostToQueue( HQUEUE16 hQueue, int type, HWND hwnd,
static BOOL MSG_PostToQueue( DWORD tid, int type, HWND hwnd,
UINT message, WPARAM wParam, LPARAM lParam )
{
MSG msg;
unsigned int res;
if ( !hQueue ) return FALSE;
TRACE( "posting %x %x (%s) %x %lx\n", hwnd, message, SPY_GetMsgName(message), wParam, lParam );
msg.hwnd = hwnd;
msg.message = message;
msg.wParam = wParam;
msg.lParam = lParam;
msg.time = GetTickCount();
GetCursorPos(&msg.pt);
SERVER_START_REQ( send_message )
{
req->posted = TRUE;
req->id = (void *)tid;
req->type = type;
req->win = hwnd;
req->msg = message;
req->wparam = wParam;
req->lparam = lParam;
req->info = 0;
res = SERVER_CALL();
}
SERVER_END_REQ;
return QUEUE_AddMsg( hQueue, type, &msg, 0 );
if (res)
{
if (res == STATUS_INVALID_PARAMETER)
SetLastError( ERROR_INVALID_THREAD_ID );
else
SetLastError( RtlNtStatusToDosError(res) );
}
return !res;
}
/***********************************************************************
* MSG_IsPointerMessage
*
@ -1652,7 +1514,6 @@ static BOOL MSG_IsPointerMessage(UINT message, WPARAM wParam, LPARAM lParam) {
static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam )
{
HQUEUE16 hQueue;
WND *wndPtr;
/* See thread on wine-devel around 6.2.2001. Basically posted messages
@ -1680,7 +1541,7 @@ static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message,
{
TRACE("BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
wndPtr->hwndSelf, message, wParam, lParam);
MSG_PostToQueue( wndPtr->hmemTaskQ, type,
MSG_PostToQueue( GetWindowThreadProcessId( wndPtr->hwndSelf, NULL ), type,
wndPtr->hwndSelf, message, wParam, lParam );
}
}
@ -1689,11 +1550,8 @@ static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message,
return TRUE;
}
wndPtr = WIN_FindWndPtr( hwnd );
hQueue = wndPtr? wndPtr->hmemTaskQ : 0;
WIN_ReleaseWndPtr(wndPtr);
return MSG_PostToQueue( hQueue, type, hwnd, message, wParam, lParam );
return MSG_PostToQueue( GetWindowThreadProcessId( hwnd, NULL ),
type, hwnd, message, wParam, lParam );
}
/***********************************************************************
@ -1730,8 +1588,9 @@ BOOL WINAPI PostMessageW( HWND hwnd, UINT message, WPARAM wParam,
BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message,
WPARAM16 wParam, LPARAM lParam )
{
return MSG_PostToQueue( GetTaskQueue16(hTask), QMSG_WIN16,
0, message, wParam, lParam );
TDB *pTask = TASK_GetPtr( hTask );
if (!pTask) return FALSE;
return MSG_PostToQueue( (DWORD)pTask->teb->tid, QMSG_WIN16, 0, message, wParam, lParam );
}
/**********************************************************************
@ -1740,8 +1599,7 @@ BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message,
BOOL WINAPI PostThreadMessageA( DWORD idThread, UINT message,
WPARAM wParam, LPARAM lParam )
{
return MSG_PostToQueue( GetThreadQueue16(idThread), QMSG_WIN32A,
0, message, wParam, lParam );
return MSG_PostToQueue( idThread, QMSG_WIN32A, 0, message, wParam, lParam );
}
/**********************************************************************
@ -1750,8 +1608,7 @@ BOOL WINAPI PostThreadMessageA( DWORD idThread, UINT message,
BOOL WINAPI PostThreadMessageW( DWORD idThread, UINT message,
WPARAM wParam, LPARAM lParam )
{
return MSG_PostToQueue( GetThreadQueue16(idThread), QMSG_WIN32W,
0, message, wParam, lParam );
return MSG_PostToQueue( idThread, QMSG_WIN32W, 0, message, wParam, lParam );
}
@ -1784,7 +1641,7 @@ static void MSG_CallWndProcHook( LPMSG pmsg, BOOL bUnicode )
* 1 otherwise
*/
static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam, DWORD timeout, WORD flags,
LPARAM lParam, DWORD timeout, WORD type,
LRESULT *pRes)
{
WND * wndPtr = 0;
@ -1814,7 +1671,7 @@ static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam,
TRACE("BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
MSG_SendMessage( wndPtr->hwndSelf, msg, wParam, lParam,
timeout, flags, pRes);
timeout, type, pRes);
}
}
WIN_ReleaseWndPtr(wndPtr);
@ -1825,29 +1682,35 @@ static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam,
if (HOOK_IsHooked( WH_CALLWNDPROC ))
{
if (flags & SMSG_UNICODE)
MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE);
else if (flags & SMSG_WIN32)
MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE);
else
switch(type)
{
LPCWPSTRUCT16 pmsg;
case QMSG_WIN16:
{
LPCWPSTRUCT16 pmsg;
if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
{
pmsg->hwnd = hwnd & 0xffff;
pmsg->message= msg & 0xffff;
pmsg->wParam = wParam & 0xffff;
pmsg->lParam = lParam;
HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
(LPARAM)SEGPTR_GET(pmsg) );
hwnd = pmsg->hwnd;
msg = pmsg->message;
wParam = pmsg->wParam;
lParam = pmsg->lParam;
SEGPTR_FREE( pmsg );
}
}
if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
{
pmsg->hwnd = hwnd & 0xffff;
pmsg->message= msg & 0xffff;
pmsg->wParam = wParam & 0xffff;
pmsg->lParam = lParam;
HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
(LPARAM)SEGPTR_GET(pmsg) );
hwnd = pmsg->hwnd;
msg = pmsg->message;
wParam = pmsg->wParam;
lParam = pmsg->lParam;
SEGPTR_FREE( pmsg );
}
}
break;
case QMSG_WIN32A:
MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE);
break;
case QMSG_WIN32W:
MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE);
break;
}
}
if (!(wndPtr = WIN_FindWndPtr( hwnd )))
@ -1860,33 +1723,35 @@ static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam,
ret = 0; /* Don't send anything if the task is dying */
goto END;
}
if (flags & SMSG_WIN32)
if (type != QMSG_WIN16)
SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam );
else
SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
if (wndPtr->hmemTaskQ && wndPtr->hmemTaskQ != GetFastQueue16())
ret = MSG_SendMessageInterThread( wndPtr->hmemTaskQ, hwnd, msg,
wParam, lParam, timeout, flags, pRes );
wParam, lParam, timeout, type, pRes );
else
{
LRESULT res;
LRESULT res = 0;
/* Call the right CallWindowProc flavor */
if (flags & SMSG_UNICODE)
res = CallWindowProcW( (WNDPROC)wndPtr->winproc,
hwnd, msg, wParam, lParam );
else if (flags & SMSG_WIN32)
res = CallWindowProcA( (WNDPROC)wndPtr->winproc,
hwnd, msg, wParam, lParam );
else
res = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
(HWND16) hwnd, (UINT16) msg,
(WPARAM16) wParam, lParam );
switch(type)
{
case QMSG_WIN16:
res = CallWindowProc16( (WNDPROC16)wndPtr->winproc, hwnd, msg, wParam, lParam );
break;
case QMSG_WIN32A:
res = CallWindowProcA( (WNDPROC)wndPtr->winproc, hwnd, msg, wParam, lParam );
break;
case QMSG_WIN32W:
res = CallWindowProcW( (WNDPROC)wndPtr->winproc, hwnd, msg, wParam, lParam );
break;
}
if (pRes) *pRes = res;
}
if (flags & SMSG_WIN32)
if (type != QMSG_WIN16)
SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, pRes?*pRes:0, wParam, lParam );
else
SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, pRes?*pRes:0, wParam, lParam );
@ -1903,7 +1768,7 @@ LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
LPARAM lParam)
{
LRESULT res;
MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, 0, &res);
MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN16, &res);
return res;
}
@ -1916,8 +1781,7 @@ LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wParam,
{
LRESULT res;
MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE,
SMSG_WIN32, &res);
MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32A, &res);
return res;
}
@ -1952,8 +1816,7 @@ LRESULT WINAPI SendMessageW(
) {
LRESULT res;
MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE,
SMSG_WIN32 | SMSG_UNICODE, &res);
MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32W, &res);
return res;
}
@ -1971,7 +1834,7 @@ LRESULT WINAPI SendMessageTimeout16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
/* FIXME: need support for SMTO_BLOCK */
ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, 0, &msgRet);
ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN16, &msgRet);
if (resultp) *resultp = (WORD) msgRet;
return ret;
}
@ -1989,8 +1852,7 @@ LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wParam,
/* FIXME: need support for SMTO_BLOCK */
ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, SMSG_WIN32,
&msgRet);
ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN32A, &msgRet);
if (resultp) *resultp = (DWORD) msgRet;
return ret;
@ -2009,8 +1871,7 @@ LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam,
/* FIXME: need support for SMTO_BLOCK */
ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout,
SMSG_WIN32 | SMSG_UNICODE, &msgRet);
ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN32W, &msgRet);
if (resultp) *resultp = (DWORD) msgRet;
return ret;
@ -2022,77 +1883,82 @@ LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam,
*
* WaitMessage() suspends a thread until events appear in the thread's
* queue.
*
* BUGS
*
* Is supposed to return BOOL under Win32.
*
* Thread-local message queues are not supported.
*
* CONFORMANCE
*
* ECMA-234, Win32
*
*/
void WINAPI WaitMessage( void )
BOOL WINAPI WaitMessage(void)
{
QUEUE_WaitBits( QS_ALLINPUT, INFINITE );
return (MsgWaitForMultipleObjectsEx( 0, NULL, INFINITE, QS_ALLINPUT, 0 ) != WAIT_FAILED);
}
/***********************************************************************
* MsgWaitForMultipleObjects (USER32.@)
* MsgWaitForMultipleObjectsEx (USER32.@)
*/
DWORD WINAPI MsgWaitForMultipleObjects( DWORD nCount, HANDLE *pHandles,
BOOL fWaitAll, DWORD dwMilliseconds,
DWORD dwWakeMask )
DWORD WINAPI MsgWaitForMultipleObjectsEx( DWORD count, CONST HANDLE *pHandles,
DWORD timeout, DWORD mask, DWORD flags )
{
DWORD i;
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
DWORD ret;
DWORD i, ret;
HQUEUE16 hQueue = GetFastQueue16();
MESSAGEQUEUE *msgQueue = QUEUE_Lock( hQueue );
if (!msgQueue) return WAIT_FAILED;
MESSAGEQUEUE *msgQueue;
if (nCount > MAXIMUM_WAIT_OBJECTS-1)
if (count > MAXIMUM_WAIT_OBJECTS-1)
{
SetLastError( ERROR_INVALID_PARAMETER );
QUEUE_Unlock( msgQueue );
return WAIT_FAILED;
}
EnterCriticalSection( &msgQueue->cSection );
msgQueue->changeBits = 0;
msgQueue->wakeMask = dwWakeMask;
LeaveCriticalSection( &msgQueue->cSection );
if (!(msgQueue = QUEUE_Lock( hQueue ))) return WAIT_FAILED;
/* set the queue mask */
SERVER_START_REQ( set_queue_mask )
{
req->wake_mask = (flags & MWMO_INPUTAVAILABLE) ? mask : 0;
req->changed_mask = mask;
req->skip_wait = 0;
SERVER_CALL();
}
SERVER_END_REQ;
/* Add the thread event to the handle list */
for (i = 0; i < nCount; i++) handles[i] = pHandles[i];
handles[nCount] = msgQueue->server_queue;
if (USER_Driver.pMsgWaitForMultipleObjects)
for (i = 0; i < count; i++) handles[i] = pHandles[i];
handles[count] = msgQueue->server_queue;
if (USER_Driver.pMsgWaitForMultipleObjectsEx)
{
ret = USER_Driver.pMsgWaitForMultipleObjects(nCount+1, handles, fWaitAll, dwMilliseconds);
if (ret == nCount+1) ret = nCount; /* pretend the msg queue is ready */
ret = USER_Driver.pMsgWaitForMultipleObjectsEx( count+1, handles, timeout, mask, flags );
if (ret == count+1) ret = count; /* pretend the msg queue is ready */
}
else
ret = WaitForMultipleObjects( nCount+1, handles, fWaitAll, dwMilliseconds );
ret = WaitForMultipleObjectsEx( count+1, handles, flags & MWMO_WAITALL,
timeout, flags & MWMO_ALERTABLE );
QUEUE_Unlock( msgQueue );
return ret;
}
/***********************************************************************
* MsgWaitForMultipleObjects (USER.640)
* MsgWaitForMultipleObjects (USER32.@)
*/
DWORD WINAPI MsgWaitForMultipleObjects16( DWORD nCount, HANDLE *pHandles,
BOOL fWaitAll, DWORD dwMilliseconds,
DWORD dwWakeMask )
DWORD WINAPI MsgWaitForMultipleObjects( DWORD count, CONST HANDLE *handles,
BOOL wait_all, DWORD timeout, DWORD mask )
{
TRACE("(%lu,%p,%u,%lu,0x%lx)\n",
nCount, pHandles, fWaitAll, dwMilliseconds, dwWakeMask);
return MsgWaitForMultipleObjects(nCount, pHandles, fWaitAll, dwMilliseconds, dwWakeMask);
return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask,
wait_all ? MWMO_WAITALL : 0 );
}
/***********************************************************************
* MsgWaitForMultipleObjects16 (USER.640)
*/
DWORD WINAPI MsgWaitForMultipleObjects16( DWORD count, CONST HANDLE *handles,
BOOL wait_all, DWORD timeout, DWORD mask )
{
return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask,
wait_all ? MWMO_WAITALL : 0 );
}
struct accent_char
{
BYTE ac_accent;
@ -2594,17 +2460,25 @@ BOOL16 WINAPI InSendMessage16(void)
*/
BOOL WINAPI InSendMessage(void)
{
MESSAGEQUEUE *queue;
BOOL ret;
return (InSendMessageEx(NULL) & (ISMEX_SEND|ISMEX_REPLIED)) == ISMEX_SEND;
}
if (!(queue = QUEUE_Lock( GetFastQueue16() )))
return 0;
ret = (BOOL)queue->smWaiting;
QUEUE_Unlock( queue );
/***********************************************************************
* InSendMessageEx (USER32.@)
*/
DWORD WINAPI InSendMessageEx( LPVOID reserved )
{
DWORD ret = 0;
SERVER_START_REQ( in_send_message )
{
if (!SERVER_CALL_ERR()) ret = req->flags;
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* BroadcastSystemMessage (USER32.@)
*/
@ -2623,8 +2497,7 @@ LONG WINAPI BroadcastSystemMessage(
*/
BOOL WINAPI SendNotifyMessageA(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE,
SMSG_WIN32, NULL);
return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32A, NULL);
}
/***********************************************************************
@ -2632,8 +2505,7 @@ BOOL WINAPI SendNotifyMessageA(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
*/
BOOL WINAPI SendNotifyMessageW(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE,
SMSG_WIN32 | SMSG_UNICODE, NULL);
return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32W, NULL);
}
/***********************************************************************

File diff suppressed because it is too large Load Diff

View File

@ -8,10 +8,12 @@
#include "wingdi.h"
#include "wine/winuser16.h"
#include "winuser.h"
#include "winerror.h"
#include "queue.h"
#include "winproc.h"
#include "services.h"
#include "message.h"
#include "server.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(timer);
@ -24,15 +26,13 @@ typedef struct tagTIMER
UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
UINT id;
UINT timeout;
HANDLE hService;
BOOL expired;
HWINDOWPROC proc;
} TIMER;
#define NB_TIMERS 34
#define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
#define SYS_TIMER_RATE 54925
#define SYS_TIMER_RATE 55 /* min. timer rate in ms (actually 54.925)*/
static TIMER TimersArray[NB_TIMERS];
@ -46,18 +46,6 @@ static CRITICAL_SECTION csTimer = CRITICAL_SECTION_INIT;
*/
static void TIMER_ClearTimer( TIMER * pTimer )
{
if ( pTimer->hService != INVALID_HANDLE_VALUE )
{
SERVICE_Delete( pTimer->hService );
pTimer->hService = INVALID_HANDLE_VALUE;
}
if ( pTimer->expired )
{
QUEUE_DecTimerCount( pTimer->hq );
pTimer->expired = FALSE;
}
pTimer->hwnd = 0;
pTimer->msg = 0;
pTimer->id = 0;
@ -81,7 +69,7 @@ void TIMER_RemoveWindowTimers( HWND hwnd )
for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
if ((pTimer->hwnd == hwnd) && pTimer->timeout)
TIMER_ClearTimer( pTimer );
LeaveCriticalSection( &csTimer );
}
@ -106,85 +94,6 @@ void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
}
/***********************************************************************
* TIMER_CheckTimer
*/
static void CALLBACK TIMER_CheckTimer( ULONG_PTR timer_ptr )
{
TIMER *pTimer = (TIMER *)timer_ptr;
HQUEUE16 wakeQueue = 0;
EnterCriticalSection( &csTimer );
/* Paranoid check to prevent a race condition ... */
if ( !pTimer->timeout )
{
LeaveCriticalSection( &csTimer );
return;
}
if ( !pTimer->expired )
{
TRACE("Timer expired: %04x, %04x, %04x, %08lx\n",
pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
pTimer->expired = TRUE;
wakeQueue = pTimer->hq;
}
LeaveCriticalSection( &csTimer );
/* Note: This has to be done outside the csTimer critical section,
otherwise we'll get deadlocks. */
if ( wakeQueue )
QUEUE_IncTimerCount( wakeQueue );
}
/***********************************************************************
* TIMER_GetTimerMsg
*
* Build a message for an expired timer.
*/
BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd,
HQUEUE16 hQueue, BOOL remove )
{
TIMER *pTimer;
int i;
EnterCriticalSection( &csTimer );
for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
if ( pTimer->timeout != 0 && pTimer->expired
&& (hwnd? (pTimer->hwnd == hwnd) : (pTimer->hq == hQueue)) )
break;
if ( i == NB_TIMERS )
{
LeaveCriticalSection( &csTimer );
return FALSE; /* No timer */
}
TRACE("Timer got message: %04x, %04x, %04x, %08lx\n",
pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
if (remove)
pTimer->expired = FALSE;
/* Build the message */
msg->hwnd = pTimer->hwnd;
msg->message = pTimer->msg;
msg->wParam = pTimer->id;
msg->lParam = (LONG)pTimer->proc;
msg->time = GetTickCount();
LeaveCriticalSection( &csTimer );
return TRUE;
}
/***********************************************************************
* TIMER_SetTimer
*/
@ -193,12 +102,20 @@ static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
{
int i;
TIMER * pTimer;
HWINDOWPROC winproc = 0;
if (GetWindowThreadProcessId( hwnd, NULL ) != GetCurrentThreadId())
{
SetLastError( ERROR_INVALID_WINDOW_HANDLE );
return 0;
}
if (!timeout)
{ /* timeout==0 is a legal argument UB 990821*/
WARN("Timeout== 0 not implemented, using timeout=1\n");
timeout=1;
}
EnterCriticalSection( &csTimer );
/* Check if there's already a timer with the same hwnd and id */
@ -228,21 +145,28 @@ static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
if (!hwnd) id = i + 1;
if (proc) WINPROC_SetProc( &winproc, proc, type, WIN_PROC_TIMER );
SERVER_START_REQ( set_win_timer )
{
req->win = hwnd;
req->msg = sys ? WM_SYSTIMER : WM_TIMER;
req->id = id;
req->rate = max( timeout, SYS_TIMER_RATE );
req->lparam = (unsigned int)winproc;
SERVER_CALL();
}
SERVER_END_REQ;
/* Add the timer */
pTimer->hwnd = hwnd;
pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) )
: GetFastQueue16( );
pTimer->hq = GetFastQueue16();
pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
pTimer->id = id;
pTimer->timeout = timeout;
pTimer->proc = (HWINDOWPROC)0;
if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
pTimer->proc = winproc;
pTimer->expired = FALSE;
pTimer->hService = SERVICE_AddTimer( max( timeout, (SYS_TIMER_RATE+500)/1000 ),
TIMER_CheckTimer, (ULONG_PTR)pTimer );
TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
(DWORD)pTimer->proc );
@ -262,6 +186,15 @@ static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
int i;
TIMER * pTimer;
SERVER_START_REQ( kill_win_timer )
{
req->win = hwnd;
req->msg = sys ? WM_SYSTIMER : WM_TIMER;
req->id = id;
SERVER_CALL();
}
SERVER_END_REQ;
EnterCriticalSection( &csTimer );
/* Find the timer */

View File

@ -458,29 +458,8 @@ static WND* WIN_DestroyWindow( WND* wndPtr )
/* toss stale messages from the queue */
if( wndPtr->hmemTaskQ )
{
BOOL bPostQuit = FALSE;
WPARAM wQuitParam = 0;
MESSAGEQUEUE* msgQ = (MESSAGEQUEUE*) QUEUE_Lock(wndPtr->hmemTaskQ);
QMSG *qmsg;
while( (qmsg = QUEUE_FindMsg(msgQ, hwnd, 0, 0)) != 0 )
{
if( qmsg->msg.message == WM_QUIT )
{
bPostQuit = TRUE;
wQuitParam = qmsg->msg.wParam;
}
QUEUE_RemoveMsg(msgQ, qmsg);
}
QUEUE_Unlock(msgQ);
/* repost WM_QUIT to make sure this app exits its message loop */
if( bPostQuit ) PostQuitMessage(wQuitParam);
wndPtr->hmemTaskQ = 0;
}
QUEUE_CleanupWindow( hwnd );
wndPtr->hmemTaskQ = 0;
if (!(wndPtr->dwStyle & WS_CHILD))
if (wndPtr->wIDmenu)

View File

@ -167,17 +167,18 @@ void X11DRV_Synchronize( void )
/***********************************************************************
* MsgWaitForMultipleObjects (X11DRV.@)
* MsgWaitForMultipleObjectsEx (X11DRV.@)
*/
DWORD X11DRV_MsgWaitForMultipleObjects( DWORD count, HANDLE *handles,
BOOL wait_all, DWORD timeout )
DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
DWORD timeout, DWORD mask, DWORD flags )
{
HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
DWORD i, ret;
struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
if (!data || data->process_event_count)
return WaitForMultipleObjects( count, handles, wait_all, timeout );
return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
timeout, flags & MWMO_ALERTABLE );
for (i = 0; i < count; i++) new_handles[i] = handles[i];
new_handles[count] = data->display_fd;
@ -187,7 +188,8 @@ DWORD X11DRV_MsgWaitForMultipleObjects( DWORD count, HANDLE *handles,
XFlush( gdi_display );
XFlush( data->display );
wine_tsx11_unlock();
ret = WaitForMultipleObjects( count+1, new_handles, wait_all, timeout );
ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
timeout, flags & MWMO_ALERTABLE );
if (ret == count) process_events( data->display );
data->process_event_count--;
return ret;