Commit 51ab43bd authored by Alexandre Julliard's avatar Alexandre Julliard

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

the server. Implemented MsgWaitForMultipleObjectsEx.
parent cd8d181a
...@@ -414,7 +414,7 @@ debug_channels (accel caret class clipboard combo cursor dc ddeml dialog driver ...@@ -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 ModifyMenuW(long long long long ptr) ModifyMenuW
@ stdcall MoveWindow(long long long long long long) MoveWindow @ stdcall MoveWindow(long long long long long long) MoveWindow
@ stdcall MsgWaitForMultipleObjects(long ptr long long long) MsgWaitForMultipleObjects @ stdcall MsgWaitForMultipleObjects(long ptr long long long) MsgWaitForMultipleObjects
@ stub MsgWaitForMultipleObjectsEx @ stdcall MsgWaitForMultipleObjectsEx(long ptr long long long) MsgWaitForMultipleObjectsEx
@ stdcall OemKeyScan(long) OemKeyScan @ stdcall OemKeyScan(long) OemKeyScan
@ stdcall OemToCharA(ptr ptr) OemToCharA @ stdcall OemToCharA(ptr ptr) OemToCharA
@ stdcall OemToCharBuffA(ptr ptr long) OemToCharBuffA @ stdcall OemToCharBuffA(ptr ptr long) OemToCharBuffA
......
...@@ -88,7 +88,7 @@ static BOOL load_driver(void) ...@@ -88,7 +88,7 @@ static BOOL load_driver(void)
GET_USER_FUNC(DestroyWindow); GET_USER_FUNC(DestroyWindow);
GET_USER_FUNC(GetDC); GET_USER_FUNC(GetDC);
GET_USER_FUNC(EnableWindow); GET_USER_FUNC(EnableWindow);
GET_USER_FUNC(MsgWaitForMultipleObjects); GET_USER_FUNC(MsgWaitForMultipleObjectsEx);
GET_USER_FUNC(ScrollWindowEx); GET_USER_FUNC(ScrollWindowEx);
GET_USER_FUNC(SetFocus); GET_USER_FUNC(SetFocus);
GET_USER_FUNC(SetParent); GET_USER_FUNC(SetParent);
......
...@@ -31,7 +31,7 @@ debug_channels (bitblt bitmap clipboard cursor dinput event font gdi graphics ...@@ -31,7 +31,7 @@ debug_channels (bitblt bitmap clipboard cursor dinput event font gdi graphics
@ cdecl DestroyWindow(long) X11DRV_DestroyWindow @ cdecl DestroyWindow(long) X11DRV_DestroyWindow
@ cdecl GetDC(long long long long) X11DRV_GetDC @ cdecl GetDC(long long long long) X11DRV_GetDC
@ cdecl EnableWindow(long long) X11DRV_EnableWindow @ 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 ScrollWindowEx(long long long ptr ptr long ptr long) X11DRV_ScrollWindowEx
@ cdecl SetFocus(long) X11DRV_SetFocus @ cdecl SetFocus(long) X11DRV_SetFocus
@ cdecl SetParent(long long) X11DRV_SetParent @ cdecl SetParent(long long) X11DRV_SetParent
......
...@@ -21,8 +21,6 @@ extern BOOL MSG_InternalGetMessage( struct tagMSG *msg, HWND hwnd, HWND hwndOwne ...@@ -21,8 +21,6 @@ extern BOOL MSG_InternalGetMessage( struct tagMSG *msg, HWND hwnd, HWND hwndOwne
/* timer.c */ /* timer.c */
extern void TIMER_RemoveWindowTimers( HWND hwnd ); extern void TIMER_RemoveWindowTimers( HWND hwnd );
extern void TIMER_RemoveQueueTimers( HQUEUE16 hqueue ); 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 ); extern BOOL TIMER_IsTimerValid( HWND hwnd, UINT id, HWINDOWPROC hProc );
/* input.c */ /* input.c */
......
...@@ -31,43 +31,6 @@ typedef struct tagQMSG ...@@ -31,43 +31,6 @@ typedef struct tagQMSG
#define QMSG_HARDWARE 3 #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 /* Per-queue data for the message queue
* Note that we currently only store the current values for * Note that we currently only store the current values for
* Active, Capture and Focus windows currently. * Active, Capture and Focus windows currently.
...@@ -87,7 +50,6 @@ typedef struct tagPERQUEUEDATA ...@@ -87,7 +50,6 @@ typedef struct tagPERQUEUEDATA
/* Message queue */ /* Message queue */
typedef struct tagMESSAGEQUEUE typedef struct tagMESSAGEQUEUE
{ {
HQUEUE16 next; /* Next queue */
HQUEUE16 self; /* Handle to self (was: reserved) */ HQUEUE16 self; /* Handle to self (was: reserved) */
TEB* teb; /* Thread owning queue */ TEB* teb; /* Thread owning queue */
HANDLE server_queue; /* Handle to server-side queue */ HANDLE server_queue; /* Handle to server-side queue */
...@@ -96,27 +58,17 @@ typedef struct tagMESSAGEQUEUE ...@@ -96,27 +58,17 @@ typedef struct tagMESSAGEQUEUE
DWORD magic; /* magic number should be QUEUE_MAGIC */ DWORD magic; /* magic number should be QUEUE_MAGIC */
DWORD lockCount; /* reference counter */ DWORD lockCount; /* reference counter */
WORD msgCount; /* Number of waiting messages */
QMSG* firstMsg; /* First message in linked list */ QMSG* firstMsg; /* First message in linked list */
QMSG* lastMsg; /* Last message in linked list */ QMSG* lastMsg; /* Last message in linked list */
WORD wPostQMsg; /* PostQuitMessage flag */ WORD wPostQMsg; /* PostQuitMessage flag */
WORD wExitCode; /* PostQuitMessage exit code */ WORD wExitCode; /* PostQuitMessage exit code */
WORD wPaintCount; /* Number of WM_PAINT needed */ 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 GetMessageTimeVal; /* Value for GetMessageTime */
DWORD GetMessagePosVal; /* Value for GetMessagePos */ DWORD GetMessagePosVal; /* Value for GetMessagePos */
DWORD GetMessageExtraInfoVal; /* Value for GetMessageExtraInfo */ 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 hCurHook; /* Current hook */
HANDLE16 hooks[WH_NB_HOOKS]; /* Task hooks list */ HANDLE16 hooks[WH_NB_HOOKS]; /* Task hooks list */
...@@ -125,14 +77,6 @@ typedef struct tagMESSAGEQUEUE ...@@ -125,14 +77,6 @@ typedef struct tagMESSAGEQUEUE
} MESSAGEQUEUE; } 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 #define QUEUE_MAGIC 0xD46E80AF
/* Per queue data management methods */ /* Per queue data management methods */
...@@ -152,28 +96,22 @@ INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT ); ...@@ -152,28 +96,22 @@ INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT );
extern MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue ); extern MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue );
extern void QUEUE_Unlock( MESSAGEQUEUE *queue ); extern void QUEUE_Unlock( MESSAGEQUEUE *queue );
extern void QUEUE_DumpQueue( HQUEUE16 hQueue ); extern void QUEUE_DumpQueue( HQUEUE16 hQueue );
extern void QUEUE_WalkQueues(void);
extern BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue ); extern BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue );
extern void QUEUE_SetExitingQueue( HQUEUE16 hQueue ); extern void QUEUE_SetExitingQueue( HQUEUE16 hQueue );
extern MESSAGEQUEUE *QUEUE_GetSysQueue(void); 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 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit );
extern WORD QUEUE_TestWakeBit( 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 int QUEUE_WaitBits( WORD bits, DWORD timeout );
extern void QUEUE_IncPaintCount( HQUEUE16 hQueue ); extern void QUEUE_IncPaintCount( HQUEUE16 hQueue );
extern void QUEUE_DecPaintCount( 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_CreateSysMsgQueue( int size );
extern BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue ); extern BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue );
extern HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue ); extern HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue );
extern BOOL QUEUE_AddMsg( HQUEUE16 hQueue, int type, MSG * msg, DWORD extraInfo ); extern BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove,
extern QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd, BOOL sent_only, QMSG *msg );
int first, int last );
extern void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg ); extern void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg );
extern SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg ); extern void QUEUE_CleanupWindow( HWND hwnd );
extern BOOL QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg );
extern void hardware_event( UINT message, WPARAM wParam, LPARAM lParam, extern void hardware_event( UINT message, WPARAM wParam, LPARAM lParam,
int xPos, int yPos, DWORD time, DWORD extraInfo ); int xPos, int yPos, DWORD time, DWORD extraInfo );
......
...@@ -1296,14 +1296,41 @@ struct get_msg_queue_request ...@@ -1296,14 +1296,41 @@ struct get_msg_queue_request
OUT handle_t handle; /* handle to the queue */ 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 */ REQUEST_HEADER; /* request header */
IN handle_t handle; /* handle to the queue */ 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 */ /* Wait for a process to start waiting on input */
struct wait_input_idle_request struct wait_input_idle_request
{ {
...@@ -1313,6 +1340,97 @@ struct wait_input_idle_request ...@@ -1313,6 +1340,97 @@ struct wait_input_idle_request
OUT handle_t event; /* handle to idle event */ 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 struct create_serial_request
{ {
REQUEST_HEADER; /* request header */ REQUEST_HEADER; /* request header */
...@@ -1473,8 +1591,18 @@ enum request ...@@ -1473,8 +1591,18 @@ enum request
REQ_get_atom_name, REQ_get_atom_name,
REQ_init_atom_table, REQ_init_atom_table,
REQ_get_msg_queue, REQ_get_msg_queue,
REQ_wake_queue, REQ_set_queue_bits,
REQ_set_queue_mask,
REQ_get_queue_status,
REQ_wait_input_idle, 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_create_serial,
REQ_get_serial_info, REQ_get_serial_info,
REQ_set_serial_info, REQ_set_serial_info,
...@@ -1588,15 +1716,25 @@ union generic_request ...@@ -1588,15 +1716,25 @@ union generic_request
struct get_atom_name_request get_atom_name; struct get_atom_name_request get_atom_name;
struct init_atom_table_request init_atom_table; struct init_atom_table_request init_atom_table;
struct get_msg_queue_request get_msg_queue; 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 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 create_serial_request create_serial;
struct get_serial_info_request get_serial_info; struct get_serial_info_request get_serial_info;
struct set_serial_info_request set_serial_info; struct set_serial_info_request set_serial_info;
struct create_async_request create_async; struct create_async_request create_async;
}; };
#define SERVER_PROTOCOL_VERSION 44 #define SERVER_PROTOCOL_VERSION 45
/* ### make_requests end ### */ /* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */ /* Everything above this line is generated automatically by tools/make_requests */
......
...@@ -73,7 +73,7 @@ typedef struct tagUSER_DRIVER { ...@@ -73,7 +73,7 @@ typedef struct tagUSER_DRIVER {
BOOL (*pDestroyWindow)(HWND); BOOL (*pDestroyWindow)(HWND);
BOOL (*pGetDC)(HWND,HDC,HRGN,DWORD); BOOL (*pGetDC)(HWND,HDC,HRGN,DWORD);
BOOL (*pEnableWindow)(HWND,BOOL); 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); INT (*pScrollWindowEx)(HWND,INT,INT,const RECT*,const RECT*,HRGN,LPRECT,UINT);
void (*pSetFocus)(HWND); void (*pSetFocus)(HWND);
HWND (*pSetParent)(HWND,HWND); HWND (*pSetParent)(HWND,HWND);
......
...@@ -902,6 +902,10 @@ typedef struct ...@@ -902,6 +902,10 @@ typedef struct
#define WM_APP 0x8000 #define WM_APP 0x8000
/* MsgWaitForMultipleObjectsEx flags */
#define MWMO_WAITALL 0x0001
#define MWMO_ALERTABLE 0x0002
#define MWMO_INPUTAVAILABLE 0x0004
#define DLGC_WANTARROWS 0x0001 #define DLGC_WANTARROWS 0x0001
#define DLGC_WANTTAB 0x0002 #define DLGC_WANTTAB 0x0002
...@@ -3026,6 +3030,16 @@ typedef struct ...@@ -3026,6 +3030,16 @@ typedef struct
#define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY) #define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY)
#define QS_ALLINPUT (QS_ALLEVENTS | QS_SENDMESSAGE) #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_READWRITE 0x0000
#define DDL_READONLY 0x0001 #define DDL_READONLY 0x0001
#define DDL_HIDDEN 0x0002 #define DDL_HIDDEN 0x0002
...@@ -3184,10 +3198,11 @@ INT WINAPI MessageBoxExW(HWND,LPCWSTR,LPCWSTR,UINT,WORD); ...@@ -3184,10 +3198,11 @@ INT WINAPI MessageBoxExW(HWND,LPCWSTR,LPCWSTR,UINT,WORD);
HMONITOR WINAPI MonitorFromPoint(POINT,DWORD); HMONITOR WINAPI MonitorFromPoint(POINT,DWORD);
HMONITOR WINAPI MonitorFromRect(LPRECT,DWORD); HMONITOR WINAPI MonitorFromRect(LPRECT,DWORD);
HMONITOR WINAPI MonitorFromWindow(HWND,DWORD); HMONITOR WINAPI MonitorFromWindow(HWND,DWORD);
DWORD WINAPI MsgWaitForMultipleObjects(DWORD,HANDLE*,BOOL,DWORD,DWORD); DWORD WINAPI MsgWaitForMultipleObjects(DWORD,CONST HANDLE*,BOOL,DWORD,DWORD);
BOOL WINAPI PaintDesktop(HDC); DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD,CONST HANDLE*,DWORD,DWORD,DWORD);
BOOL WINAPI PostThreadMessageA(DWORD, UINT, WPARAM, LPARAM); BOOL WINAPI PaintDesktop(HDC);
BOOL WINAPI PostThreadMessageW(DWORD, UINT, WPARAM, LPARAM); BOOL WINAPI PostThreadMessageA(DWORD,UINT,WPARAM,LPARAM);
BOOL WINAPI PostThreadMessageW(DWORD,UINT,WPARAM,LPARAM);
#define PostThreadMessage WINELIB_NAME_AW(PostThreadMessage) #define PostThreadMessage WINELIB_NAME_AW(PostThreadMessage)
BOOL WINAPI RegisterHotKey(HWND,INT,UINT,UINT); BOOL WINAPI RegisterHotKey(HWND,INT,UINT,UINT);
HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE,LPVOID,DWORD); HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE,LPVOID,DWORD);
...@@ -3229,7 +3244,6 @@ LONG WINAPI GetMessageTime(void); ...@@ -3229,7 +3244,6 @@ LONG WINAPI GetMessageTime(void);
DWORD WINAPI OemKeyScan(WORD); DWORD WINAPI OemKeyScan(WORD);
BOOL WINAPI ReleaseCapture(void); BOOL WINAPI ReleaseCapture(void);
BOOL WINAPI SetKeyboardState(LPBYTE); BOOL WINAPI SetKeyboardState(LPBYTE);
VOID WINAPI WaitMessage(void);
/* Declarations for functions that change between Win16 and Win32 */ /* Declarations for functions that change between Win16 and Win32 */
...@@ -3589,12 +3603,13 @@ BOOL WINAPI GrayStringA(HDC,HBRUSH,GRAYSTRINGPROC,LPARAM, ...@@ -3589,12 +3603,13 @@ BOOL WINAPI GrayStringA(HDC,HBRUSH,GRAYSTRINGPROC,LPARAM,
BOOL WINAPI GrayStringW(HDC,HBRUSH,GRAYSTRINGPROC,LPARAM, BOOL WINAPI GrayStringW(HDC,HBRUSH,GRAYSTRINGPROC,LPARAM,
INT,INT,INT,INT,INT); INT,INT,INT,INT,INT);
#define GrayString WINELIB_NAME_AW(GrayString) #define GrayString WINELIB_NAME_AW(GrayString)
BOOL WINAPI HideCaret(HWND); BOOL WINAPI HideCaret(HWND);
BOOL WINAPI HiliteMenuItem(HWND,HMENU,UINT,UINT); BOOL WINAPI HiliteMenuItem(HWND,HMENU,UINT,UINT);
BOOL WINAPI InflateRect(LPRECT,INT,INT); BOOL WINAPI InflateRect(LPRECT,INT,INT);
BOOL WINAPI InSendMessage(void); BOOL WINAPI InSendMessage(void);
BOOL WINAPI InsertMenuA(HMENU,UINT,UINT,UINT,LPCSTR); DWORD WINAPI InSendMessageEx(LPVOID);
BOOL WINAPI InsertMenuW(HMENU,UINT,UINT,UINT,LPCWSTR); BOOL WINAPI InsertMenuA(HMENU,UINT,UINT,UINT,LPCSTR);
BOOL WINAPI InsertMenuW(HMENU,UINT,UINT,UINT,LPCWSTR);
#define InsertMenu WINELIB_NAME_AW(InsertMenu) #define InsertMenu WINELIB_NAME_AW(InsertMenu)
BOOL WINAPI InsertMenuItemA(HMENU,UINT,BOOL,const MENUITEMINFOA*); BOOL WINAPI InsertMenuItemA(HMENU,UINT,BOOL,const MENUITEMINFOA*);
BOOL WINAPI InsertMenuItemW(HMENU,UINT,BOOL,const MENUITEMINFOW*); BOOL WINAPI InsertMenuItemW(HMENU,UINT,BOOL,const MENUITEMINFOW*);
...@@ -3837,6 +3852,7 @@ WORD WINAPI VkKeyScanW(WCHAR); ...@@ -3837,6 +3852,7 @@ WORD WINAPI VkKeyScanW(WCHAR);
WORD WINAPI VkKeyScanExA(CHAR, HKL); WORD WINAPI VkKeyScanExA(CHAR, HKL);
WORD WINAPI VkKeyScanExW(WCHAR, HKL); WORD WINAPI VkKeyScanExW(WCHAR, HKL);
#define VkKeyScanEx WINELIB_NAME_AW(VkKeyScanEx) #define VkKeyScanEx WINELIB_NAME_AW(VkKeyScanEx)
BOOL WINAPI WaitMessage(void);
HWND WINAPI WindowFromDC(HDC); HWND WINAPI WindowFromDC(HDC);
HWND WINAPI WindowFromPoint(POINT); HWND WINAPI WindowFromPoint(POINT);
BOOL WINAPI WinHelpA(HWND,LPCSTR,UINT,DWORD); BOOL WINAPI WinHelpA(HWND,LPCSTR,UINT,DWORD);
......
...@@ -8,16 +8,72 @@ ...@@ -8,16 +8,72 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "handle.h" #include "handle.h"
#include "thread.h" #include "thread.h"
#include "process.h" #include "process.h"
#include "request.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 msg_queue
{ {
struct object obj; /* object header */ struct object obj; /* object header */
struct thread *thread; /* thread owning this queue */ unsigned int wake_bits; /* wakeup bits */
int signaled; /* queue has been signaled */ 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 ); 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 ...@@ -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 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_signaled( struct object *obj, struct thread *thread );
static int msg_queue_satisfied( 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 = static const struct object_ops msg_queue_ops =
{ {
...@@ -39,7 +97,7 @@ 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_get_fd, /* get_fd */
no_flush, /* flush */ no_flush, /* flush */
no_get_file_info, /* get_file_info */ 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 ) ...@@ -49,8 +107,20 @@ static struct msg_queue *create_msg_queue( struct thread *thread )
if ((queue = alloc_object( &msg_queue_ops, -1 ))) if ((queue = alloc_object( &msg_queue_ops, -1 )))
{ {
queue->signaled = 0; queue->wake_bits = 0;
queue->thread = thread; 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; thread->queue = queue;
if (!thread->process->queue) if (!thread->process->queue)
thread->process->queue = (struct msg_queue *)grab_object( queue ); thread->process->queue = (struct msg_queue *)grab_object( queue );
...@@ -58,13 +128,211 @@ static struct msg_queue *create_msg_queue( struct thread *thread ) ...@@ -58,13 +128,211 @@ static struct msg_queue *create_msg_queue( struct thread *thread )
return queue; 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 ) static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
{ {
struct msg_queue *queue = (struct msg_queue *)obj; struct msg_queue *queue = (struct msg_queue *)obj;
struct process *process = entry->thread->process; 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 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 ); 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 * ...@@ -79,8 +347,10 @@ static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry *
remove_queue( obj, entry ); remove_queue( obj, entry );
assert( entry->thread->queue == queue );
/* if waiting on the main process queue, reset the idle event */ /* 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 ); 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 * ...@@ -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 ) static void msg_queue_dump( struct object *obj, int verbose )
{ {
struct msg_queue *queue = (struct msg_queue *)obj; 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 ) static int msg_queue_signaled( struct object *obj, struct thread *thread )
{ {
struct msg_queue *queue = (struct msg_queue *)obj; 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 ) static int msg_queue_satisfied( struct object *obj, struct thread *thread )
{ {
struct msg_queue *queue = (struct msg_queue *)obj; struct msg_queue *queue = (struct msg_queue *)obj;
queue->signaled = 0; queue->wake_mask = 0;
queue->changed_mask = 0;
return 0; /* Not abandoned */ 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 */ /* get the message queue of the current thread */
DECL_HANDLER(get_msg_queue) DECL_HANDLER(get_msg_queue)
{ {
struct msg_queue *queue = current->queue; struct msg_queue *queue = get_current_queue();
req->handle = 0; req->handle = 0;
if (!queue) queue = create_msg_queue( current );
if (queue) req->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 ); 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, struct msg_queue *queue = (struct msg_queue *)get_handle_obj( current->process, req->handle,
0, &msg_queue_ops ); 0, &msg_queue_ops );
if (queue) if (queue)
{ {
queue->signaled = 1; req->changed_mask = queue->changed_mask;
wake_up( &queue->obj, 0 ); if (!req->mask_cond || (queue->changed_mask & req->mask_cond))
change_queue_bits( queue, req->set, req->clear );
release_object( queue ); 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 );
}
...@@ -170,8 +170,18 @@ DECL_HANDLER(find_atom); ...@@ -170,8 +170,18 @@ DECL_HANDLER(find_atom);
DECL_HANDLER(get_atom_name); DECL_HANDLER(get_atom_name);
DECL_HANDLER(init_atom_table); DECL_HANDLER(init_atom_table);
DECL_HANDLER(get_msg_queue); 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(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(create_serial);
DECL_HANDLER(get_serial_info); DECL_HANDLER(get_serial_info);
DECL_HANDLER(set_serial_info); DECL_HANDLER(set_serial_info);
...@@ -284,8 +294,18 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = ...@@ -284,8 +294,18 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_get_atom_name, (req_handler)req_get_atom_name,
(req_handler)req_init_atom_table, (req_handler)req_init_atom_table,
(req_handler)req_get_msg_queue, (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_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_create_serial,
(req_handler)req_get_serial_info, (req_handler)req_get_serial_info,
(req_handler)req_set_serial_info, (req_handler)req_set_serial_info,
......
...@@ -169,6 +169,16 @@ static void cleanup_thread( struct thread *thread ) ...@@ -169,6 +169,16 @@ static void cleanup_thread( struct thread *thread )
if (thread->reply_fd != -1) close( thread->reply_fd ); if (thread->reply_fd != -1) close( thread->reply_fd );
if (thread->wait_fd != -1) close( thread->wait_fd ); if (thread->wait_fd != -1) close( thread->wait_fd );
if (thread->request_fd) release_object( thread->request_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++) for (i = 0; i < MAX_INFLIGHT_FDS; i++)
{ {
if (thread->inflight[i].client != -1) if (thread->inflight[i].client != -1)
...@@ -191,14 +201,13 @@ static void destroy_thread( struct object *obj ) ...@@ -191,14 +201,13 @@ static void destroy_thread( struct object *obj )
assert( obj->ops == &thread_ops ); assert( obj->ops == &thread_ops );
assert( !thread->debug_ctx ); /* cannot still be debugging something */ assert( !thread->debug_ctx ); /* cannot still be debugging something */
release_object( thread->process );
if (thread->next) thread->next->prev = thread->prev; if (thread->next) thread->next->prev = thread->prev;
if (thread->prev) thread->prev->next = thread->next; if (thread->prev) thread->prev->next = thread->next;
else first_thread = thread->next; else first_thread = thread->next;
while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc ); while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc );
if (thread->info) release_object( thread->info ); if (thread->info) release_object( thread->info );
if (thread->queue) release_object( thread->queue );
cleanup_thread( thread ); cleanup_thread( thread );
release_object( thread->process );
} }
/* dump a thread on stdout for debugging purposes */ /* dump a thread on stdout for debugging purposes */
...@@ -223,6 +232,7 @@ struct thread *get_thread_from_id( void *id ) ...@@ -223,6 +232,7 @@ struct thread *get_thread_from_id( void *id )
struct thread *t = first_thread; struct thread *t = first_thread;
while (t && (t != id)) t = t->next; while (t && (t != id)) t = t->next;
if (t) grab_object( t ); if (t) grab_object( t );
else set_error( STATUS_INVALID_PARAMETER );
return t; return t;
} }
......
...@@ -1414,10 +1414,41 @@ static void dump_get_msg_queue_reply( const struct get_msg_queue_request *req ) ...@@ -1414,10 +1414,41 @@ static void dump_get_msg_queue_reply( const struct get_msg_queue_request *req )
fprintf( stderr, " handle=%d", req->handle ); 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, " 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 ) 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 ...@@ -1431,6 +1462,84 @@ static void dump_wait_input_idle_reply( const struct wait_input_idle_request *re
fprintf( stderr, " event=%d", req->event ); 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 ) static void dump_create_serial_request( const struct create_serial_request *req )
{ {
fprintf( stderr, " access=%08x,", req->access ); fprintf( stderr, " access=%08x,", req->access );
...@@ -1589,8 +1698,18 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { ...@@ -1589,8 +1698,18 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_get_atom_name_request, (dump_func)dump_get_atom_name_request,
(dump_func)dump_init_atom_table_request, (dump_func)dump_init_atom_table_request,
(dump_func)dump_get_msg_queue_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_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_create_serial_request,
(dump_func)dump_get_serial_info_request, (dump_func)dump_get_serial_info_request,
(dump_func)dump_set_serial_info_request, (dump_func)dump_set_serial_info_request,
...@@ -1700,8 +1819,18 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { ...@@ -1700,8 +1819,18 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_get_atom_name_reply, (dump_func)dump_get_atom_name_reply,
(dump_func)0, (dump_func)0,
(dump_func)dump_get_msg_queue_reply, (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)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_create_serial_reply,
(dump_func)dump_get_serial_info_reply, (dump_func)dump_get_serial_info_reply,
(dump_func)0, (dump_func)0,
...@@ -1811,8 +1940,18 @@ static const char * const req_names[REQ_NB_REQUESTS] = { ...@@ -1811,8 +1940,18 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"get_atom_name", "get_atom_name",
"init_atom_table", "init_atom_table",
"get_msg_queue", "get_msg_queue",
"wake_queue", "set_queue_bits",
"set_queue_mask",
"get_queue_status",
"wait_input_idle", "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", "create_serial",
"get_serial_info", "get_serial_info",
"set_serial_info", "set_serial_info",
......
...@@ -131,6 +131,7 @@ BOOL CLIPBOARD_IsLocked() ...@@ -131,6 +131,7 @@ BOOL CLIPBOARD_IsLocked()
* by another client. However the handler must have access to the * by another client. However the handler must have access to the
* clipboard in order to update data in response to this message. * clipboard in order to update data in response to this message.
*/ */
#if 0
MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() ); MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
if ( queue if ( queue
...@@ -141,6 +142,10 @@ BOOL CLIPBOARD_IsLocked() ...@@ -141,6 +142,10 @@ BOOL CLIPBOARD_IsLocked()
bIsLocked = FALSE; bIsLocked = FALSE;
QUEUE_Unlock( queue ); QUEUE_Unlock( queue );
#else
/* FIXME: queue check no longer possible */
bIsLocked = FALSE;
#endif
} }
return bIsLocked; return bIsLocked;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "wine/winbase16.h" #include "wine/winbase16.h"
#include "message.h" #include "message.h"
#include "winerror.h" #include "winerror.h"
#include "server.h"
#include "win.h" #include "win.h"
#include "heap.h" #include "heap.h"
#include "hook.h" #include "hook.h"
...@@ -24,6 +25,7 @@ ...@@ -24,6 +25,7 @@
#include "winproc.h" #include "winproc.h"
#include "user.h" #include "user.h"
#include "thread.h" #include "thread.h"
#include "task.h"
#include "options.h" #include "options.h"
#include "controls.h" #include "controls.h"
#include "struct32.h" #include "struct32.h"
...@@ -115,9 +117,9 @@ static DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD first, DWORD last, ...@@ -115,9 +117,9 @@ static DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD first, DWORD last,
POINT16 pt; POINT16 pt;
HANDLE16 hQ = GetFastQueue16(); HANDLE16 hQ = GetFastQueue16();
MESSAGEQUEUE *queue = QUEUE_Lock(hQ); MESSAGEQUEUE *queue = QUEUE_Lock(hQ);
BOOL mouseClick = ((message == WM_LBUTTONDOWN) || int mouseClick = ((message == WM_LBUTTONDOWN) ||
(message == WM_RBUTTONDOWN) || (message == WM_RBUTTONDOWN) ||
(message == WM_MBUTTONDOWN))?1:0; (message == WM_MBUTTONDOWN));
DWORD retvalue; DWORD retvalue;
/* Find the window to dispatch this mouse message to */ /* Find the window to dispatch this mouse message to */
...@@ -155,7 +157,7 @@ static DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD first, DWORD last, ...@@ -155,7 +157,7 @@ static DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD first, DWORD last,
/* Wake up the other task */ /* Wake up the other task */
QUEUE_Unlock( queue ); QUEUE_Unlock( queue );
queue = QUEUE_Lock( pWnd->hmemTaskQ ); queue = QUEUE_Lock( pWnd->hmemTaskQ );
if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE ); if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE, 0 );
QUEUE_Unlock( queue ); QUEUE_Unlock( queue );
retvalue = SYSQ_MSG_ABANDON; retvalue = SYSQ_MSG_ABANDON;
...@@ -387,7 +389,7 @@ static DWORD MSG_TranslateKbdMsg( HWND hTopWnd, DWORD first, DWORD last, ...@@ -387,7 +389,7 @@ static DWORD MSG_TranslateKbdMsg( HWND hTopWnd, DWORD first, DWORD last,
/* Wake up the other task */ /* Wake up the other task */
queue = QUEUE_Lock( pWnd->hmemTaskQ ); queue = QUEUE_Lock( pWnd->hmemTaskQ );
if (queue) QUEUE_SetWakeBit( queue, QS_KEY ); if (queue) QUEUE_SetWakeBit( queue, QS_KEY, 0 );
QUEUE_Unlock( queue ); QUEUE_Unlock( queue );
WIN_ReleaseWndPtr(pWnd); WIN_ReleaseWndPtr(pWnd);
return SYSQ_MSG_ABANDON; return SYSQ_MSG_ABANDON;
...@@ -771,127 +773,59 @@ UINT WINAPI GetDoubleClickTime(void) ...@@ -771,127 +773,59 @@ UINT WINAPI GetDoubleClickTime(void)
static LRESULT MSG_SendMessageInterThread( HQUEUE16 hDestQueue, static LRESULT MSG_SendMessageInterThread( HQUEUE16 hDestQueue,
HWND hwnd, UINT msg, HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam, WPARAM wParam, LPARAM lParam,
DWORD timeout, WORD flags, DWORD timeout, WORD type,
LRESULT *pRes) LRESULT *pRes)
{ {
MESSAGEQUEUE *queue, *destQ; MESSAGEQUEUE *destQ;
SMSG *smsg; BOOL ret;
LRESULT retVal = 1; int iWndsLocks;
int iWndsLocks; LRESULT result = 0;
if (pRes) *pRes = 0;
if (IsTaskLocked16() || !IsWindow(hwnd)) TRACE( "hwnd %x msg %x (%s) wp %x lp %lx\n", hwnd, msg, SPY_GetMsgName(msg), wParam, lParam );
return 0;
/* create a SMSG structure to hold SendMessage() parameters */ if (!(destQ = QUEUE_Lock( hDestQueue ))) return 0;
if (! (smsg = (SMSG *) HeapAlloc( GetProcessHeap(), 0, sizeof(SMSG) )) )
return 0;
if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0;
if (!(destQ = QUEUE_Lock( hDestQueue ))) SERVER_START_REQ( send_message )
{ {
QUEUE_Unlock( queue ); req->posted = FALSE;
return 0; 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();
} }
SERVER_END_REQ;
QUEUE_Unlock( destQ );
if (!ret) return 0;
TRACE_(sendmsg)("SM: %s [%04x] (%04x -> %04x)\n", iWndsLocks = WIN_SuspendWndsLock();
SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
/* fill up SMSG structure */ /* wait for the result */
smsg->hWnd = hwnd; QUEUE_WaitBits( QS_SMRESULT, timeout );
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 */ SERVER_START_REQ( get_message_reply )
if (QUEUE_AddSMSG(destQ, SM_PENDING_LIST, smsg) == FALSE)
{ {
retVal = 0; req->cancel = 1;
goto CLEANUP; if ((ret = !SERVER_CALL_ERR())) result = req->result;
} }
SERVER_END_REQ;
if (!pRes) goto CLEANUP; /* don't need a reply */ 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() );
iWndsLocks = WIN_SuspendWndsLock();
/* wait for the result */ if (!ret && (GetLastError() == ERROR_IO_PENDING))
while ( TRUE )
{ {
/* if (timeout == INFINITE) ERR("no timeout but no result\n");
* The sequence is crucial to avoid deadlock situations: SetLastError(0); /* timeout */
* - 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;
}
} }
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 if (pRes) *pRes = result;
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 );
WIN_RestoreWndsLock(iWndsLocks);
CLEANUP: return ret;
QUEUE_Unlock( queue );
QUEUE_Unlock( destQ );
TRACE_(sendmsg)("done!\n");
return retVal;
} }
...@@ -908,77 +842,14 @@ void WINAPI ReplyMessage16( LRESULT result ) ...@@ -908,77 +842,14 @@ void WINAPI ReplyMessage16( LRESULT result )
*/ */
BOOL WINAPI ReplyMessage( LRESULT result ) BOOL WINAPI ReplyMessage( LRESULT result )
{ {
MESSAGEQUEUE *senderQ = 0; BOOL ret;
MESSAGEQUEUE *queue = 0; SERVER_START_REQ( reply_message )
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) )
{
/* 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;
}
if (smsg->flags & SMSG_SENDING_REPLY)
{ {
/* remove msg from the waiting list, since this is the last req->result = result;
ReplyMessage */ req->remove = 0;
QUEUE_RemoveSMSG( queue, SM_WAITING_LIST, smsg ); ret = !SERVER_CALL_ERR();
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);
} }
SERVER_END_REQ;
ReplyMessageEnd:
if ( senderQ )
QUEUE_Unlock( senderQ );
if ( queue )
QUEUE_Unlock( queue );
return ret; return ret;
} }
...@@ -1116,9 +987,9 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, ...@@ -1116,9 +987,9 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd,
iWndsLocks = WIN_SuspendWndsLock(); iWndsLocks = WIN_SuspendWndsLock();
while(1) while(1)
{ {
QMSG *qmsg; WORD wakeBits = HIWORD(GetQueueStatus( mask ));
hQueue = GetFastQueue16(); hQueue = GetFastQueue16();
msgQueue = QUEUE_Lock( hQueue ); msgQueue = QUEUE_Lock( hQueue );
if (!msgQueue) if (!msgQueue)
...@@ -1127,10 +998,7 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, ...@@ -1127,10 +998,7 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd,
return FALSE; return FALSE;
} }
EnterCriticalSection( &msgQueue->cSection ); #if 0
msgQueue->changeBits = 0;
LeaveCriticalSection( &msgQueue->cSection );
/* First handle a message put by SendMessage() */ /* First handle a message put by SendMessage() */
while ( QUEUE_ReceiveMessage( msgQueue ) ) while ( QUEUE_ReceiveMessage( msgQueue ) )
...@@ -1152,36 +1020,69 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, ...@@ -1152,36 +1020,69 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd,
break; break;
} }
LeaveCriticalSection( &msgQueue->cSection ); LeaveCriticalSection( &msgQueue->cSection );
#endif
/* Now find a normal message */ /* Now find a normal message */
retry: retry:
if ((QUEUE_TestWakeBit(msgQueue, mask & QS_POSTMESSAGE)) && if (wakeBits & (QS_POSTMESSAGE|QS_TIMER|QS_PAINT))
((qmsg = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != 0))
{ {
/* Try to convert message to requested type */ QMSG qmsg;
MSG tmpMsg = qmsg->msg; if (QUEUE_FindMsg( hwnd, first, last, flags & PM_REMOVE, FALSE, &qmsg ))
if ( !MSG_ConvertMsg( &tmpMsg, qmsg->type, type ) )
{ {
ERR( "Message %s of wrong type contains pointer parameters. Skipped!\n", /* Try to convert message to requested type */
SPY_GetMsgName(tmpMsg.message)); MSG tmpMsg = qmsg.msg;
QUEUE_RemoveMsg( msgQueue, qmsg ); if ( !MSG_ConvertMsg( &tmpMsg, qmsg.type, type ) )
goto retry; {
} 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; msg = tmpMsg;
msgQueue->GetMessageTimeVal = msg.time; msgQueue->GetMessageTimeVal = msg.time;
msgQueue->GetMessagePosVal = MAKELONG( (INT16)msg.pt.x, (INT16)msg.pt.y ); msgQueue->GetMessagePosVal = MAKELONG( (INT16)msg.pt.x, (INT16)msg.pt.y );
msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo; msgQueue->GetMessageExtraInfoVal = qmsg.extraInfo;
if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, qmsg ); /* need to fill the window handle for WM_PAINT message */
break; 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;
}
} }
changeBits = MSG_JournalPlayBackMsg(); changeBits = MSG_JournalPlayBackMsg();
#if 0 /* FIXME */
EnterCriticalSection( &msgQueue->cSection ); EnterCriticalSection( &msgQueue->cSection );
msgQueue->changeBits |= changeBits; msgQueue->changeBits |= changeBits;
LeaveCriticalSection( &msgQueue->cSection ); LeaveCriticalSection( &msgQueue->cSection );
#endif
/* Now find a hardware event */ /* Now find a hardware event */
...@@ -1194,68 +1095,14 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, ...@@ -1194,68 +1095,14 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd,
break; 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 (peek)
{ {
#if 0 /* FIXME */ #if 0 /* FIXME */
if (!(flags & PM_NOYIELD)) UserYield16(); if (!(flags & PM_NOYIELD)) UserYield16();
#endif #endif
/* check for graphics events */ /* check for graphics events */
if (USER_Driver.pMsgWaitForMultipleObjects) if (USER_Driver.pMsgWaitForMultipleObjectsEx)
USER_Driver.pMsgWaitForMultipleObjects( 0, NULL, FALSE, 0 ); USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
QUEUE_Unlock( msgQueue ); QUEUE_Unlock( msgQueue );
WIN_RestoreWndsLock(iWndsLocks); WIN_RestoreWndsLock(iWndsLocks);
...@@ -1556,23 +1403,38 @@ BOOL WINAPI GetMessageW( ...@@ -1556,23 +1403,38 @@ BOOL WINAPI GetMessageW(
/*********************************************************************** /***********************************************************************
* MSG_PostToQueue * 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 ) 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; SERVER_START_REQ( send_message )
msg.message = message; {
msg.wParam = wParam; req->posted = TRUE;
msg.lParam = lParam; req->id = (void *)tid;
msg.time = GetTickCount(); req->type = type;
GetCursorPos(&msg.pt); 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 * MSG_IsPointerMessage
* *
...@@ -1652,7 +1514,6 @@ static BOOL MSG_IsPointerMessage(UINT message, WPARAM wParam, LPARAM lParam) { ...@@ -1652,7 +1514,6 @@ static BOOL MSG_IsPointerMessage(UINT message, WPARAM wParam, LPARAM lParam) {
static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message, static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam ) WPARAM wParam, LPARAM lParam )
{ {
HQUEUE16 hQueue;
WND *wndPtr; WND *wndPtr;
/* See thread on wine-devel around 6.2.2001. Basically posted messages /* 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, ...@@ -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", TRACE("BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
wndPtr->hwndSelf, message, wParam, lParam); wndPtr->hwndSelf, message, wParam, lParam);
MSG_PostToQueue( wndPtr->hmemTaskQ, type, MSG_PostToQueue( GetWindowThreadProcessId( wndPtr->hwndSelf, NULL ), type,
wndPtr->hwndSelf, message, wParam, lParam ); wndPtr->hwndSelf, message, wParam, lParam );
} }
} }
...@@ -1689,11 +1550,8 @@ static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message, ...@@ -1689,11 +1550,8 @@ static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message,
return TRUE; return TRUE;
} }
wndPtr = WIN_FindWndPtr( hwnd ); return MSG_PostToQueue( GetWindowThreadProcessId( hwnd, NULL ),
hQueue = wndPtr? wndPtr->hmemTaskQ : 0; type, hwnd, message, wParam, lParam );
WIN_ReleaseWndPtr(wndPtr);
return MSG_PostToQueue( hQueue, type, hwnd, message, wParam, lParam );
} }
/*********************************************************************** /***********************************************************************
...@@ -1730,8 +1588,9 @@ BOOL WINAPI PostMessageW( HWND hwnd, UINT message, WPARAM wParam, ...@@ -1730,8 +1588,9 @@ BOOL WINAPI PostMessageW( HWND hwnd, UINT message, WPARAM wParam,
BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message, BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message,
WPARAM16 wParam, LPARAM lParam ) WPARAM16 wParam, LPARAM lParam )
{ {
return MSG_PostToQueue( GetTaskQueue16(hTask), QMSG_WIN16, TDB *pTask = TASK_GetPtr( hTask );
0, message, wParam, lParam ); 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, ...@@ -1740,8 +1599,7 @@ BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message,
BOOL WINAPI PostThreadMessageA( DWORD idThread, UINT message, BOOL WINAPI PostThreadMessageA( DWORD idThread, UINT message,
WPARAM wParam, LPARAM lParam ) WPARAM wParam, LPARAM lParam )
{ {
return MSG_PostToQueue( GetThreadQueue16(idThread), QMSG_WIN32A, return MSG_PostToQueue( idThread, QMSG_WIN32A, 0, message, wParam, lParam );
0, message, wParam, lParam );
} }
/********************************************************************** /**********************************************************************
...@@ -1750,8 +1608,7 @@ BOOL WINAPI PostThreadMessageA( DWORD idThread, UINT message, ...@@ -1750,8 +1608,7 @@ BOOL WINAPI PostThreadMessageA( DWORD idThread, UINT message,
BOOL WINAPI PostThreadMessageW( DWORD idThread, UINT message, BOOL WINAPI PostThreadMessageW( DWORD idThread, UINT message,
WPARAM wParam, LPARAM lParam ) WPARAM wParam, LPARAM lParam )
{ {
return MSG_PostToQueue( GetThreadQueue16(idThread), QMSG_WIN32W, return MSG_PostToQueue( idThread, QMSG_WIN32W, 0, message, wParam, lParam );
0, message, wParam, lParam );
} }
...@@ -1784,7 +1641,7 @@ static void MSG_CallWndProcHook( LPMSG pmsg, BOOL bUnicode ) ...@@ -1784,7 +1641,7 @@ static void MSG_CallWndProcHook( LPMSG pmsg, BOOL bUnicode )
* 1 otherwise * 1 otherwise
*/ */
static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam, static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam, DWORD timeout, WORD flags, LPARAM lParam, DWORD timeout, WORD type,
LRESULT *pRes) LRESULT *pRes)
{ {
WND * wndPtr = 0; WND * wndPtr = 0;
...@@ -1814,7 +1671,7 @@ static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam, ...@@ -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", TRACE("BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
wndPtr->hwndSelf, msg, (DWORD)wParam, lParam); wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
MSG_SendMessage( wndPtr->hwndSelf, msg, wParam, lParam, MSG_SendMessage( wndPtr->hwndSelf, msg, wParam, lParam,
timeout, flags, pRes); timeout, type, pRes);
} }
} }
WIN_ReleaseWndPtr(wndPtr); WIN_ReleaseWndPtr(wndPtr);
...@@ -1825,29 +1682,35 @@ static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam, ...@@ -1825,29 +1682,35 @@ static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam,
if (HOOK_IsHooked( WH_CALLWNDPROC )) if (HOOK_IsHooked( WH_CALLWNDPROC ))
{ {
if (flags & SMSG_UNICODE) switch(type)
MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE);
else if (flags & SMSG_WIN32)
MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE);
else
{ {
LPCWPSTRUCT16 pmsg; case QMSG_WIN16:
{
LPCWPSTRUCT16 pmsg;
if ((pmsg = SEGPTR_NEW(CWPSTRUCT16))) if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
{ {
pmsg->hwnd = hwnd & 0xffff; pmsg->hwnd = hwnd & 0xffff;
pmsg->message= msg & 0xffff; pmsg->message= msg & 0xffff;
pmsg->wParam = wParam & 0xffff; pmsg->wParam = wParam & 0xffff;
pmsg->lParam = lParam; pmsg->lParam = lParam;
HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1, HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
(LPARAM)SEGPTR_GET(pmsg) ); (LPARAM)SEGPTR_GET(pmsg) );
hwnd = pmsg->hwnd; hwnd = pmsg->hwnd;
msg = pmsg->message; msg = pmsg->message;
wParam = pmsg->wParam; wParam = pmsg->wParam;
lParam = pmsg->lParam; lParam = pmsg->lParam;
SEGPTR_FREE( pmsg ); 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 ))) if (!(wndPtr = WIN_FindWndPtr( hwnd )))
...@@ -1860,33 +1723,35 @@ static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam, ...@@ -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 */ ret = 0; /* Don't send anything if the task is dying */
goto END; goto END;
} }
if (flags & SMSG_WIN32) if (type != QMSG_WIN16)
SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam ); SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam );
else else
SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam ); SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
if (wndPtr->hmemTaskQ && wndPtr->hmemTaskQ != GetFastQueue16()) if (wndPtr->hmemTaskQ && wndPtr->hmemTaskQ != GetFastQueue16())
ret = MSG_SendMessageInterThread( wndPtr->hmemTaskQ, hwnd, msg, ret = MSG_SendMessageInterThread( wndPtr->hmemTaskQ, hwnd, msg,
wParam, lParam, timeout, flags, pRes ); wParam, lParam, timeout, type, pRes );
else else
{ {
LRESULT res; LRESULT res = 0;
/* Call the right CallWindowProc flavor */ /* Call the right CallWindowProc flavor */
if (flags & SMSG_UNICODE) switch(type)
res = CallWindowProcW( (WNDPROC)wndPtr->winproc, {
hwnd, msg, wParam, lParam ); case QMSG_WIN16:
else if (flags & SMSG_WIN32) res = CallWindowProc16( (WNDPROC16)wndPtr->winproc, hwnd, msg, wParam, lParam );
res = CallWindowProcA( (WNDPROC)wndPtr->winproc, break;
hwnd, msg, wParam, lParam ); case QMSG_WIN32A:
else res = CallWindowProcA( (WNDPROC)wndPtr->winproc, hwnd, msg, wParam, lParam );
res = CallWindowProc16( (WNDPROC16)wndPtr->winproc, break;
(HWND16) hwnd, (UINT16) msg, case QMSG_WIN32W:
(WPARAM16) wParam, lParam ); res = CallWindowProcW( (WNDPROC)wndPtr->winproc, hwnd, msg, wParam, lParam );
break;
}
if (pRes) *pRes = res; if (pRes) *pRes = res;
} }
if (flags & SMSG_WIN32) if (type != QMSG_WIN16)
SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, pRes?*pRes:0, wParam, lParam ); SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, pRes?*pRes:0, wParam, lParam );
else else
SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, pRes?*pRes:0, wParam, lParam ); 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, ...@@ -1903,7 +1768,7 @@ LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
LPARAM lParam) LPARAM lParam)
{ {
LRESULT res; LRESULT res;
MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, 0, &res); MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN16, &res);
return res; return res;
} }
...@@ -1916,8 +1781,7 @@ LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wParam, ...@@ -1916,8 +1781,7 @@ LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wParam,
{ {
LRESULT res; LRESULT res;
MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32A, &res);
SMSG_WIN32, &res);
return res; return res;
} }
...@@ -1952,8 +1816,7 @@ LRESULT WINAPI SendMessageW( ...@@ -1952,8 +1816,7 @@ LRESULT WINAPI SendMessageW(
) { ) {
LRESULT res; LRESULT res;
MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32W, &res);
SMSG_WIN32 | SMSG_UNICODE, &res);
return res; return res;
} }
...@@ -1971,7 +1834,7 @@ LRESULT WINAPI SendMessageTimeout16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, ...@@ -1971,7 +1834,7 @@ LRESULT WINAPI SendMessageTimeout16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
/* FIXME: need support for SMTO_BLOCK */ /* 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; if (resultp) *resultp = (WORD) msgRet;
return ret; return ret;
} }
...@@ -1989,8 +1852,7 @@ LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wParam, ...@@ -1989,8 +1852,7 @@ LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wParam,
/* FIXME: need support for SMTO_BLOCK */ /* FIXME: need support for SMTO_BLOCK */
ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, SMSG_WIN32, ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN32A, &msgRet);
&msgRet);
if (resultp) *resultp = (DWORD) msgRet; if (resultp) *resultp = (DWORD) msgRet;
return ret; return ret;
...@@ -2009,8 +1871,7 @@ LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam, ...@@ -2009,8 +1871,7 @@ LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam,
/* FIXME: need support for SMTO_BLOCK */ /* FIXME: need support for SMTO_BLOCK */
ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN32W, &msgRet);
SMSG_WIN32 | SMSG_UNICODE, &msgRet);
if (resultp) *resultp = (DWORD) msgRet; if (resultp) *resultp = (DWORD) msgRet;
return ret; return ret;
...@@ -2022,77 +1883,82 @@ LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam, ...@@ -2022,77 +1883,82 @@ LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam,
* *
* WaitMessage() suspends a thread until events appear in the thread's * WaitMessage() suspends a thread until events appear in the thread's
* queue. * 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, DWORD WINAPI MsgWaitForMultipleObjectsEx( DWORD count, CONST HANDLE *pHandles,
BOOL fWaitAll, DWORD dwMilliseconds, DWORD timeout, DWORD mask, DWORD flags )
DWORD dwWakeMask )
{ {
DWORD i;
HANDLE handles[MAXIMUM_WAIT_OBJECTS]; HANDLE handles[MAXIMUM_WAIT_OBJECTS];
DWORD ret; DWORD i, ret;
HQUEUE16 hQueue = GetFastQueue16(); HQUEUE16 hQueue = GetFastQueue16();
MESSAGEQUEUE *msgQueue = QUEUE_Lock( hQueue ); MESSAGEQUEUE *msgQueue;
if (!msgQueue) return WAIT_FAILED;
if (nCount > MAXIMUM_WAIT_OBJECTS-1) if (count > MAXIMUM_WAIT_OBJECTS-1)
{ {
SetLastError( ERROR_INVALID_PARAMETER ); SetLastError( ERROR_INVALID_PARAMETER );
QUEUE_Unlock( msgQueue );
return WAIT_FAILED; return WAIT_FAILED;
} }
EnterCriticalSection( &msgQueue->cSection ); if (!(msgQueue = QUEUE_Lock( hQueue ))) return WAIT_FAILED;
msgQueue->changeBits = 0;
msgQueue->wakeMask = dwWakeMask; /* set the queue mask */
LeaveCriticalSection( &msgQueue->cSection ); 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 */ /* Add the thread event to the handle list */
for (i = 0; i < nCount; i++) handles[i] = pHandles[i]; for (i = 0; i < count; i++) handles[i] = pHandles[i];
handles[nCount] = msgQueue->server_queue; handles[count] = msgQueue->server_queue;
if (USER_Driver.pMsgWaitForMultipleObjects)
if (USER_Driver.pMsgWaitForMultipleObjectsEx)
{ {
ret = USER_Driver.pMsgWaitForMultipleObjects(nCount+1, handles, fWaitAll, dwMilliseconds); ret = USER_Driver.pMsgWaitForMultipleObjectsEx( count+1, handles, timeout, mask, flags );
if (ret == nCount+1) ret = nCount; /* pretend the msg queue is ready */ if (ret == count+1) ret = count; /* pretend the msg queue is ready */
} }
else else
ret = WaitForMultipleObjects( nCount+1, handles, fWaitAll, dwMilliseconds ); ret = WaitForMultipleObjectsEx( count+1, handles, flags & MWMO_WAITALL,
timeout, flags & MWMO_ALERTABLE );
QUEUE_Unlock( msgQueue ); QUEUE_Unlock( msgQueue );
return ret; return ret;
} }
/***********************************************************************
* MsgWaitForMultipleObjects (USER32.@)
*/
DWORD WINAPI MsgWaitForMultipleObjects( DWORD count, CONST HANDLE *handles,
BOOL wait_all, DWORD timeout, DWORD mask )
{
return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask,
wait_all ? MWMO_WAITALL : 0 );
}
/*********************************************************************** /***********************************************************************
* MsgWaitForMultipleObjects (USER.640) * MsgWaitForMultipleObjects16 (USER.640)
*/ */
DWORD WINAPI MsgWaitForMultipleObjects16( DWORD nCount, HANDLE *pHandles, DWORD WINAPI MsgWaitForMultipleObjects16( DWORD count, CONST HANDLE *handles,
BOOL fWaitAll, DWORD dwMilliseconds, BOOL wait_all, DWORD timeout, DWORD mask )
DWORD dwWakeMask )
{ {
TRACE("(%lu,%p,%u,%lu,0x%lx)\n", return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask,
nCount, pHandles, fWaitAll, dwMilliseconds, dwWakeMask); wait_all ? MWMO_WAITALL : 0 );
return MsgWaitForMultipleObjects(nCount, pHandles, fWaitAll, dwMilliseconds, dwWakeMask);
} }
struct accent_char struct accent_char
{ {
BYTE ac_accent; BYTE ac_accent;
...@@ -2594,17 +2460,25 @@ BOOL16 WINAPI InSendMessage16(void) ...@@ -2594,17 +2460,25 @@ BOOL16 WINAPI InSendMessage16(void)
*/ */
BOOL WINAPI InSendMessage(void) BOOL WINAPI InSendMessage(void)
{ {
MESSAGEQUEUE *queue; return (InSendMessageEx(NULL) & (ISMEX_SEND|ISMEX_REPLIED)) == ISMEX_SEND;
BOOL ret; }
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; return ret;
} }
/*********************************************************************** /***********************************************************************
* BroadcastSystemMessage (USER32.@) * BroadcastSystemMessage (USER32.@)
*/ */
...@@ -2623,8 +2497,7 @@ LONG WINAPI BroadcastSystemMessage( ...@@ -2623,8 +2497,7 @@ LONG WINAPI BroadcastSystemMessage(
*/ */
BOOL WINAPI SendNotifyMessageA(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) BOOL WINAPI SendNotifyMessageA(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{ {
return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32A, NULL);
SMSG_WIN32, NULL);
} }
/*********************************************************************** /***********************************************************************
...@@ -2632,8 +2505,7 @@ BOOL WINAPI SendNotifyMessageA(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) ...@@ -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) BOOL WINAPI SendNotifyMessageW(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{ {
return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32W, NULL);
SMSG_WIN32 | SMSG_UNICODE, NULL);
} }
/*********************************************************************** /***********************************************************************
......
/* * Message queues related functions /*
* Message queues related functions
* *
* Copyright 1993, 1994 Alexandre Julliard * Copyright 1993, 1994 Alexandre Julliard
*/ */
...@@ -20,12 +21,11 @@ ...@@ -20,12 +21,11 @@
#include "server.h" #include "server.h"
#include "spy.h" #include "spy.h"
DECLARE_DEBUG_CHANNEL(msg);
DECLARE_DEBUG_CHANNEL(sendmsg); DECLARE_DEBUG_CHANNEL(sendmsg);
DEFAULT_DEBUG_CHANNEL(msg);
#define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */ #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
static HQUEUE16 hFirstQueue = 0;
static HQUEUE16 hExitingQueue = 0; static HQUEUE16 hExitingQueue = 0;
static HQUEUE16 hmemSysMsgQueue = 0; static HQUEUE16 hmemSysMsgQueue = 0;
static MESSAGEQUEUE *sysMsgQueue = NULL; static MESSAGEQUEUE *sysMsgQueue = NULL;
...@@ -59,7 +59,7 @@ PERQUEUEDATA * PERQDATA_CreateInstance( ) ...@@ -59,7 +59,7 @@ PERQUEUEDATA * PERQDATA_CreateInstance( )
TRACE_(msg)("()\n"); TRACE_(msg)("()\n");
/* Share a single instance of perQData for all 16 bit tasks */ /* Share a single instance of perQData for all 16 bit tasks */
if ( ( bIsWin16 = THREAD_IsWin16( NtCurrentTeb() ) ) ) if ( ( bIsWin16 = !(NtCurrentTeb()->tibflags & TEBF_WIN32) ) )
{ {
/* If previously allocated, just bump up ref count */ /* If previously allocated, just bump up ref count */
if ( pQDataWin16 ) if ( pQDataWin16 )
...@@ -363,21 +363,14 @@ void QUEUE_DumpQueue( HQUEUE16 hQueue ) ...@@ -363,21 +363,14 @@ void QUEUE_DumpQueue( HQUEUE16 hQueue )
EnterCriticalSection( &pq->cSection ); EnterCriticalSection( &pq->cSection );
DPRINTF( "next: %12.4x Intertask SendMessage:\n" DPRINTF( "thread: %10p Intertask SendMessage:\n"
"thread: %10p ----------------------\n" "firstMsg: %8p lastMsg: %8p\n"
"firstMsg: %8p smWaiting: %10p\n"
"lastMsg: %8p smPending: %10p\n"
"msgCount: %8.4x smProcessing: %10p\n"
"lockCount: %7.4x\n" "lockCount: %7.4x\n"
"paints: %10.4x\n" "paints: %10.4x\n"
"timers: %10.4x\n"
"wakeBits: %8.4x\n"
"wakeMask: %8.4x\n"
"hCurHook: %8.4x\n", "hCurHook: %8.4x\n",
pq->next, pq->teb, pq->firstMsg, pq->smWaiting, pq->lastMsg, pq->teb, pq->firstMsg, pq->lastMsg,
pq->smPending, pq->msgCount, pq->smProcessing, (unsigned)pq->lockCount, pq->wPaintCount,
(unsigned)pq->lockCount, pq->wPaintCount, pq->wTimerCount, pq->hCurHook);
pq->wakeBits, pq->wakeMask, pq->hCurHook);
LeaveCriticalSection( &pq->cSection ); LeaveCriticalSection( &pq->cSection );
...@@ -386,34 +379,6 @@ void QUEUE_DumpQueue( HQUEUE16 hQueue ) ...@@ -386,34 +379,6 @@ void QUEUE_DumpQueue( HQUEUE16 hQueue )
/*********************************************************************** /***********************************************************************
* QUEUE_WalkQueues
*/
void QUEUE_WalkQueues(void)
{
char module[10];
HQUEUE16 hQueue = hFirstQueue;
DPRINTF( "Queue Msgs Thread Task Module\n" );
while (hQueue)
{
MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
if (!queue)
{
WARN_(msg)("Bad queue handle %04x\n", hQueue );
return;
}
if (!GetModuleName16( queue->teb->htask16, module, sizeof(module )))
strcpy( module, "???" );
DPRINTF( "%04x %4d %p %04x %s\n", hQueue,queue->msgCount,
queue->teb, queue->teb->htask16, module );
hQueue = queue->next;
QUEUE_Unlock( queue );
}
DPRINTF( "\n" );
}
/***********************************************************************
* QUEUE_IsExitingQueue * QUEUE_IsExitingQueue
*/ */
BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue ) BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue )
...@@ -452,24 +417,25 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData ) ...@@ -452,24 +417,25 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
if ( !msgQueue ) if ( !msgQueue )
return 0; return 0;
SERVER_START_REQ( get_msg_queue ) if (bCreatePerQData)
{ {
SERVER_CALL_ERR(); SERVER_START_REQ( get_msg_queue )
handle = req->handle; {
} SERVER_CALL_ERR();
SERVER_END_REQ; handle = req->handle;
if (!handle) }
{ SERVER_END_REQ;
ERR_(msg)("Cannot get thread queue"); if (!handle)
GlobalFree16( hQueue ); {
return 0; ERR_(msg)("Cannot get thread queue");
GlobalFree16( hQueue );
return 0;
}
msgQueue->server_queue = handle;
} }
msgQueue->server_queue = handle;
msgQueue->server_queue = ConvertToGlobalHandle( msgQueue->server_queue );
msgQueue->self = hQueue; msgQueue->self = hQueue;
msgQueue->wakeBits = msgQueue->changeBits = 0;
InitializeCriticalSection( &msgQueue->cSection ); InitializeCriticalSection( &msgQueue->cSection );
MakeCriticalSectionGlobal( &msgQueue->cSection ); MakeCriticalSectionGlobal( &msgQueue->cSection );
...@@ -484,44 +450,6 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData ) ...@@ -484,44 +450,6 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
/*********************************************************************** /***********************************************************************
* QUEUE_FlushMessage
*
* Try to reply to all pending sent messages on exit.
*/
static void QUEUE_FlushMessages( MESSAGEQUEUE *queue )
{
SMSG *smsg;
MESSAGEQUEUE *senderQ = 0;
if( queue )
{
EnterCriticalSection( &queue->cSection );
/* empty the list of pending SendMessage waiting to be received */
while (queue->smPending)
{
smsg = QUEUE_RemoveSMSG( queue, SM_PENDING_LIST, 0);
senderQ = QUEUE_Lock( smsg->hSrcQueue );
if ( !senderQ )
continue;
/* return 0, to unblock other thread */
smsg->lResult = 0;
smsg->flags |= SMSG_HAVE_RESULT;
QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
QUEUE_Unlock( senderQ );
}
QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
LeaveCriticalSection( &queue->cSection );
}
}
/***********************************************************************
* QUEUE_DeleteMsgQueue * QUEUE_DeleteMsgQueue
* *
* Unlinks and deletes a message queue. * Unlinks and deletes a message queue.
...@@ -532,7 +460,6 @@ static void QUEUE_FlushMessages( MESSAGEQUEUE *queue ) ...@@ -532,7 +460,6 @@ static void QUEUE_FlushMessages( MESSAGEQUEUE *queue )
BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue ) BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
{ {
MESSAGEQUEUE * msgQueue = QUEUE_Lock(hQueue); MESSAGEQUEUE * msgQueue = QUEUE_Lock(hQueue);
HQUEUE16 *pPrev;
TRACE_(msg)("(): Deleting message queue %04x\n", hQueue); TRACE_(msg)("(): Deleting message queue %04x\n", hQueue);
...@@ -547,9 +474,6 @@ BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue ) ...@@ -547,9 +474,6 @@ BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
if( hCursorQueue == hQueue ) hCursorQueue = 0; if( hCursorQueue == hQueue ) hCursorQueue = 0;
if( hActiveQueue == hQueue ) hActiveQueue = 0; if( hActiveQueue == hQueue ) hActiveQueue = 0;
/* flush sent messages */
QUEUE_FlushMessages( msgQueue );
HeapLock( GetProcessHeap() ); /* FIXME: a bit overkill */ HeapLock( GetProcessHeap() ); /* FIXME: a bit overkill */
/* Release per queue data if present */ /* Release per queue data if present */
...@@ -558,24 +482,7 @@ BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue ) ...@@ -558,24 +482,7 @@ BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
PERQDATA_Release( msgQueue->pQData ); PERQDATA_Release( msgQueue->pQData );
msgQueue->pQData = 0; msgQueue->pQData = 0;
} }
/* remove the message queue from the global link list */
pPrev = &hFirstQueue;
while (*pPrev && (*pPrev != hQueue))
{
MESSAGEQUEUE *msgQ = (MESSAGEQUEUE*)GlobalLock16(*pPrev);
/* sanity check */
if ( !msgQ || (msgQ->magic != QUEUE_MAGIC) )
{
/* HQUEUE link list is corrupted, try to exit gracefully */
ERR_(msg)("HQUEUE link list corrupted!\n");
pPrev = 0;
break;
}
pPrev = &msgQ->next;
}
if (pPrev && *pPrev) *pPrev = msgQueue->next;
msgQueue->self = 0; msgQueue->self = 0;
HeapUnlock( GetProcessHeap() ); HeapUnlock( GetProcessHeap() );
...@@ -619,47 +526,34 @@ MESSAGEQUEUE *QUEUE_GetSysQueue(void) ...@@ -619,47 +526,34 @@ MESSAGEQUEUE *QUEUE_GetSysQueue(void)
* *
* See "Windows Internals", p.449 * See "Windows Internals", p.449
*/ */
static BOOL QUEUE_TrySetWakeBit( MESSAGEQUEUE *queue, WORD bit, BOOL always ) static BOOL QUEUE_TrySetWakeBit( MESSAGEQUEUE *queue, WORD set, WORD clear, BOOL always )
{ {
BOOL wake = FALSE; BOOL wake = FALSE;
EnterCriticalSection( &queue->cSection ); TRACE_(msg)("queue = %04x, set = %04x, clear = %04x, always = %d\n",
queue->self, set, clear, always );
if (!queue->server_queue) return FALSE;
TRACE_(msg)("queue = %04x (wm=%04x), bit = %04x, always = %d\n", SERVER_START_REQ( set_queue_bits )
queue->self, queue->wakeMask, bit, always );
if ((queue->wakeMask & bit) || always)
{ {
if (bit & QS_MOUSE) pMouseQueue = queue; req->handle = queue->server_queue;
if (bit & QS_KEY) pKbdQueue = queue; req->set = set;
queue->changeBits |= bit; req->clear = clear;
queue->wakeBits |= bit; req->mask_cond = always ? 0 : set;
if (!SERVER_CALL()) wake = (req->changed_mask & set) != 0;
} }
if (queue->wakeMask & bit) SERVER_END_REQ;
{
queue->wakeMask = 0;
wake = TRUE;
}
LeaveCriticalSection( &queue->cSection );
if ( wake ) if (wake || always)
{ {
/* Wake up thread waiting for message */ if (set & QS_MOUSE) pMouseQueue = queue;
SERVER_START_REQ( wake_queue ) if (set & QS_KEY) pKbdQueue = queue;
{
req->handle = queue->server_queue;
req->bits = bit;
SERVER_CALL();
}
SERVER_END_REQ;
} }
return wake; return wake;
} }
void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit ) void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD set, WORD clear )
{ {
QUEUE_TrySetWakeBit( queue, bit, TRUE ); QUEUE_TrySetWakeBit( queue, set, clear, TRUE );
} }
...@@ -668,25 +562,9 @@ void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit ) ...@@ -668,25 +562,9 @@ void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
*/ */
void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit ) void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
{ {
EnterCriticalSection( &queue->cSection ); QUEUE_SetWakeBit( queue, 0, bit );
queue->changeBits &= ~bit;
queue->wakeBits &= ~bit;
LeaveCriticalSection( &queue->cSection );
}
/***********************************************************************
* QUEUE_TestWakeBit
*/
WORD QUEUE_TestWakeBit( MESSAGEQUEUE *queue, WORD bit )
{
WORD ret;
EnterCriticalSection( &queue->cSection );
ret = queue->wakeBits & bit;
LeaveCriticalSection( &queue->cSection );
return ret;
} }
/*********************************************************************** /***********************************************************************
* QUEUE_WaitBits * QUEUE_WaitBits
* *
...@@ -708,38 +586,44 @@ int QUEUE_WaitBits( WORD bits, DWORD timeout ) ...@@ -708,38 +586,44 @@ int QUEUE_WaitBits( WORD bits, DWORD timeout )
for (;;) for (;;)
{ {
unsigned int wake_bits = 0, changed_bits = 0;
DWORD dwlc; DWORD dwlc;
EnterCriticalSection( &queue->cSection ); 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 (queue->changeBits & bits) if (changed_bits & bits)
{ {
/* One of the bits is set; we can return */ /* One of the bits is set; we can return */
queue->wakeMask = 0;
LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue ); QUEUE_Unlock( queue );
return 1; return 1;
} }
if (queue->wakeBits & QS_SENDMESSAGE) if (wake_bits & QS_SENDMESSAGE)
{ {
/* Process the sent message immediately */ /* Process the sent message immediately */
queue->wakeMask = 0; QMSG msg;
QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg );
LeaveCriticalSection( &queue->cSection ); continue; /* nested sm crux */
QUEUE_ReceiveMessage( queue );
continue; /* nested sm crux */
} }
queue->wakeMask = bits | QS_SENDMESSAGE; TRACE_(msg)("(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n",
TRACE_(msg)("%04x: wakeMask is %04x, waiting\n", queue->self, queue->wakeMask); queue->self, bits, wake_bits, changed_bits );
LeaveCriticalSection( &queue->cSection );
ReleaseThunkLock( &dwlc ); ReleaseThunkLock( &dwlc );
if (dwlc) TRACE_(msg)("had win16 lock\n"); if (dwlc) TRACE_(msg)("had win16 lock\n");
if (USER_Driver.pMsgWaitForMultipleObjects) if (USER_Driver.pMsgWaitForMultipleObjectsEx)
USER_Driver.pMsgWaitForMultipleObjects( 1, &queue->server_queue, FALSE, timeout ); USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, timeout, 0, 0 );
else else
WaitForSingleObject( queue->server_queue, timeout ); WaitForSingleObject( queue->server_queue, timeout );
if (dwlc) RestoreThunkLock( dwlc ); if (dwlc) RestoreThunkLock( dwlc );
...@@ -747,323 +631,98 @@ int QUEUE_WaitBits( WORD bits, DWORD timeout ) ...@@ -747,323 +631,98 @@ int QUEUE_WaitBits( WORD bits, DWORD timeout )
} }
/*********************************************************************** /* handle the reception of a sent message by calling the corresponding window proc */
* QUEUE_AddSMSG static void handle_sent_message( QMSG *msg )
*
* This routine is called when a SMSG need to be added to one of the three
* SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
*/
BOOL QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
{ {
TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list, LRESULT result = 0;
smsg, SPY_GetMsgName(smsg->msg)); MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
switch (list) WND *wndPtr = WIN_FindWndPtr( msg->msg.hwnd );
{
case SM_PROCESSING_LIST:
/* don't need to be thread safe, only accessed by the
thread associated with the sender queue */
smsg->nextProcessing = queue->smProcessing;
queue->smProcessing = smsg;
break;
case SM_WAITING_LIST:
/* don't need to be thread safe, only accessed by the
thread associated with the receiver queue */
smsg->nextWaiting = queue->smWaiting;
queue->smWaiting = smsg;
break;
case SM_PENDING_LIST:
{
/* make it thread safe, could be accessed by the sender and
receiver thread */
SMSG **prev;
EnterCriticalSection( &queue->cSection );
smsg->nextPending = NULL;
prev = &queue->smPending;
while ( *prev )
prev = &(*prev)->nextPending;
*prev = smsg;
LeaveCriticalSection( &queue->cSection );
QUEUE_SetWakeBit( queue, QS_SENDMESSAGE );
break;
}
default: TRACE( "got hwnd %x msg %x (%s) wp %x lp %lx\n",
ERR_(sendmsg)("Invalid list: %d", list); msg->msg.hwnd, msg->msg.message, SPY_GetMsgName(msg->msg.message),
break; msg->msg.wParam, msg->msg.lParam );
}
return TRUE;
}
queue->GetMessageExtraInfoVal = msg->extraInfo;
/*********************************************************************** /* call the right version of CallWindowProcXX */
* QUEUE_RemoveSMSG switch(msg->type)
*
* This routine is called when a SMSG needs to be removed from one of the three
* SM lists (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST).
* If smsg == 0, remove the first smsg from the specified list
*/
SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
{
switch (list)
{ {
case SM_PROCESSING_LIST: case QMSG_WIN16:
/* don't need to be thread safe, only accessed by the result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
thread associated with the sender queue */ (HWND16) msg->msg.hwnd,
(UINT16) msg->msg.message,
/* if smsg is equal to null, it means the first in the list */ LOWORD(msg->msg.wParam),
if (!smsg) msg->msg.lParam );
smsg = queue->smProcessing; break;
case QMSG_WIN32A:
TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list, result = CallWindowProcA( wndPtr->winproc, msg->msg.hwnd, msg->msg.message,
smsg, SPY_GetMsgName(smsg->msg)); msg->msg.wParam, msg->msg.lParam );
/* In fact SM_PROCESSING_LIST is a stack, and smsg break;
should be always at the top of the list */ case QMSG_WIN32W:
if ( (smsg != queue->smProcessing) || !queue->smProcessing ) result = CallWindowProcW( wndPtr->winproc, msg->msg.hwnd, msg->msg.message,
{ msg->msg.wParam, msg->msg.lParam );
ERR_(sendmsg)("smsg not at the top of Processing list, smsg=0x%p queue=0x%p\n", smsg, queue); break;
return 0;
}
else
{
queue->smProcessing = smsg->nextProcessing;
smsg->nextProcessing = 0;
}
return smsg;
case SM_WAITING_LIST:
/* don't need to be thread safe, only accessed by the
thread associated with the receiver queue */
/* if smsg is equal to null, it means the first in the list */
if (!smsg)
smsg = queue->smWaiting;
TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
smsg, SPY_GetMsgName(smsg->msg));
/* In fact SM_WAITING_LIST is a stack, and smsg
should be always at the top of the list */
if ( (smsg != queue->smWaiting) || !queue->smWaiting )
{
ERR_(sendmsg)("smsg not at the top of Waiting list, smsg=0x%p queue=0x%p\n", smsg, queue);
return 0;
}
else
{
queue->smWaiting = smsg->nextWaiting;
smsg->nextWaiting = 0;
}
return smsg;
case SM_PENDING_LIST:
/* make it thread safe, could be accessed by the sender and
receiver thread */
EnterCriticalSection( &queue->cSection );
if (!smsg)
smsg = queue->smPending;
if ( (smsg != queue->smPending) || !queue->smPending )
{
ERR_(sendmsg)("should always remove the top one in Pending list, smsg=0x%p queue=0x%p\n", smsg, queue);
LeaveCriticalSection( &queue->cSection );
return 0;
}
TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
smsg, SPY_GetMsgName(smsg->msg));
queue->smPending = smsg->nextPending;
smsg->nextPending = 0;
/* if no more SMSG in Pending list, clear QS_SENDMESSAGE flag */
if (!queue->smPending)
QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
LeaveCriticalSection( &queue->cSection );
return smsg;
default:
ERR_(sendmsg)("Invalid list: %d\n", list);
break;
}
return 0;
}
/***********************************************************************
* QUEUE_ReceiveMessage
*
* This routine is called to check whether a sent message is waiting
* for the queue. If so, it is received and processed.
*/
BOOL QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
{
LRESULT result = 0;
SMSG *smsg;
MESSAGEQUEUE *senderQ;
EnterCriticalSection( &queue->cSection );
if ( !((queue->wakeBits & QS_SENDMESSAGE) && queue->smPending) )
{
LeaveCriticalSection( &queue->cSection );
return FALSE;
} }
LeaveCriticalSection( &queue->cSection );
TRACE_(sendmsg)("queue %04x\n", queue->self );
/* remove smsg on the top of the pending list and put it in the processing list */
smsg = QUEUE_RemoveSMSG(queue, SM_PENDING_LIST, 0);
QUEUE_AddSMSG(queue, SM_WAITING_LIST, smsg);
TRACE_(sendmsg)("RM: %s [%04x] (%04x -> %04x)\n",
SPY_GetMsgName(smsg->msg), smsg->msg, smsg->hSrcQueue, smsg->hDstQueue );
if (IsWindow( smsg->hWnd ))
{
WND *wndPtr = WIN_FindWndPtr( smsg->hWnd );
DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
/* use sender queue extra info value while calling the window proc */
senderQ = QUEUE_Lock( smsg->hSrcQueue );
if (senderQ)
{
queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
QUEUE_Unlock( senderQ );
}
/* call the right version of CallWindowProcXX */
if (smsg->flags & SMSG_WIN32)
{
TRACE_(sendmsg)("\trcm: msg is Win32\n" );
if (smsg->flags & SMSG_UNICODE)
result = CallWindowProcW( wndPtr->winproc,
smsg->hWnd, smsg->msg,
smsg->wParam, smsg->lParam );
else
result = CallWindowProcA( wndPtr->winproc,
smsg->hWnd, smsg->msg,
smsg->wParam, smsg->lParam );
}
else /* Win16 message */
result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
(HWND16) smsg->hWnd,
(UINT16) smsg->msg,
LOWORD (smsg->wParam),
smsg->lParam );
queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */
WIN_ReleaseWndPtr(wndPtr);
TRACE_(sendmsg)("result = %08x\n", (unsigned)result );
}
else WARN_(sendmsg)("\trcm: bad hWnd\n");
/* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not
an early reply */
smsg->flags |= SMSG_SENDING_REPLY;
ReplyMessage( result );
TRACE_(sendmsg)("done!\n" );
return TRUE;
}
queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */
WIN_ReleaseWndPtr(wndPtr);
QUEUE_Unlock( queue );
SERVER_START_REQ( reply_message )
/***********************************************************************
* QUEUE_AddMsg
*
* Add a message to the queue. Return FALSE if queue is full.
*/
BOOL QUEUE_AddMsg( HQUEUE16 hQueue, int type, MSG *msg, DWORD extraInfo )
{
MESSAGEQUEUE *msgQueue;
QMSG *qmsg;
if (!(msgQueue = QUEUE_Lock( hQueue ))) return FALSE;
/* allocate new message in global heap for now */
if (!(qmsg = (QMSG *) HeapAlloc( GetProcessHeap(), 0, sizeof(QMSG) ) ))
{ {
QUEUE_Unlock( msgQueue ); req->result = result;
return 0; req->remove = 1;
SERVER_CALL();
} }
SERVER_END_REQ;
EnterCriticalSection( &msgQueue->cSection );
/* Store message */
qmsg->type = type;
qmsg->msg = *msg;
qmsg->extraInfo = extraInfo;
/* insert the message in the link list */
qmsg->nextMsg = 0;
qmsg->prevMsg = msgQueue->lastMsg;
if (msgQueue->lastMsg)
msgQueue->lastMsg->nextMsg = qmsg;
/* update first and last anchor in message queue */
msgQueue->lastMsg = qmsg;
if (!msgQueue->firstMsg)
msgQueue->firstMsg = qmsg;
msgQueue->msgCount++;
LeaveCriticalSection( &msgQueue->cSection );
QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
QUEUE_Unlock( msgQueue );
return TRUE;
} }
/*********************************************************************** /***********************************************************************
* QUEUE_FindMsg * QUEUE_FindMsg
* *
* Find a message matching the given parameters. Return -1 if none available. * Find a message matching the given parameters. Return -1 if none available.
*/ */
QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last ) BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove, BOOL sent_only, QMSG *msg )
{ {
QMSG* qmsg; BOOL ret = FALSE, sent = FALSE;
EnterCriticalSection( &msgQueue->cSection ); if (!first && !last) last = ~0;
if (!msgQueue->msgCount) for (;;)
qmsg = 0;
else if (!hwnd && !first && !last)
qmsg = msgQueue->firstMsg;
else
{ {
/* look in linked list for message matching first and last criteria */ SERVER_START_REQ( get_message )
for (qmsg = msgQueue->firstMsg; qmsg; qmsg = qmsg->nextMsg)
{ {
MSG *msg = &(qmsg->msg); req->remove = remove;
req->posted = !sent_only;
if (!hwnd || (msg->hwnd == hwnd)) req->get_win = hwnd;
req->get_first = first;
req->get_last = last;
if ((ret = !SERVER_CALL()))
{ {
if (!first && !last) sent = req->sent;
break; /* found it */ msg->type = req->type;
msg->msg.hwnd = req->win;
if ((msg->message >= first) && (!last || (msg->message <= last))) msg->msg.message = req->msg;
break; /* found it */ msg->msg.wParam = req->wparam;
msg->msg.lParam = req->lparam;
msg->msg.time = 0; /* FIXME */
msg->msg.pt.x = 0; /* FIXME */
msg->msg.pt.y = 0; /* FIXME */
msg->extraInfo = req->info;
} }
} }
SERVER_END_REQ;
if (!ret || !sent) break;
handle_sent_message( msg );
} }
LeaveCriticalSection( &msgQueue->cSection );
return qmsg; 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;
} }
...@@ -1092,82 +751,25 @@ void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg ) ...@@ -1092,82 +751,25 @@ void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg )
/* deallocate the memory for the message */ /* deallocate the memory for the message */
HeapFree( GetProcessHeap(), 0, qmsg ); HeapFree( GetProcessHeap(), 0, qmsg );
msgQueue->msgCount--;
if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
LeaveCriticalSection( &msgQueue->cSection ); LeaveCriticalSection( &msgQueue->cSection );
} }
#if 0
/*********************************************************************** /***********************************************************************
* QUEUE_WakeSomeone * QUEUE_CleanupWindow
* *
* Wake a queue upon reception of a hardware event. * Cleanup the queue to account for a window being deleted.
*/ */
static void QUEUE_WakeSomeone( UINT message ) void QUEUE_CleanupWindow( HWND hwnd )
{ {
WND* wndPtr = NULL; SERVER_START_REQ( cleanup_window_queue )
WORD wakeBit;
HWND hwnd;
HQUEUE16 hQueue = 0;
MESSAGEQUEUE *queue = NULL;
if (hCursorQueue)
hQueue = hCursorQueue;
if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
{
wakeBit = QS_KEY;
if( hActiveQueue )
hQueue = hActiveQueue;
}
else
{
wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
if( (hwnd = GetCapture()) )
if( (wndPtr = WIN_FindWndPtr( hwnd )) )
{
hQueue = wndPtr->hmemTaskQ;
WIN_ReleaseWndPtr(wndPtr);
}
}
if( (hwnd = GetSysModalWindow16()) )
{
if( (wndPtr = WIN_FindWndPtr( hwnd )) )
{
hQueue = wndPtr->hmemTaskQ;
WIN_ReleaseWndPtr(wndPtr);
}
}
if (hQueue)
{
queue = QUEUE_Lock( hQueue );
QUEUE_SetWakeBit( queue, wakeBit );
QUEUE_Unlock( queue );
return;
}
/* Search for someone to wake */
hQueue = hFirstQueue;
while ( (queue = QUEUE_Lock( hQueue )) )
{ {
if (QUEUE_TrySetWakeBit( queue, wakeBit, FALSE )) req->win = hwnd;
{ SERVER_CALL();
QUEUE_Unlock( queue );
return;
}
hQueue = queue->next;
QUEUE_Unlock( queue );
} }
SERVER_END_REQ;
WARN_(msg)("couldn't find queue\n");
} }
#endif
/*********************************************************************** /***********************************************************************
...@@ -1227,8 +829,6 @@ void hardware_event( UINT message, WPARAM wParam, LPARAM lParam, ...@@ -1227,8 +829,6 @@ void hardware_event( UINT message, WPARAM wParam, LPARAM lParam,
sysMsgQueue->lastMsg = qmsg; sysMsgQueue->lastMsg = qmsg;
if (!sysMsgQueue->firstMsg) if (!sysMsgQueue->firstMsg)
sysMsgQueue->firstMsg = qmsg; sysMsgQueue->firstMsg = qmsg;
sysMsgQueue->msgCount++;
} }
/* Store message */ /* Store message */
...@@ -1252,7 +852,7 @@ void hardware_event( UINT message, WPARAM wParam, LPARAM lParam, ...@@ -1252,7 +852,7 @@ void hardware_event( UINT message, WPARAM wParam, LPARAM lParam,
if ((message >= WM_KEYFIRST) && (message <= WM_KEYLAST)) wakeBit = QS_KEY; if ((message >= WM_KEYFIRST) && (message <= WM_KEYLAST)) wakeBit = QS_KEY;
else wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON; else wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
QUEUE_SetWakeBit( queue, wakeBit ); QUEUE_SetWakeBit( queue, wakeBit, 0 );
QUEUE_Unlock( queue ); QUEUE_Unlock( queue );
} }
} }
...@@ -1289,7 +889,7 @@ void QUEUE_IncPaintCount( HQUEUE16 hQueue ) ...@@ -1289,7 +889,7 @@ void QUEUE_IncPaintCount( HQUEUE16 hQueue )
EnterCriticalSection( &queue->cSection ); EnterCriticalSection( &queue->cSection );
queue->wPaintCount++; queue->wPaintCount++;
LeaveCriticalSection( &queue->cSection ); LeaveCriticalSection( &queue->cSection );
QUEUE_SetWakeBit( queue, QS_PAINT ); QUEUE_SetWakeBit( queue, QS_PAINT, 0 );
QUEUE_Unlock( queue ); QUEUE_Unlock( queue );
} }
...@@ -1304,39 +904,7 @@ void QUEUE_DecPaintCount( HQUEUE16 hQueue ) ...@@ -1304,39 +904,7 @@ void QUEUE_DecPaintCount( HQUEUE16 hQueue )
if (!(queue = QUEUE_Lock( hQueue ))) return; if (!(queue = QUEUE_Lock( hQueue ))) return;
EnterCriticalSection( &queue->cSection ); EnterCriticalSection( &queue->cSection );
queue->wPaintCount--; queue->wPaintCount--;
if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT; if (!queue->wPaintCount) QUEUE_ClearWakeBit( queue, QS_PAINT );
LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue );
}
/***********************************************************************
* QUEUE_IncTimerCount
*/
void QUEUE_IncTimerCount( HQUEUE16 hQueue )
{
MESSAGEQUEUE *queue;
if (!(queue = QUEUE_Lock( hQueue ))) return;
EnterCriticalSection( &queue->cSection );
queue->wTimerCount++;
LeaveCriticalSection( &queue->cSection );
QUEUE_SetWakeBit( queue, QS_TIMER );
QUEUE_Unlock( queue );
}
/***********************************************************************
* QUEUE_DecTimerCount
*/
void QUEUE_DecTimerCount( HQUEUE16 hQueue )
{
MESSAGEQUEUE *queue;
if (!(queue = QUEUE_Lock( hQueue ))) return;
EnterCriticalSection( &queue->cSection );
queue->wTimerCount--;
if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
LeaveCriticalSection( &queue->cSection ); LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue ); QUEUE_Unlock( queue );
} }
...@@ -1367,14 +935,7 @@ void WINAPI PostQuitMessage16( INT16 exitCode ) ...@@ -1367,14 +935,7 @@ void WINAPI PostQuitMessage16( INT16 exitCode )
*/ */
void WINAPI PostQuitMessage( INT exitCode ) void WINAPI PostQuitMessage( INT exitCode )
{ {
MESSAGEQUEUE *queue; PostThreadMessageW( GetCurrentThreadId(), WM_QUIT, exitCode, 0 );
if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return;
EnterCriticalSection( &queue->cSection );
queue->wPostQMsg = TRUE;
queue->wExitCode = (WORD)exitCode;
LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue );
} }
...@@ -1470,9 +1031,6 @@ HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags ) ...@@ -1470,9 +1031,6 @@ HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
HeapLock( GetProcessHeap() ); /* FIXME: a bit overkill */ HeapLock( GetProcessHeap() ); /* FIXME: a bit overkill */
SetThreadQueue16( 0, hQueue ); SetThreadQueue16( 0, hQueue );
teb->queue = hQueue; teb->queue = hQueue;
queuePtr->next = hFirstQueue;
hFirstQueue = hQueue;
HeapUnlock( GetProcessHeap() ); HeapUnlock( GetProcessHeap() );
QUEUE_Unlock( queuePtr ); QUEUE_Unlock( queuePtr );
...@@ -1486,17 +1044,7 @@ HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags ) ...@@ -1486,17 +1044,7 @@ HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
*/ */
DWORD WINAPI GetQueueStatus16( UINT16 flags ) DWORD WINAPI GetQueueStatus16( UINT16 flags )
{ {
MESSAGEQUEUE *queue; return GetQueueStatus( flags );
DWORD ret;
if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0;
EnterCriticalSection( &queue->cSection );
ret = MAKELONG( queue->changeBits, queue->wakeBits );
queue->changeBits = 0;
LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue );
return ret & MAKELONG( flags, flags );
} }
/*********************************************************************** /***********************************************************************
...@@ -1504,17 +1052,16 @@ DWORD WINAPI GetQueueStatus16( UINT16 flags ) ...@@ -1504,17 +1052,16 @@ DWORD WINAPI GetQueueStatus16( UINT16 flags )
*/ */
DWORD WINAPI GetQueueStatus( UINT flags ) DWORD WINAPI GetQueueStatus( UINT flags )
{ {
MESSAGEQUEUE *queue; DWORD ret = 0;
DWORD ret;
if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0; SERVER_START_REQ( get_queue_status )
EnterCriticalSection( &queue->cSection ); {
ret = MAKELONG( queue->changeBits, queue->wakeBits ); req->clear = 1;
queue->changeBits = 0; SERVER_CALL();
LeaveCriticalSection( &queue->cSection ); ret = MAKELONG( req->changed_bits & flags, req->wake_bits & flags );
QUEUE_Unlock( queue ); }
SERVER_END_REQ;
return ret & MAKELONG( flags, flags ); return ret;
} }
...@@ -1527,6 +1074,23 @@ BOOL16 WINAPI GetInputState16(void) ...@@ -1527,6 +1074,23 @@ BOOL16 WINAPI GetInputState16(void)
} }
/*********************************************************************** /***********************************************************************
* GetInputState (USER32.@)
*/
BOOL WINAPI GetInputState(void)
{
DWORD ret = 0;
SERVER_START_REQ( get_queue_status )
{
req->clear = 0;
SERVER_CALL();
ret = req->wake_bits & (QS_KEY | QS_MOUSEBUTTON);
}
SERVER_END_REQ;
return ret;
}
/***********************************************************************
* WaitForInputIdle (USER32.@) * WaitForInputIdle (USER32.@)
*/ */
DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut) DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
...@@ -1552,10 +1116,8 @@ DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut) ...@@ -1552,10 +1116,8 @@ DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
ret = MsgWaitForMultipleObjects ( 1, &idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE ); ret = MsgWaitForMultipleObjects ( 1, &idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE );
if ( ret == ( WAIT_OBJECT_0 + 1 )) if ( ret == ( WAIT_OBJECT_0 + 1 ))
{ {
MESSAGEQUEUE * queue; QMSG msg;
if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0xFFFFFFFF; QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg );
QUEUE_ReceiveMessage ( queue );
QUEUE_Unlock ( queue );
continue; continue;
} }
if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF ) if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF )
...@@ -1574,49 +1136,23 @@ DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut) ...@@ -1574,49 +1136,23 @@ DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
} }
/*********************************************************************** /***********************************************************************
* GetInputState (USER32.@)
*/
BOOL WINAPI GetInputState(void)
{
MESSAGEQUEUE *queue;
BOOL ret;
if (!(queue = QUEUE_Lock( GetFastQueue16() )))
return FALSE;
EnterCriticalSection( &queue->cSection );
ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue );
return ret;
}
/***********************************************************************
* UserYield (USER.332) * UserYield (USER.332)
* UserYield16 (USER32.@) * UserYield16 (USER32.@)
*/ */
void WINAPI UserYield16(void) void WINAPI UserYield16(void)
{ {
MESSAGEQUEUE *queue; QMSG msg;
/* Handle sent messages */ /* Handle sent messages */
queue = QUEUE_Lock( GetFastQueue16() ); while (QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg ))
while ( queue && QUEUE_ReceiveMessage( queue ) )
; ;
QUEUE_Unlock( queue );
/* Yield */ /* Yield */
OldYield16(); OldYield16();
/* Handle sent messages again */ /* Handle sent messages again */
queue = QUEUE_Lock( GetFastQueue16() ); while (QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg ))
while ( queue && QUEUE_ReceiveMessage( queue ) )
; ;
QUEUE_Unlock( queue );
} }
/*********************************************************************** /***********************************************************************
......
...@@ -8,10 +8,12 @@ ...@@ -8,10 +8,12 @@
#include "wingdi.h" #include "wingdi.h"
#include "wine/winuser16.h" #include "wine/winuser16.h"
#include "winuser.h" #include "winuser.h"
#include "winerror.h"
#include "queue.h" #include "queue.h"
#include "winproc.h" #include "winproc.h"
#include "services.h"
#include "message.h" #include "message.h"
#include "server.h"
#include "debugtools.h" #include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(timer); DEFAULT_DEBUG_CHANNEL(timer);
...@@ -24,15 +26,13 @@ typedef struct tagTIMER ...@@ -24,15 +26,13 @@ typedef struct tagTIMER
UINT16 msg; /* WM_TIMER or WM_SYSTIMER */ UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
UINT id; UINT id;
UINT timeout; UINT timeout;
HANDLE hService;
BOOL expired;
HWINDOWPROC proc; HWINDOWPROC proc;
} TIMER; } TIMER;
#define NB_TIMERS 34 #define NB_TIMERS 34
#define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */ #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]; static TIMER TimersArray[NB_TIMERS];
...@@ -46,18 +46,6 @@ static CRITICAL_SECTION csTimer = CRITICAL_SECTION_INIT; ...@@ -46,18 +46,6 @@ static CRITICAL_SECTION csTimer = CRITICAL_SECTION_INIT;
*/ */
static void TIMER_ClearTimer( TIMER * pTimer ) 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->hwnd = 0;
pTimer->msg = 0; pTimer->msg = 0;
pTimer->id = 0; pTimer->id = 0;
...@@ -81,7 +69,7 @@ void TIMER_RemoveWindowTimers( HWND hwnd ) ...@@ -81,7 +69,7 @@ void TIMER_RemoveWindowTimers( HWND hwnd )
for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++) for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
if ((pTimer->hwnd == hwnd) && pTimer->timeout) if ((pTimer->hwnd == hwnd) && pTimer->timeout)
TIMER_ClearTimer( pTimer ); TIMER_ClearTimer( pTimer );
LeaveCriticalSection( &csTimer ); LeaveCriticalSection( &csTimer );
} }
...@@ -107,85 +95,6 @@ void TIMER_RemoveQueueTimers( HQUEUE16 hqueue ) ...@@ -107,85 +95,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 * TIMER_SetTimer
*/ */
static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout, static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
...@@ -193,12 +102,20 @@ static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout, ...@@ -193,12 +102,20 @@ static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
{ {
int i; int i;
TIMER * pTimer; TIMER * pTimer;
HWINDOWPROC winproc = 0;
if (GetWindowThreadProcessId( hwnd, NULL ) != GetCurrentThreadId())
{
SetLastError( ERROR_INVALID_WINDOW_HANDLE );
return 0;
}
if (!timeout) if (!timeout)
{ /* timeout==0 is a legal argument UB 990821*/ { /* timeout==0 is a legal argument UB 990821*/
WARN("Timeout== 0 not implemented, using timeout=1\n"); WARN("Timeout== 0 not implemented, using timeout=1\n");
timeout=1; timeout=1;
} }
EnterCriticalSection( &csTimer ); EnterCriticalSection( &csTimer );
/* Check if there's already a timer with the same hwnd and id */ /* 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, ...@@ -228,21 +145,28 @@ static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout,
if (!hwnd) id = i + 1; 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 */ /* Add the timer */
pTimer->hwnd = hwnd; pTimer->hwnd = hwnd;
pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) ) pTimer->hq = GetFastQueue16();
: GetFastQueue16( );
pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER; pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
pTimer->id = id; pTimer->id = id;
pTimer->timeout = timeout; pTimer->timeout = timeout;
pTimer->proc = (HWINDOWPROC)0; pTimer->proc = winproc;
if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
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", TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n",
pTimer, pTimer->hwnd, pTimer->msg, pTimer->id, pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
(DWORD)pTimer->proc ); (DWORD)pTimer->proc );
...@@ -262,6 +186,15 @@ static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys ) ...@@ -262,6 +186,15 @@ static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys )
int i; int i;
TIMER * pTimer; 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 ); EnterCriticalSection( &csTimer );
/* Find the timer */ /* Find the timer */
......
...@@ -458,29 +458,8 @@ static WND* WIN_DestroyWindow( WND* wndPtr ) ...@@ -458,29 +458,8 @@ static WND* WIN_DestroyWindow( WND* wndPtr )
/* toss stale messages from the queue */ /* toss stale messages from the queue */
if( wndPtr->hmemTaskQ ) QUEUE_CleanupWindow( hwnd );
{ wndPtr->hmemTaskQ = 0;
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;
}
if (!(wndPtr->dwStyle & WS_CHILD)) if (!(wndPtr->dwStyle & WS_CHILD))
if (wndPtr->wIDmenu) if (wndPtr->wIDmenu)
......
...@@ -167,17 +167,18 @@ void X11DRV_Synchronize( void ) ...@@ -167,17 +167,18 @@ void X11DRV_Synchronize( void )
/*********************************************************************** /***********************************************************************
* MsgWaitForMultipleObjects (X11DRV.@) * MsgWaitForMultipleObjectsEx (X11DRV.@)
*/ */
DWORD X11DRV_MsgWaitForMultipleObjects( DWORD count, HANDLE *handles, DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
BOOL wait_all, DWORD timeout ) DWORD timeout, DWORD mask, DWORD flags )
{ {
HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */ HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
DWORD i, ret; DWORD i, ret;
struct x11drv_thread_data *data = NtCurrentTeb()->driver_data; struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
if (!data || data->process_event_count) 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]; for (i = 0; i < count; i++) new_handles[i] = handles[i];
new_handles[count] = data->display_fd; new_handles[count] = data->display_fd;
...@@ -187,7 +188,8 @@ DWORD X11DRV_MsgWaitForMultipleObjects( DWORD count, HANDLE *handles, ...@@ -187,7 +188,8 @@ DWORD X11DRV_MsgWaitForMultipleObjects( DWORD count, HANDLE *handles,
XFlush( gdi_display ); XFlush( gdi_display );
XFlush( data->display ); XFlush( data->display );
wine_tsx11_unlock(); 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 ); if (ret == count) process_events( data->display );
data->process_event_count--; data->process_event_count--;
return ret; return ret;
......
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