2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
15 #include "sysmetrics.h"
23 /* #define DEBUG_MSG */
27 #define HWND_BROADCAST ((HWND)0xffff)
29 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
32 extern BOOL
TIMER_CheckTimer( LONG
*next
, MSG
*msg
,
33 HWND hwnd
, BOOL remove
); /* timer.c */
35 /* System message queue (for hardware events) */
36 static HANDLE hmemSysMsgQueue
= 0;
37 static MESSAGEQUEUE
* sysMsgQueue
= NULL
;
39 /* Double-click time */
40 static int doubleClickSpeed
= 452;
43 /***********************************************************************
46 * Create a message queue.
48 static HANDLE
MSG_CreateMsgQueue( int size
)
51 MESSAGEQUEUE
* msgQueue
;
54 queueSize
= sizeof(MESSAGEQUEUE
) + size
* sizeof(QMSG
);
55 if (!(hQueue
= GlobalAlloc( GMEM_FIXED
, queueSize
))) return 0;
56 msgQueue
= (MESSAGEQUEUE
*) GlobalLock( hQueue
);
59 msgQueue
->msgSize
= sizeof(QMSG
);
60 msgQueue
->msgCount
= 0;
61 msgQueue
->nextMessage
= 0;
62 msgQueue
->nextFreeMessage
= 0;
63 msgQueue
->queueSize
= size
;
64 msgQueue
->GetMessageTimeVal
= 0;
65 msgQueue
->GetMessagePosVal
= 0;
66 msgQueue
->GetMessageExtraInfoVal
= 0;
71 msgQueue
->wPostQMsg
= 0;
72 msgQueue
->wExitCode
= 0;
73 msgQueue
->InSendMessageHandle
= 0;
74 msgQueue
->wPaintCount
= 0;
75 msgQueue
->wTimerCount
= 0;
76 msgQueue
->tempStatus
= 0;
78 GlobalUnlock( hQueue
);
83 /***********************************************************************
84 * MSG_CreateSysMsgQueue
86 * Create the system message queue, and set the double-click speed.
87 * Must be called only once.
89 BOOL
MSG_CreateSysMsgQueue( int size
)
91 if (size
> MAX_QUEUE_SIZE
) size
= MAX_QUEUE_SIZE
;
92 else if (size
<= 0) size
= 1;
93 if (!(hmemSysMsgQueue
= MSG_CreateMsgQueue( size
))) return FALSE
;
94 sysMsgQueue
= (MESSAGEQUEUE
*) GlobalLock( hmemSysMsgQueue
);
95 doubleClickSpeed
= GetProfileInt( "windows", "DoubleClickSpeed", 452 );
100 /***********************************************************************
103 * Add a message to the queue. Return FALSE if queue is full.
105 static int MSG_AddMsg( HANDLE hQueue
, MSG
* msg
, DWORD extraInfo
)
108 MESSAGEQUEUE
*msgQueue
;
110 if (!(msgQueue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return FALSE
;
111 pos
= msgQueue
->nextFreeMessage
;
113 /* Check if queue is full */
114 if ((pos
== msgQueue
->nextMessage
) && (msgQueue
->msgCount
> 0)) {
115 fprintf(stderr
,"MSG_AddMsg // queue is full !\n");
120 msgQueue
->messages
[pos
].msg
= *msg
;
121 msgQueue
->messages
[pos
].extraInfo
= extraInfo
;
122 if (pos
< msgQueue
->queueSize
-1) pos
++;
124 msgQueue
->nextFreeMessage
= pos
;
125 msgQueue
->msgCount
++;
126 msgQueue
->status
|= QS_POSTMESSAGE
;
127 msgQueue
->tempStatus
|= QS_POSTMESSAGE
;
132 /***********************************************************************
135 * Find a message matching the given parameters. Return -1 if none available.
137 static int MSG_FindMsg(MESSAGEQUEUE
* msgQueue
, HWND hwnd
, int first
, int last
)
139 int i
, pos
= msgQueue
->nextMessage
;
141 dprintf_msg(stddeb
,"MSG_FindMsg: hwnd=0x"NPFMT
"\n\n", hwnd
);
143 if (!msgQueue
->msgCount
) return -1;
144 if (!hwnd
&& !first
&& !last
) return pos
;
146 for (i
= 0; i
< msgQueue
->msgCount
; i
++)
148 MSG
* msg
= &msgQueue
->messages
[pos
].msg
;
150 if (!hwnd
|| (msg
->hwnd
== hwnd
))
152 if (!first
&& !last
) return pos
;
153 if ((msg
->message
>= first
) && (msg
->message
<= last
)) return pos
;
155 if (pos
< msgQueue
->queueSize
-1) pos
++;
162 /***********************************************************************
165 * Remove a message from the queue (pos must be a valid position).
167 static void MSG_RemoveMsg( MESSAGEQUEUE
* msgQueue
, int pos
)
169 if (pos
>= msgQueue
->nextMessage
)
171 for ( ; pos
> msgQueue
->nextMessage
; pos
--)
172 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
-1];
173 msgQueue
->nextMessage
++;
174 if (msgQueue
->nextMessage
>= msgQueue
->queueSize
)
175 msgQueue
->nextMessage
= 0;
179 for ( ; pos
< msgQueue
->nextFreeMessage
; pos
++)
180 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
+1];
181 if (msgQueue
->nextFreeMessage
) msgQueue
->nextFreeMessage
--;
182 else msgQueue
->nextFreeMessage
= msgQueue
->queueSize
-1;
184 msgQueue
->msgCount
--;
185 if (!msgQueue
->msgCount
) msgQueue
->status
&= ~QS_POSTMESSAGE
;
186 msgQueue
->tempStatus
= 0;
190 /***********************************************************************
191 * MSG_GetWindowForEvent
193 * Find the window and hittest for a mouse event.
195 static INT
MSG_GetWindowForEvent( POINT pt
, HWND
*phwnd
)
199 INT hittest
= HTERROR
;
202 *phwnd
= hwnd
= GetDesktopWindow();
207 /* If point is in window, and window is visible, and it */
208 /* is enabled (or it's a top-level window), then explore */
209 /* its children. Otherwise, go to the next window. */
211 wndPtr
= WIN_FindWndPtr( hwnd
);
212 if ((wndPtr
->dwStyle
& WS_VISIBLE
) &&
213 (!(wndPtr
->dwStyle
& WS_DISABLED
) ||
214 !(wndPtr
->dwStyle
& WS_CHILD
)) &&
215 (x
>= wndPtr
->rectWindow
.left
) &&
216 (x
< wndPtr
->rectWindow
.right
) &&
217 (y
>= wndPtr
->rectWindow
.top
) &&
218 (y
< wndPtr
->rectWindow
.bottom
))
221 x
-= wndPtr
->rectClient
.left
;
222 y
-= wndPtr
->rectClient
.top
;
223 /* If window is minimized or disabled, ignore its children */
224 if ((wndPtr
->dwStyle
& WS_MINIMIZE
) ||
225 (wndPtr
->dwStyle
& WS_DISABLED
)) break;
226 hwnd
= wndPtr
->hwndChild
;
228 else hwnd
= wndPtr
->hwndNext
;
231 /* Make point relative to parent again */
233 wndPtr
= WIN_FindWndPtr( *phwnd
);
234 x
+= wndPtr
->rectClient
.left
;
235 y
+= wndPtr
->rectClient
.top
;
237 /* Send the WM_NCHITTEST message */
241 wndPtr
= WIN_FindWndPtr( *phwnd
);
242 if (wndPtr
->dwStyle
& WS_DISABLED
) hittest
= HTERROR
;
243 else hittest
= (INT
)SendMessage( *phwnd
, WM_NCHITTEST
, 0,
244 MAKELONG( pt
.x
, pt
.y
) );
245 if (hittest
!= HTTRANSPARENT
) break; /* Found the window */
246 hwnd
= wndPtr
->hwndNext
;
249 WND
*nextPtr
= WIN_FindWndPtr( hwnd
);
250 if ((nextPtr
->dwStyle
& WS_VISIBLE
) &&
251 (x
>= nextPtr
->rectWindow
.left
) &&
252 (x
< nextPtr
->rectWindow
.right
) &&
253 (y
>= nextPtr
->rectWindow
.top
) &&
254 (y
< nextPtr
->rectWindow
.bottom
)) break;
255 hwnd
= nextPtr
->hwndNext
;
257 if (hwnd
) *phwnd
= hwnd
; /* Found a suitable sibling */
258 else /* Go back to the parent */
260 if (!(*phwnd
= wndPtr
->hwndParent
)) break;
261 wndPtr
= WIN_FindWndPtr( *phwnd
);
262 x
+= wndPtr
->rectClient
.left
;
263 y
+= wndPtr
->rectClient
.top
;
267 if (!*phwnd
) *phwnd
= GetDesktopWindow();
272 /***********************************************************************
273 * MSG_TranslateMouseMsg
275 * Translate an mouse hardware event into a real mouse message.
276 * Return value indicates whether the translated message must be passed
279 * - Find the window for this message.
280 * - Translate button-down messages in double-clicks.
281 * - Send the WM_NCHITTEST message to find where the cursor is.
282 * - Activate the window if needed.
283 * - Translate the message into a non-client message, or translate
284 * the coordinates to client coordinates.
285 * - Send the WM_SETCURSOR message.
287 static BOOL
MSG_TranslateMouseMsg( MSG
*msg
, BOOL remove
)
291 static DWORD lastClickTime
= 0;
292 static WORD lastClickMsg
= 0;
293 static POINT lastClickPos
= { 0, 0 };
295 BOOL mouseClick
= ((msg
->message
== WM_LBUTTONDOWN
) ||
296 (msg
->message
== WM_RBUTTONDOWN
) ||
297 (msg
->message
== WM_MBUTTONDOWN
));
299 /* Find the window */
303 msg
->hwnd
= GetCapture();
304 msg
->lParam
= MAKELONG( msg
->pt
.x
, msg
->pt
.y
);
305 ScreenToClient( msg
->hwnd
, (LPPOINT
)&msg
->lParam
);
306 return TRUE
; /* No need to further process the message */
309 if ((hittest
= MSG_GetWindowForEvent( msg
->pt
, &msg
->hwnd
)) != HTERROR
)
312 /* Send the WM_PARENTNOTIFY message */
314 if (mouseClick
) WIN_SendParentNotify( msg
->hwnd
, msg
->message
, 0,
315 MAKELONG( msg
->pt
.x
, msg
->pt
.y
) );
317 /* Activate the window if needed */
321 HWND hwndTop
= WIN_GetTopParent( msg
->hwnd
);
322 if (hwndTop
!= GetActiveWindow())
324 LONG ret
= SendMessage( msg
->hwnd
, WM_MOUSEACTIVATE
,
326 MAKELONG( hittest
, msg
->message
) );
327 if ((ret
== MA_ACTIVATEANDEAT
) || (ret
== MA_NOACTIVATEANDEAT
))
329 if ((ret
== MA_ACTIVATE
) || (ret
== MA_ACTIVATEANDEAT
))
331 SetWindowPos( hwndTop
, HWND_TOP
, 0, 0, 0, 0,
332 SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
333 WINPOS_ChangeActiveWindow( hwndTop
, TRUE
);
339 /* Send the WM_SETCURSOR message */
341 SendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
342 MAKELONG( hittest
, msg
->message
));
343 if (eatMsg
) return FALSE
;
345 /* Check for double-click */
349 BOOL dbl_click
= FALSE
;
351 if ((msg
->message
== lastClickMsg
) &&
352 (msg
->time
- lastClickTime
< doubleClickSpeed
) &&
353 (abs(msg
->pt
.x
- lastClickPos
.x
) < SYSMETRICS_CXDOUBLECLK
/2) &&
354 (abs(msg
->pt
.y
- lastClickPos
.y
) < SYSMETRICS_CYDOUBLECLK
/2))
357 if (dbl_click
&& (hittest
== HTCLIENT
))
359 /* Check whether window wants the double click message. */
360 WND
* wndPtr
= WIN_FindWndPtr( msg
->hwnd
);
361 if (!wndPtr
|| !(WIN_CLASS_STYLE(wndPtr
) & CS_DBLCLKS
))
365 if (dbl_click
) switch(msg
->message
)
367 case WM_LBUTTONDOWN
: msg
->message
= WM_LBUTTONDBLCLK
; break;
368 case WM_RBUTTONDOWN
: msg
->message
= WM_RBUTTONDBLCLK
; break;
369 case WM_MBUTTONDOWN
: msg
->message
= WM_MBUTTONDBLCLK
; break;
374 lastClickTime
= msg
->time
;
375 lastClickMsg
= msg
->message
;
376 lastClickPos
= msg
->pt
;
380 /* Build the translated message */
382 msg
->lParam
= MAKELONG( msg
->pt
.x
, msg
->pt
.y
);
383 if (hittest
== HTCLIENT
)
385 ScreenToClient( msg
->hwnd
, (LPPOINT
)&msg
->lParam
);
389 msg
->wParam
= hittest
;
390 msg
->message
+= WM_NCLBUTTONDOWN
- WM_LBUTTONDOWN
;
397 /***********************************************************************
398 * MSG_TranslateKeyboardMsg
400 * Translate an keyboard hardware event into a real message.
401 * Return value indicates whether the translated message must be passed
404 static BOOL
MSG_TranslateKeyboardMsg( MSG
*msg
)
406 /* Should check Ctrl-Esc and PrintScreen here */
408 msg
->hwnd
= GetFocus();
411 /* Send the message to the active window instead, */
412 /* translating messages to their WM_SYS equivalent */
413 msg
->hwnd
= GetActiveWindow();
414 msg
->message
+= WM_SYSKEYDOWN
- WM_KEYDOWN
;
420 /***********************************************************************
421 * MSG_PeekHardwareMsg
423 * Peek for a hardware message matching the hwnd and message filters.
425 static BOOL
MSG_PeekHardwareMsg( MSG
*msg
, HWND hwnd
, WORD first
, WORD last
,
428 int i
, pos
= sysMsgQueue
->nextMessage
;
430 for (i
= 0; i
< sysMsgQueue
->msgCount
; i
++, pos
++)
432 if (pos
>= sysMsgQueue
->queueSize
) pos
= 0;
433 *msg
= sysMsgQueue
->messages
[pos
].msg
;
435 /* Translate message */
437 if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
439 if (!MSG_TranslateMouseMsg( msg
, remove
)) continue;
441 else if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
443 if (!MSG_TranslateKeyboardMsg( msg
)) continue;
445 else continue; /* Should never happen */
447 /* Check message against filters */
449 if (hwnd
&& (msg
->hwnd
!= hwnd
)) continue;
450 if ((first
|| last
) &&
451 ((msg
->message
< first
) || (msg
->message
> last
))) continue;
452 if ((msg
->hwnd
!= GetDesktopWindow()) &&
453 (GetWindowTask(msg
->hwnd
) != GetCurrentTask()))
454 continue; /* Not for this task */
455 if (remove
) MSG_RemoveMsg( sysMsgQueue
, pos
);
462 /**********************************************************************
463 * SetDoubleClickTime (USER.20)
465 void SetDoubleClickTime( WORD interval
)
468 doubleClickSpeed
= 500;
470 doubleClickSpeed
= interval
;
474 /**********************************************************************
475 * GetDoubleClickTime (USER.21)
477 WORD
GetDoubleClickTime()
479 return (WORD
)doubleClickSpeed
;
483 /***********************************************************************
486 void MSG_IncPaintCount( HANDLE hQueue
)
490 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
491 queue
->wPaintCount
++;
492 queue
->status
|= QS_PAINT
;
493 queue
->tempStatus
|= QS_PAINT
;
497 /***********************************************************************
500 void MSG_DecPaintCount( HANDLE hQueue
)
504 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
505 queue
->wPaintCount
--;
506 if (!queue
->wPaintCount
) queue
->status
&= ~QS_PAINT
;
510 /***********************************************************************
513 void MSG_IncTimerCount( HANDLE hQueue
)
517 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
518 queue
->wTimerCount
++;
519 queue
->status
|= QS_TIMER
;
520 queue
->tempStatus
|= QS_TIMER
;
524 /***********************************************************************
527 void MSG_DecTimerCount( HANDLE hQueue
)
531 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
532 queue
->wTimerCount
--;
533 if (!queue
->wTimerCount
) queue
->status
&= ~QS_TIMER
;
537 /***********************************************************************
540 * Add an event to the system message queue.
541 * Note: the position is relative to the desktop window.
543 void hardware_event( WORD message
, WORD wParam
, LONG lParam
,
544 int xPos
, int yPos
, DWORD time
, DWORD extraInfo
)
549 if (!sysMsgQueue
) return;
550 pos
= sysMsgQueue
->nextFreeMessage
;
552 /* Merge with previous event if possible */
554 if ((message
== WM_MOUSEMOVE
) && sysMsgQueue
->msgCount
)
557 else pos
= sysMsgQueue
->queueSize
- 1;
558 msg
= &sysMsgQueue
->messages
[pos
].msg
;
559 if ((msg
->message
== message
) && (msg
->wParam
== wParam
))
560 sysMsgQueue
->msgCount
--; /* Merge events */
562 pos
= sysMsgQueue
->nextFreeMessage
; /* Don't merge */
565 /* Check if queue is full */
567 if ((pos
== sysMsgQueue
->nextMessage
) && sysMsgQueue
->msgCount
)
569 /* Queue is full, beep (but not on every mouse motion...) */
570 if (message
!= WM_MOUSEMOVE
) MessageBeep(0);
576 msg
= &sysMsgQueue
->messages
[pos
].msg
;
578 msg
->message
= message
;
579 msg
->wParam
= wParam
;
580 msg
->lParam
= lParam
;
582 msg
->pt
.x
= xPos
& 0xffff;
583 msg
->pt
.y
= yPos
& 0xffff;
584 sysMsgQueue
->messages
[pos
].extraInfo
= extraInfo
;
585 if (pos
< sysMsgQueue
->queueSize
- 1) pos
++;
587 sysMsgQueue
->nextFreeMessage
= pos
;
588 sysMsgQueue
->msgCount
++;
592 /***********************************************************************
593 * MSG_GetHardwareMessage
595 * Like GetMessage(), but only return mouse and keyboard events.
596 * Used internally for window moving and resizing. Mouse messages
597 * are not translated.
598 * Warning: msg->hwnd is always 0.
600 BOOL
MSG_GetHardwareMessage( LPMSG msg
)
607 if ((pos
= MSG_FindMsg( sysMsgQueue
, 0, 0, 0 )) != -1)
609 *msg
= sysMsgQueue
->messages
[pos
].msg
;
610 MSG_RemoveMsg( sysMsgQueue
, pos
);
613 XNextEvent( display
, &event
);
614 EVENT_ProcessEvent( &event
);
620 /***********************************************************************
621 * SetMessageQueue (USER.266)
623 BOOL
SetMessageQueue( int size
)
626 MESSAGEQUEUE
*queuePtr
;
628 if ((size
> MAX_QUEUE_SIZE
) || (size
<= 0)) return TRUE
;
630 /* Free the old message queue */
631 if ((hQueue
= GetTaskQueue(0)) != 0)
633 GlobalUnlock( hQueue
);
634 GlobalFree( hQueue
);
637 if (!(hQueue
= MSG_CreateMsgQueue( size
))) return FALSE
;
638 queuePtr
= (MESSAGEQUEUE
*)GlobalLock( hQueue
);
639 queuePtr
->hTask
= GetCurrentTask();
640 SetTaskQueue( 0, hQueue
);
645 /***********************************************************************
646 * GetWindowTask (USER.224)
648 HTASK
GetWindowTask( HWND hwnd
)
650 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
651 MESSAGEQUEUE
*queuePtr
;
653 if (!wndPtr
) return 0;
654 queuePtr
= (MESSAGEQUEUE
*)GlobalLock( wndPtr
->hmemTaskQ
);
655 if (!queuePtr
) return 0;
656 return queuePtr
->hTask
;
660 /***********************************************************************
661 * PostQuitMessage (USER.6)
663 void PostQuitMessage( int exitCode
)
667 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return;
668 queue
->wPostQMsg
= TRUE
;
669 queue
->wExitCode
= exitCode
;
673 /***********************************************************************
674 * GetQueueStatus (USER.334)
676 DWORD
GetQueueStatus( int flags
)
681 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
682 ret
= MAKELONG( queue
->tempStatus
, queue
->status
);
683 queue
->tempStatus
= 0;
684 return ret
& MAKELONG( flags
, flags
);
688 /***********************************************************************
689 * GetInputState (USER.335)
695 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return FALSE
;
696 return queue
->status
& (QS_KEY
| QS_MOUSEBUTTON
);
700 /***********************************************************************
703 * Synchronize with the X server. Should not be used too often.
705 void MSG_Synchronize()
709 XSync( display
, False
);
710 while (XPending( display
))
712 XNextEvent( display
, &event
);
713 EVENT_ProcessEvent( &event
);
718 /***********************************************************************
721 * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
722 * Return TRUE if an event is pending, FALSE on timeout or error
723 * (for instance lost connection with the server).
725 BOOL
MSG_WaitXEvent( LONG maxWait
)
728 struct timeval timeout
;
730 int fd
= ConnectionNumber(display
);
732 if (!XPending(display
) && (maxWait
!= -1))
734 FD_ZERO( &read_set
);
735 FD_SET( fd
, &read_set
);
737 timeout
.tv_usec
= (maxWait
% 1000) * 1000;
738 timeout
.tv_sec
= maxWait
/ 1000;
741 sigsetjmp(env_wait_x
, 1);
744 if (DDE_GetRemoteMessage()) {
745 while(DDE_GetRemoteMessage())
749 stop_wait_op
= STOP_WAIT_X
;
750 /* The code up to the next "stop_wait_op= CONT" must be reentrant */
751 if (select( fd
+1, &read_set
, NULL
, NULL
, &timeout
) != 1 &&
752 !XPending(display
)) {
758 #else /* CONFIG_IPC */
759 if (select( fd
+1, &read_set
, NULL
, NULL
, &timeout
) != 1)
760 return FALSE
; /* Timeout or error */
761 #endif /* CONFIG_IPC */
765 /* Process the event (and possibly others that occurred in the meantime) */
770 if (DDE_GetRemoteMessage())
772 while(DDE_GetRemoteMessage()) ;
775 #endif /* CONFIG_IPC */
777 XNextEvent( display
, &event
);
778 EVENT_ProcessEvent( &event
);
780 while (XPending( display
));
785 /***********************************************************************
788 static BOOL
MSG_PeekMessage( LPMSG msg
, HWND hwnd
, WORD first
, WORD last
,
789 WORD flags
, BOOL peek
)
792 MESSAGEQUEUE
*msgQueue
;
793 LONG nextExp
; /* Next timer expiration time */
796 DDE_TestDDE(hwnd
); /* do we have dde handling in the window ?*/
797 DDE_GetRemoteMessage();
798 #endif /* CONFIG_IPC */
802 mask
= QS_POSTMESSAGE
; /* Always selectioned */
803 if ((first
<= WM_KEYLAST
) && (last
>= WM_KEYFIRST
)) mask
|= QS_KEY
;
804 if ((first
<= WM_MOUSELAST
) && (last
>= WM_MOUSEFIRST
)) mask
|= QS_MOUSE
;
805 if ((first
<= WM_TIMER
) && (last
>= WM_TIMER
)) mask
|= QS_TIMER
;
806 if ((first
<= WM_SYSTIMER
) && (last
>= WM_SYSTIMER
)) mask
|= QS_TIMER
;
807 if ((first
<= WM_PAINT
) && (last
>= WM_PAINT
)) mask
|= QS_PAINT
;
809 else mask
= QS_MOUSE
| QS_KEY
| QS_POSTMESSAGE
| QS_TIMER
| QS_PAINT
;
813 msgQueue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) );
814 if (!msgQueue
) return FALSE
;
816 /* First handle a message put by SendMessage() */
817 if (msgQueue
->status
& QS_SENDMESSAGE
)
819 if (!hwnd
|| (msgQueue
->hWnd
== hwnd
))
821 if ((!first
&& !last
) ||
822 ((msgQueue
->msg
>= first
) && (msgQueue
->msg
<= last
)))
824 msg
->hwnd
= msgQueue
->hWnd
;
825 msg
->message
= msgQueue
->msg
;
826 msg
->wParam
= msgQueue
->wParam
;
827 msg
->lParam
= msgQueue
->lParam
;
828 if (flags
& PM_REMOVE
) msgQueue
->status
&= ~QS_SENDMESSAGE
;
834 /* Now find a normal message */
835 pos
= MSG_FindMsg( msgQueue
, hwnd
, first
, last
);
838 QMSG
*qmsg
= &msgQueue
->messages
[pos
];
840 msgQueue
->GetMessageTimeVal
= msg
->time
;
841 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
842 msgQueue
->GetMessageExtraInfoVal
= qmsg
->extraInfo
;
844 if (flags
& PM_REMOVE
) MSG_RemoveMsg( msgQueue
, pos
);
848 /* Now find a hardware event */
849 if (MSG_PeekHardwareMsg( msg
, hwnd
, first
, last
, flags
& PM_REMOVE
))
852 msgQueue
->GetMessageTimeVal
= msg
->time
;
853 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
854 msgQueue
->GetMessageExtraInfoVal
= 0; /* Always 0 for now */
858 /* Now handle a WM_QUIT message */
859 if (msgQueue
->wPostQMsg
)
862 msg
->message
= WM_QUIT
;
863 msg
->wParam
= msgQueue
->wExitCode
;
868 /* Now find a WM_PAINT message */
869 if ((msgQueue
->status
& QS_PAINT
) && (mask
& QS_PAINT
))
871 msg
->hwnd
= WIN_FindWinToRepaint( hwnd
);
872 msg
->message
= WM_PAINT
;
875 if (msg
->hwnd
!= 0) break;
878 /* Finally handle WM_TIMER messages */
879 if ((msgQueue
->status
& QS_TIMER
) && (mask
& QS_TIMER
))
881 if (TIMER_CheckTimer( &nextExp
, msg
, hwnd
, flags
& PM_REMOVE
))
882 break; /* Got a timer msg */
884 else nextExp
= -1; /* No timeout needed */
888 /* Wait until something happens */
891 if (!MSG_WaitXEvent( 0 )) return FALSE
; /* No pending event */
893 else /* Wait for an event, then restart the loop */
894 MSG_WaitXEvent( nextExp
);
897 /* We got a message */
898 if (peek
) return TRUE
;
899 else return (msg
->message
!= WM_QUIT
);
903 /***********************************************************************
904 * MSG_InternalGetMessage
906 * GetMessage() function for internal use. Behave like GetMessage(),
907 * but also call message filters and optionally send WM_ENTERIDLE messages.
908 * 'hwnd' must be the handle of the dialog or menu window.
909 * 'code' is the message filter value (MSGF_??? codes).
911 BOOL
MSG_InternalGetMessage( SEGPTR msg
, HWND hwnd
, HWND hwndOwner
, short code
,
912 WORD flags
, BOOL sendIdle
)
918 if (!MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
919 0, 0, 0, flags
, TRUE
))
921 /* No message present -> send ENTERIDLE and wait */
922 SendMessage( hwndOwner
, WM_ENTERIDLE
, code
, (LPARAM
)hwnd
);
923 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
924 0, 0, 0, flags
, FALSE
);
927 else /* Always wait for a message */
928 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
929 0, 0, 0, flags
, FALSE
);
931 if (!CallMsgFilter( msg
, code
))
932 return (((MSG
*)PTR_SEG_TO_LIN(msg
))->message
!= WM_QUIT
);
934 /* Message filtered -> remove it from the queue */
935 /* if it's still there. */
936 if (!(flags
& PM_REMOVE
))
937 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
938 0, 0, 0, PM_REMOVE
, TRUE
);
943 /***********************************************************************
944 * PeekMessage (USER.109)
946 BOOL
PeekMessage( LPMSG msg
, HWND hwnd
, WORD first
, WORD last
, WORD flags
)
948 return MSG_PeekMessage( msg
, hwnd
, first
, last
, flags
, TRUE
);
952 /***********************************************************************
953 * GetMessage (USER.108)
955 BOOL
GetMessage( SEGPTR msg
, HWND hwnd
, WORD first
, WORD last
)
957 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
958 hwnd
, first
, last
, PM_REMOVE
, FALSE
);
959 CALL_TASK_HOOK( WH_GETMESSAGE
, 0, 0, (LPARAM
)msg
);
960 CALL_SYSTEM_HOOK( WH_GETMESSAGE
, 0, 0, (LPARAM
)msg
);
961 return (((MSG
*)PTR_SEG_TO_LIN(msg
))->message
!= WM_QUIT
);
966 /***********************************************************************
967 * PostMessage (USER.110)
969 BOOL
PostMessage( HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
975 msg
.message
= message
;
978 msg
.time
= GetTickCount();
983 if (DDE_PostMessage(&msg
))
985 #endif /* CONFIG_IPC */
987 if (hwnd
== HWND_BROADCAST
) {
988 dprintf_msg(stddeb
,"PostMessage // HWND_BROADCAST !\n");
989 hwnd
= GetTopWindow(GetDesktopWindow());
991 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) break;
992 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
) {
993 dprintf_msg(stddeb
,"BROADCAST Message to hWnd="NPFMT
" m=%04X w=%04X l=%08lX !\n",
994 hwnd
, message
, wParam
, lParam
);
995 PostMessage(hwnd
, message
, wParam
, lParam
);
997 hwnd
= wndPtr
->hwndNext
;
999 dprintf_msg(stddeb
,"PostMessage // End of HWND_BROADCAST !\n");
1003 wndPtr
= WIN_FindWndPtr( hwnd
);
1004 if (!wndPtr
|| !wndPtr
->hmemTaskQ
) return FALSE
;
1006 return MSG_AddMsg( wndPtr
->hmemTaskQ
, &msg
, 0 );
1009 /***********************************************************************
1010 * PostAppMessage (USER.116)
1012 BOOL
PostAppMessage( HTASK hTask
, WORD message
, WORD wParam
, LONG lParam
)
1016 if (GetTaskQueue(hTask
) == 0) return FALSE
;
1018 msg
.message
= message
;
1019 msg
.wParam
= wParam
;
1020 msg
.lParam
= lParam
;
1021 msg
.time
= GetTickCount();
1025 return MSG_AddMsg( GetTaskQueue(hTask
), &msg
, 0 );
1029 /***********************************************************************
1030 * SendMessage (USER.111)
1032 LRESULT
SendMessage( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1042 } msgstruct
= { lParam
, wParam
, msg
, hwnd
};
1045 MSG DDE_msg
= { hwnd
, msg
, wParam
, lParam
};
1046 if (DDE_SendMessage(&DDE_msg
)) return TRUE
;
1047 #endif /* CONFIG_IPC */
1049 if (hwnd
== HWND_BROADCAST
)
1051 dprintf_msg(stddeb
,"SendMessage // HWND_BROADCAST !\n");
1052 hwnd
= GetTopWindow(GetDesktopWindow());
1055 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) break;
1056 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
1058 dprintf_msg(stddeb
,"BROADCAST Message to hWnd="NPFMT
" m=%04X w=%04lX l=%08lX !\n",
1059 hwnd
, msg
, (DWORD
)wParam
, lParam
);
1060 ret
|= SendMessage( hwnd
, msg
, wParam
, lParam
);
1062 hwnd
= wndPtr
->hwndNext
;
1064 dprintf_msg(stddeb
,"SendMessage // End of HWND_BROADCAST !\n");
1068 EnterSpyMessage(SPY_SENDMESSAGE
, hwnd
, msg
, wParam
, lParam
);
1070 CALL_TASK_HOOK( WH_CALLWNDPROC
, HC_ACTION
, 1, MAKE_SEGPTR(&msgstruct
) );
1071 CALL_SYSTEM_HOOK( WH_CALLWNDPROC
, HC_ACTION
, 1, MAKE_SEGPTR(&msgstruct
) );
1072 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
1074 ExitSpyMessage(SPY_RESULT_INVALIDHWND
,hwnd
,msg
,0);
1077 ret
= CallWindowProc( wndPtr
->lpfnWndProc
, msgstruct
.hWnd
, msgstruct
.wMsg
,
1078 msgstruct
.wParam
, msgstruct
.lParam
);
1079 ExitSpyMessage(SPY_RESULT_OK
,hwnd
,msg
,ret
);
1084 /***********************************************************************
1085 * WaitMessage (USER.112)
1087 void WaitMessage( void )
1090 MESSAGEQUEUE
*queue
;
1091 LONG nextExp
= -1; /* Next timer expiration time */
1094 DDE_GetRemoteMessage();
1095 #endif /* CONFIG_IPC */
1097 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return;
1098 if ((queue
->wPostQMsg
) ||
1099 (queue
->status
& (QS_SENDMESSAGE
| QS_PAINT
)) ||
1100 (queue
->msgCount
) || (sysMsgQueue
->msgCount
) )
1102 if ((queue
->status
& QS_TIMER
) &&
1103 TIMER_CheckTimer( &nextExp
, &msg
, 0, FALSE
))
1105 /* FIXME: (dde) must check DDE & X-events simultaneously */
1106 MSG_WaitXEvent( nextExp
);
1110 /***********************************************************************
1111 * TranslateMessage (USER.113)
1113 BOOL
TranslateMessage( LPMSG msg
)
1115 int message
= msg
->message
;
1117 if ((message
== WM_KEYDOWN
) || (message
== WM_KEYUP
) ||
1118 (message
== WM_SYSKEYDOWN
) || (message
== WM_SYSKEYUP
))
1120 dprintf_msg(stddeb
, "Translating key message\n" );
1127 /***********************************************************************
1128 * DispatchMessage (USER.114)
1130 LONG
DispatchMessage( LPMSG msg
)
1136 EnterSpyMessage( SPY_DISPATCHMESSAGE
, msg
->hwnd
, msg
->message
,
1137 msg
->wParam
, msg
->lParam
);
1139 /* Process timer messages */
1140 if ((msg
->message
== WM_TIMER
) || (msg
->message
== WM_SYSTIMER
))
1144 HINSTANCE ds
= msg
->hwnd
? WIN_GetWindowInstance( msg
->hwnd
)
1145 : (HINSTANCE
)CURRENT_DS
;
1146 return CallWndProc( (WNDPROC
)msg
->lParam
, ds
, msg
->hwnd
,
1147 msg
->message
, msg
->wParam
, GetTickCount() );
1151 if (!msg
->hwnd
) return 0;
1152 if (!(wndPtr
= WIN_FindWndPtr( msg
->hwnd
))) return 0;
1153 if (!wndPtr
->lpfnWndProc
) return 0;
1154 painting
= (msg
->message
== WM_PAINT
);
1155 if (painting
) wndPtr
->flags
|= WIN_NEEDS_BEGINPAINT
;
1156 retval
= CallWindowProc( wndPtr
->lpfnWndProc
, msg
->hwnd
, msg
->message
,
1157 msg
->wParam
, msg
->lParam
);
1158 if (painting
&& IsWindow(msg
->hwnd
) &&
1159 (wndPtr
->flags
& WIN_NEEDS_BEGINPAINT
))
1161 fprintf(stderr
, "BeginPaint not called on WM_PAINT for hwnd "NPFMT
"!\n",
1163 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
1169 /***********************************************************************
1170 * GetMessagePos (USER.119)
1172 DWORD
GetMessagePos(void)
1174 MESSAGEQUEUE
*queue
;
1176 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
1177 return queue
->GetMessagePosVal
;
1181 /***********************************************************************
1182 * GetMessageTime (USER.120)
1184 LONG
GetMessageTime(void)
1186 MESSAGEQUEUE
*queue
;
1188 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
1189 return queue
->GetMessageTimeVal
;
1193 /***********************************************************************
1194 * GetMessageExtraInfo (USER.288)
1196 LONG
GetMessageExtraInfo(void)
1198 MESSAGEQUEUE
*queue
;
1200 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
1201 return queue
->GetMessageExtraInfoVal
;
1205 /***********************************************************************
1206 * RegisterWindowMessage (USER.118)
1208 WORD
RegisterWindowMessage( SEGPTR str
)
1210 dprintf_msg(stddeb
, "RegisterWindowMessage: '%08lx'\n", str
);
1211 return GlobalAddAtom( str
);
1215 /***********************************************************************
1216 * GetTickCount (USER.13) (KERNEL32.299)
1218 DWORD
GetTickCount(void)
1221 gettimeofday( &t
, NULL
);
1222 return (t
.tv_sec
* 1000) + (t
.tv_usec
/ 1000);
1225 /***********************************************************************
1226 * InSendMessage (USER.192
1228 * According to the book, this should return true iff the current message
1229 * was send from another application. In that case, the application should
1230 * invoke ReplyMessage before calling message relevant API.
1231 * Currently, Wine will always return FALSE, as there is no other app.
1233 BOOL
InSendMessage()