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
| GMEM_ZEROINIT
, queueSize
)))
57 msgQueue
= (MESSAGEQUEUE
*) GlobalLock( hQueue
);
58 msgQueue
->msgSize
= sizeof(QMSG
);
59 msgQueue
->queueSize
= size
;
60 msgQueue
->wWinVersion
= 0; /* FIXME? */
61 GlobalUnlock( hQueue
);
66 /***********************************************************************
67 * MSG_CreateSysMsgQueue
69 * Create the system message queue, and set the double-click speed.
70 * Must be called only once.
72 BOOL
MSG_CreateSysMsgQueue( int size
)
74 if (size
> MAX_QUEUE_SIZE
) size
= MAX_QUEUE_SIZE
;
75 else if (size
<= 0) size
= 1;
76 if (!(hmemSysMsgQueue
= MSG_CreateMsgQueue( size
))) return FALSE
;
77 sysMsgQueue
= (MESSAGEQUEUE
*) GlobalLock( hmemSysMsgQueue
);
78 doubleClickSpeed
= GetProfileInt( "windows", "DoubleClickSpeed", 452 );
83 /***********************************************************************
86 * Add a message to the queue. Return FALSE if queue is full.
88 static int MSG_AddMsg( HANDLE hQueue
, MSG
* msg
, DWORD extraInfo
)
91 MESSAGEQUEUE
*msgQueue
;
93 if (!(msgQueue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return FALSE
;
94 pos
= msgQueue
->nextFreeMessage
;
96 /* Check if queue is full */
97 if ((pos
== msgQueue
->nextMessage
) && (msgQueue
->msgCount
> 0)) {
98 fprintf(stderr
,"MSG_AddMsg // queue is full !\n");
103 msgQueue
->messages
[pos
].msg
= *msg
;
104 msgQueue
->messages
[pos
].extraInfo
= extraInfo
;
105 if (pos
< msgQueue
->queueSize
-1) pos
++;
107 msgQueue
->nextFreeMessage
= pos
;
108 msgQueue
->msgCount
++;
109 msgQueue
->status
|= QS_POSTMESSAGE
;
110 msgQueue
->tempStatus
|= QS_POSTMESSAGE
;
115 /***********************************************************************
118 * Find a message matching the given parameters. Return -1 if none available.
120 static int MSG_FindMsg(MESSAGEQUEUE
* msgQueue
, HWND hwnd
, int first
, int last
)
122 int i
, pos
= msgQueue
->nextMessage
;
124 dprintf_msg(stddeb
,"MSG_FindMsg: hwnd=0x"NPFMT
"\n\n", hwnd
);
126 if (!msgQueue
->msgCount
) return -1;
127 if (!hwnd
&& !first
&& !last
) return pos
;
129 for (i
= 0; i
< msgQueue
->msgCount
; i
++)
131 MSG
* msg
= &msgQueue
->messages
[pos
].msg
;
133 if (!hwnd
|| (msg
->hwnd
== hwnd
))
135 if (!first
&& !last
) return pos
;
136 if ((msg
->message
>= first
) && (msg
->message
<= last
)) return pos
;
138 if (pos
< msgQueue
->queueSize
-1) pos
++;
145 /***********************************************************************
148 * Remove a message from the queue (pos must be a valid position).
150 static void MSG_RemoveMsg( MESSAGEQUEUE
* msgQueue
, int pos
)
152 if (pos
>= msgQueue
->nextMessage
)
154 for ( ; pos
> msgQueue
->nextMessage
; pos
--)
155 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
-1];
156 msgQueue
->nextMessage
++;
157 if (msgQueue
->nextMessage
>= msgQueue
->queueSize
)
158 msgQueue
->nextMessage
= 0;
162 for ( ; pos
< msgQueue
->nextFreeMessage
; pos
++)
163 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
+1];
164 if (msgQueue
->nextFreeMessage
) msgQueue
->nextFreeMessage
--;
165 else msgQueue
->nextFreeMessage
= msgQueue
->queueSize
-1;
167 msgQueue
->msgCount
--;
168 if (!msgQueue
->msgCount
) msgQueue
->status
&= ~QS_POSTMESSAGE
;
169 msgQueue
->tempStatus
= 0;
173 /***********************************************************************
174 * MSG_GetWindowForEvent
176 * Find the window and hittest for a mouse event.
178 static INT
MSG_GetWindowForEvent( POINT pt
, HWND
*phwnd
)
182 INT hittest
= HTERROR
;
185 *phwnd
= hwnd
= GetDesktopWindow();
190 /* If point is in window, and window is visible, and it */
191 /* is enabled (or it's a top-level window), then explore */
192 /* its children. Otherwise, go to the next window. */
194 wndPtr
= WIN_FindWndPtr( hwnd
);
195 if ((wndPtr
->dwStyle
& WS_VISIBLE
) &&
196 (!(wndPtr
->dwStyle
& WS_DISABLED
) ||
197 !(wndPtr
->dwStyle
& WS_CHILD
)) &&
198 (x
>= wndPtr
->rectWindow
.left
) &&
199 (x
< wndPtr
->rectWindow
.right
) &&
200 (y
>= wndPtr
->rectWindow
.top
) &&
201 (y
< wndPtr
->rectWindow
.bottom
))
204 x
-= wndPtr
->rectClient
.left
;
205 y
-= wndPtr
->rectClient
.top
;
206 /* If window is minimized or disabled, ignore its children */
207 if ((wndPtr
->dwStyle
& WS_MINIMIZE
) ||
208 (wndPtr
->dwStyle
& WS_DISABLED
)) break;
209 hwnd
= wndPtr
->hwndChild
;
211 else hwnd
= wndPtr
->hwndNext
;
214 /* Make point relative to parent again */
216 wndPtr
= WIN_FindWndPtr( *phwnd
);
217 x
+= wndPtr
->rectClient
.left
;
218 y
+= wndPtr
->rectClient
.top
;
220 /* Send the WM_NCHITTEST message */
224 wndPtr
= WIN_FindWndPtr( *phwnd
);
225 if (wndPtr
->dwStyle
& WS_DISABLED
) hittest
= HTERROR
;
226 else hittest
= (INT
)SendMessage( *phwnd
, WM_NCHITTEST
, 0,
227 MAKELONG( pt
.x
, pt
.y
) );
228 if (hittest
!= HTTRANSPARENT
) break; /* Found the window */
229 hwnd
= wndPtr
->hwndNext
;
232 WND
*nextPtr
= WIN_FindWndPtr( hwnd
);
233 if ((nextPtr
->dwStyle
& WS_VISIBLE
) &&
234 (x
>= nextPtr
->rectWindow
.left
) &&
235 (x
< nextPtr
->rectWindow
.right
) &&
236 (y
>= nextPtr
->rectWindow
.top
) &&
237 (y
< nextPtr
->rectWindow
.bottom
)) break;
238 hwnd
= nextPtr
->hwndNext
;
240 if (hwnd
) *phwnd
= hwnd
; /* Found a suitable sibling */
241 else /* Go back to the parent */
243 if (!(*phwnd
= wndPtr
->hwndParent
)) break;
244 wndPtr
= WIN_FindWndPtr( *phwnd
);
245 x
+= wndPtr
->rectClient
.left
;
246 y
+= wndPtr
->rectClient
.top
;
250 if (!*phwnd
) *phwnd
= GetDesktopWindow();
255 /***********************************************************************
256 * MSG_TranslateMouseMsg
258 * Translate an mouse hardware event into a real mouse message.
259 * Return value indicates whether the translated message must be passed
262 * - Find the window for this message.
263 * - Translate button-down messages in double-clicks.
264 * - Send the WM_NCHITTEST message to find where the cursor is.
265 * - Activate the window if needed.
266 * - Translate the message into a non-client message, or translate
267 * the coordinates to client coordinates.
268 * - Send the WM_SETCURSOR message.
270 static BOOL
MSG_TranslateMouseMsg( MSG
*msg
, BOOL remove
)
274 static DWORD lastClickTime
= 0;
275 static WORD lastClickMsg
= 0;
276 static POINT lastClickPos
= { 0, 0 };
278 MOUSEHOOKSTRUCT hook
= { msg
->pt
, 0, HTCLIENT
, 0 };
280 BOOL mouseClick
= ((msg
->message
== WM_LBUTTONDOWN
) ||
281 (msg
->message
== WM_RBUTTONDOWN
) ||
282 (msg
->message
== WM_MBUTTONDOWN
));
284 /* Find the window */
288 msg
->hwnd
= GetCapture();
289 ScreenToClient( msg
->hwnd
, &pt
);
290 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
291 /* No need to further process the message */
292 hook
.hwnd
= msg
->hwnd
;
293 return !HOOK_CallHooks( WH_MOUSE
, remove
? HC_ACTION
: HC_NOREMOVE
,
294 msg
->message
, (LPARAM
)MAKE_SEGPTR(&hook
));
297 if ((hittest
= MSG_GetWindowForEvent( msg
->pt
, &msg
->hwnd
)) != HTERROR
)
300 /* Send the WM_PARENTNOTIFY message */
302 if (mouseClick
) WIN_SendParentNotify( msg
->hwnd
, msg
->message
, 0,
303 MAKELONG( msg
->pt
.x
, msg
->pt
.y
) );
305 /* Activate the window if needed */
309 HWND hwndTop
= WIN_GetTopParent( msg
->hwnd
);
310 if (hwndTop
!= GetActiveWindow())
312 LONG ret
= SendMessage( msg
->hwnd
, WM_MOUSEACTIVATE
,
314 MAKELONG( hittest
, msg
->message
) );
315 if ((ret
== MA_ACTIVATEANDEAT
) || (ret
== MA_NOACTIVATEANDEAT
))
317 if ((ret
== MA_ACTIVATE
) || (ret
== MA_ACTIVATEANDEAT
))
319 SetWindowPos( hwndTop
, HWND_TOP
, 0, 0, 0, 0,
320 SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
321 WINPOS_ChangeActiveWindow( hwndTop
, TRUE
);
327 /* Send the WM_SETCURSOR message */
329 SendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
330 MAKELONG( hittest
, msg
->message
));
331 if (eatMsg
) return FALSE
;
333 /* Check for double-click */
337 BOOL dbl_click
= FALSE
;
339 if ((msg
->message
== lastClickMsg
) &&
340 (msg
->time
- lastClickTime
< doubleClickSpeed
) &&
341 (abs(msg
->pt
.x
- lastClickPos
.x
) < SYSMETRICS_CXDOUBLECLK
/2) &&
342 (abs(msg
->pt
.y
- lastClickPos
.y
) < SYSMETRICS_CYDOUBLECLK
/2))
345 if (dbl_click
&& (hittest
== HTCLIENT
))
347 /* Check whether window wants the double click message. */
348 WND
* wndPtr
= WIN_FindWndPtr( msg
->hwnd
);
349 if (!wndPtr
|| !(WIN_CLASS_STYLE(wndPtr
) & CS_DBLCLKS
))
353 if (dbl_click
) switch(msg
->message
)
355 case WM_LBUTTONDOWN
: msg
->message
= WM_LBUTTONDBLCLK
; break;
356 case WM_RBUTTONDOWN
: msg
->message
= WM_RBUTTONDBLCLK
; break;
357 case WM_MBUTTONDOWN
: msg
->message
= WM_MBUTTONDBLCLK
; break;
362 lastClickTime
= msg
->time
;
363 lastClickMsg
= msg
->message
;
364 lastClickPos
= msg
->pt
;
368 /* Build the translated message */
370 if (hittest
== HTCLIENT
)
371 ScreenToClient( msg
->hwnd
, &pt
);
374 msg
->wParam
= hittest
;
375 msg
->message
+= WM_NCLBUTTONDOWN
- WM_LBUTTONDOWN
;
377 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
379 hook
.hwnd
= msg
->hwnd
;
380 hook
.wHitTestCode
= hittest
;
381 return !HOOK_CallHooks( WH_MOUSE
, remove
? HC_ACTION
: HC_NOREMOVE
,
382 msg
->message
, (LPARAM
)MAKE_SEGPTR(&hook
));
386 /***********************************************************************
387 * MSG_TranslateKeyboardMsg
389 * Translate an keyboard hardware event into a real message.
390 * Return value indicates whether the translated message must be passed
393 static BOOL
MSG_TranslateKeyboardMsg( MSG
*msg
, BOOL remove
)
395 /* Should check Ctrl-Esc and PrintScreen here */
397 msg
->hwnd
= GetFocus();
400 /* Send the message to the active window instead, */
401 /* translating messages to their WM_SYS equivalent */
402 msg
->hwnd
= GetActiveWindow();
403 msg
->message
+= WM_SYSKEYDOWN
- WM_KEYDOWN
;
405 return !HOOK_CallHooks( WH_KEYBOARD
, remove
? HC_ACTION
: HC_NOREMOVE
,
406 msg
->wParam
, msg
->lParam
);
410 /***********************************************************************
411 * MSG_PeekHardwareMsg
413 * Peek for a hardware message matching the hwnd and message filters.
415 static BOOL
MSG_PeekHardwareMsg( MSG
*msg
, HWND hwnd
, WORD first
, WORD last
,
418 int i
, pos
= sysMsgQueue
->nextMessage
;
420 for (i
= 0; i
< sysMsgQueue
->msgCount
; i
++, pos
++)
422 if (pos
>= sysMsgQueue
->queueSize
) pos
= 0;
423 *msg
= sysMsgQueue
->messages
[pos
].msg
;
425 /* Translate message */
427 if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
429 if (!MSG_TranslateMouseMsg( msg
, remove
)) continue;
431 else if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
433 if (!MSG_TranslateKeyboardMsg( msg
, remove
)) continue;
435 else /* Non-standard hardware event */
437 HARDWAREHOOKSTRUCT hook
= { msg
->hwnd
, msg
->message
,
438 msg
->wParam
, msg
->lParam
};
439 if (HOOK_CallHooks( WH_HARDWARE
, remove
? HC_ACTION
: HC_NOREMOVE
,
440 0, (LPARAM
)MAKE_SEGPTR(&hook
) )) continue;
443 /* Check message against filters */
445 if (hwnd
&& (msg
->hwnd
!= hwnd
)) continue;
446 if ((first
|| last
) &&
447 ((msg
->message
< first
) || (msg
->message
> last
))) continue;
448 if ((msg
->hwnd
!= GetDesktopWindow()) &&
449 (GetWindowTask(msg
->hwnd
) != GetCurrentTask()))
450 continue; /* Not for this task */
453 MSG tmpMsg
= *msg
; /* FIXME */
454 HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
,
455 0, (LPARAM
)MAKE_SEGPTR(&tmpMsg
) );
456 MSG_RemoveMsg( sysMsgQueue
, pos
);
464 /**********************************************************************
465 * SetDoubleClickTime (USER.20)
467 void SetDoubleClickTime( WORD interval
)
470 doubleClickSpeed
= 500;
472 doubleClickSpeed
= interval
;
476 /**********************************************************************
477 * GetDoubleClickTime (USER.21)
479 WORD
GetDoubleClickTime()
481 return (WORD
)doubleClickSpeed
;
485 /***********************************************************************
488 void MSG_IncPaintCount( HANDLE hQueue
)
492 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
493 queue
->wPaintCount
++;
494 queue
->status
|= QS_PAINT
;
495 queue
->tempStatus
|= QS_PAINT
;
499 /***********************************************************************
502 void MSG_DecPaintCount( HANDLE hQueue
)
506 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
507 queue
->wPaintCount
--;
508 if (!queue
->wPaintCount
) queue
->status
&= ~QS_PAINT
;
512 /***********************************************************************
515 void MSG_IncTimerCount( HANDLE hQueue
)
519 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
520 queue
->wTimerCount
++;
521 queue
->status
|= QS_TIMER
;
522 queue
->tempStatus
|= QS_TIMER
;
526 /***********************************************************************
529 void MSG_DecTimerCount( HANDLE hQueue
)
533 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
534 queue
->wTimerCount
--;
535 if (!queue
->wTimerCount
) queue
->status
&= ~QS_TIMER
;
539 /***********************************************************************
542 * Add an event to the system message queue.
543 * Note: the position is relative to the desktop window.
545 void hardware_event( WORD message
, WORD wParam
, LONG lParam
,
546 int xPos
, int yPos
, DWORD time
, DWORD extraInfo
)
551 if (!sysMsgQueue
) return;
552 pos
= sysMsgQueue
->nextFreeMessage
;
554 /* Merge with previous event if possible */
556 if ((message
== WM_MOUSEMOVE
) && sysMsgQueue
->msgCount
)
559 else pos
= sysMsgQueue
->queueSize
- 1;
560 msg
= &sysMsgQueue
->messages
[pos
].msg
;
561 if ((msg
->message
== message
) && (msg
->wParam
== wParam
))
562 sysMsgQueue
->msgCount
--; /* Merge events */
564 pos
= sysMsgQueue
->nextFreeMessage
; /* Don't merge */
567 /* Check if queue is full */
569 if ((pos
== sysMsgQueue
->nextMessage
) && sysMsgQueue
->msgCount
)
571 /* Queue is full, beep (but not on every mouse motion...) */
572 if (message
!= WM_MOUSEMOVE
) MessageBeep(0);
578 msg
= &sysMsgQueue
->messages
[pos
].msg
;
580 msg
->message
= message
;
581 msg
->wParam
= wParam
;
582 msg
->lParam
= lParam
;
584 msg
->pt
.x
= xPos
& 0xffff;
585 msg
->pt
.y
= yPos
& 0xffff;
586 sysMsgQueue
->messages
[pos
].extraInfo
= extraInfo
;
587 if (pos
< sysMsgQueue
->queueSize
- 1) pos
++;
589 sysMsgQueue
->nextFreeMessage
= pos
;
590 sysMsgQueue
->msgCount
++;
594 /***********************************************************************
595 * MSG_GetHardwareMessage
597 * Like GetMessage(), but only return mouse and keyboard events.
598 * Used internally for window moving and resizing. Mouse messages
599 * are not translated.
600 * Warning: msg->hwnd is always 0.
602 BOOL
MSG_GetHardwareMessage( LPMSG msg
)
609 if ((pos
= MSG_FindMsg( sysMsgQueue
, 0, 0, 0 )) != -1)
611 *msg
= sysMsgQueue
->messages
[pos
].msg
;
612 MSG_RemoveMsg( sysMsgQueue
, pos
);
615 XNextEvent( display
, &event
);
616 EVENT_ProcessEvent( &event
);
622 /***********************************************************************
623 * SetMessageQueue (USER.266)
625 BOOL
SetMessageQueue( int size
)
628 MESSAGEQUEUE
*queuePtr
;
630 if ((size
> MAX_QUEUE_SIZE
) || (size
<= 0)) return TRUE
;
632 /* Free the old message queue */
633 if ((hQueue
= GetTaskQueue(0)) != 0)
635 GlobalUnlock( hQueue
);
636 GlobalFree( hQueue
);
639 if (!(hQueue
= MSG_CreateMsgQueue( size
))) return FALSE
;
640 queuePtr
= (MESSAGEQUEUE
*)GlobalLock( hQueue
);
641 queuePtr
->hTask
= GetCurrentTask();
642 SetTaskQueue( 0, hQueue
);
647 /***********************************************************************
648 * GetWindowTask (USER.224)
650 HTASK
GetWindowTask( HWND hwnd
)
652 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
653 MESSAGEQUEUE
*queuePtr
;
655 if (!wndPtr
) return 0;
656 queuePtr
= (MESSAGEQUEUE
*)GlobalLock( wndPtr
->hmemTaskQ
);
657 if (!queuePtr
) return 0;
658 return queuePtr
->hTask
;
662 /***********************************************************************
663 * PostQuitMessage (USER.6)
665 void PostQuitMessage( int exitCode
)
669 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return;
670 queue
->wPostQMsg
= TRUE
;
671 queue
->wExitCode
= exitCode
;
675 /***********************************************************************
676 * GetQueueStatus (USER.334)
678 DWORD
GetQueueStatus( int flags
)
683 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
684 ret
= MAKELONG( queue
->tempStatus
, queue
->status
);
685 queue
->tempStatus
= 0;
686 return ret
& MAKELONG( flags
, flags
);
690 /***********************************************************************
691 * GetInputState (USER.335)
697 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return FALSE
;
698 return queue
->status
& (QS_KEY
| QS_MOUSEBUTTON
);
702 /***********************************************************************
705 * Synchronize with the X server. Should not be used too often.
707 void MSG_Synchronize()
711 XSync( display
, False
);
712 while (XPending( display
))
714 XNextEvent( display
, &event
);
715 EVENT_ProcessEvent( &event
);
720 /***********************************************************************
723 * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
724 * Return TRUE if an event is pending, FALSE on timeout or error
725 * (for instance lost connection with the server).
727 BOOL
MSG_WaitXEvent( LONG maxWait
)
730 struct timeval timeout
;
732 int fd
= ConnectionNumber(display
);
734 if (!XPending(display
) && (maxWait
!= -1))
736 FD_ZERO( &read_set
);
737 FD_SET( fd
, &read_set
);
739 timeout
.tv_usec
= (maxWait
% 1000) * 1000;
740 timeout
.tv_sec
= maxWait
/ 1000;
743 sigsetjmp(env_wait_x
, 1);
746 if (DDE_GetRemoteMessage()) {
747 while(DDE_GetRemoteMessage())
751 stop_wait_op
= STOP_WAIT_X
;
752 /* The code up to the next "stop_wait_op= CONT" must be reentrant */
753 if (select( fd
+1, &read_set
, NULL
, NULL
, &timeout
) != 1 &&
754 !XPending(display
)) {
760 #else /* CONFIG_IPC */
761 if (select( fd
+1, &read_set
, NULL
, NULL
, &timeout
) != 1)
762 return FALSE
; /* Timeout or error */
763 #endif /* CONFIG_IPC */
767 /* Process the event (and possibly others that occurred in the meantime) */
772 if (DDE_GetRemoteMessage())
774 while(DDE_GetRemoteMessage()) ;
777 #endif /* CONFIG_IPC */
779 XNextEvent( display
, &event
);
780 EVENT_ProcessEvent( &event
);
782 while (XPending( display
));
787 /***********************************************************************
790 static BOOL
MSG_PeekMessage( LPMSG msg
, HWND hwnd
, WORD first
, WORD last
,
791 WORD flags
, BOOL peek
)
794 MESSAGEQUEUE
*msgQueue
;
795 LONG nextExp
; /* Next timer expiration time */
798 DDE_TestDDE(hwnd
); /* do we have dde handling in the window ?*/
799 DDE_GetRemoteMessage();
800 #endif /* CONFIG_IPC */
804 mask
= QS_POSTMESSAGE
; /* Always selectioned */
805 if ((first
<= WM_KEYLAST
) && (last
>= WM_KEYFIRST
)) mask
|= QS_KEY
;
806 if ((first
<= WM_MOUSELAST
) && (last
>= WM_MOUSEFIRST
)) mask
|= QS_MOUSE
;
807 if ((first
<= WM_TIMER
) && (last
>= WM_TIMER
)) mask
|= QS_TIMER
;
808 if ((first
<= WM_SYSTIMER
) && (last
>= WM_SYSTIMER
)) mask
|= QS_TIMER
;
809 if ((first
<= WM_PAINT
) && (last
>= WM_PAINT
)) mask
|= QS_PAINT
;
811 else mask
= QS_MOUSE
| QS_KEY
| QS_POSTMESSAGE
| QS_TIMER
| QS_PAINT
;
815 msgQueue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) );
816 if (!msgQueue
) return FALSE
;
818 /* First handle a message put by SendMessage() */
819 if (msgQueue
->status
& QS_SENDMESSAGE
)
821 if (!hwnd
|| (msgQueue
->hWnd
== hwnd
))
823 if ((!first
&& !last
) ||
824 ((msgQueue
->msg
>= first
) && (msgQueue
->msg
<= last
)))
826 msg
->hwnd
= msgQueue
->hWnd
;
827 msg
->message
= msgQueue
->msg
;
828 msg
->wParam
= msgQueue
->wParam
;
829 msg
->lParam
= msgQueue
->lParam
;
830 if (flags
& PM_REMOVE
) msgQueue
->status
&= ~QS_SENDMESSAGE
;
836 /* Now find a normal message */
837 pos
= MSG_FindMsg( msgQueue
, hwnd
, first
, last
);
840 QMSG
*qmsg
= &msgQueue
->messages
[pos
];
842 msgQueue
->GetMessageTimeVal
= msg
->time
;
843 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
844 msgQueue
->GetMessageExtraInfoVal
= qmsg
->extraInfo
;
846 if (flags
& PM_REMOVE
) MSG_RemoveMsg( msgQueue
, pos
);
850 /* Now find a hardware event */
851 if (MSG_PeekHardwareMsg( msg
, hwnd
, first
, last
, flags
& PM_REMOVE
))
854 msgQueue
->GetMessageTimeVal
= msg
->time
;
855 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
856 msgQueue
->GetMessageExtraInfoVal
= 0; /* Always 0 for now */
860 /* Now handle a WM_QUIT message */
861 if (msgQueue
->wPostQMsg
)
864 msg
->message
= WM_QUIT
;
865 msg
->wParam
= msgQueue
->wExitCode
;
870 /* Now find a WM_PAINT message */
871 if ((msgQueue
->status
& QS_PAINT
) && (mask
& QS_PAINT
))
873 msg
->hwnd
= WIN_FindWinToRepaint( hwnd
);
874 msg
->message
= WM_PAINT
;
877 if (msg
->hwnd
!= 0) break;
880 /* Finally handle WM_TIMER messages */
881 if ((msgQueue
->status
& QS_TIMER
) && (mask
& QS_TIMER
))
883 if (TIMER_CheckTimer( &nextExp
, msg
, hwnd
, flags
& PM_REMOVE
))
884 break; /* Got a timer msg */
886 else nextExp
= -1; /* No timeout needed */
890 /* Wait until something happens */
893 if (!MSG_WaitXEvent( 0 )) return FALSE
; /* No pending event */
895 else /* Wait for an event, then restart the loop */
896 MSG_WaitXEvent( nextExp
);
899 /* We got a message */
900 if (peek
) return TRUE
;
901 else return (msg
->message
!= WM_QUIT
);
905 /***********************************************************************
906 * MSG_InternalGetMessage
908 * GetMessage() function for internal use. Behave like GetMessage(),
909 * but also call message filters and optionally send WM_ENTERIDLE messages.
910 * 'hwnd' must be the handle of the dialog or menu window.
911 * 'code' is the message filter value (MSGF_??? codes).
913 BOOL
MSG_InternalGetMessage( SEGPTR msg
, HWND hwnd
, HWND hwndOwner
, short code
,
914 WORD flags
, BOOL sendIdle
)
920 if (!MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
921 0, 0, 0, flags
, TRUE
))
923 /* No message present -> send ENTERIDLE and wait */
924 SendMessage( hwndOwner
, WM_ENTERIDLE
, code
, (LPARAM
)hwnd
);
925 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
926 0, 0, 0, flags
, FALSE
);
929 else /* Always wait for a message */
930 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
931 0, 0, 0, flags
, FALSE
);
933 if (!CallMsgFilter( msg
, code
))
934 return (((MSG
*)PTR_SEG_TO_LIN(msg
))->message
!= WM_QUIT
);
936 /* Message filtered -> remove it from the queue */
937 /* if it's still there. */
938 if (!(flags
& PM_REMOVE
))
939 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
940 0, 0, 0, PM_REMOVE
, TRUE
);
945 /***********************************************************************
946 * PeekMessage (USER.109)
948 BOOL
PeekMessage( LPMSG msg
, HWND hwnd
, WORD first
, WORD last
, WORD flags
)
950 return MSG_PeekMessage( msg
, hwnd
, first
, last
, flags
, TRUE
);
954 /***********************************************************************
955 * GetMessage (USER.108)
957 BOOL
GetMessage( SEGPTR msg
, HWND hwnd
, UINT first
, UINT last
)
959 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
960 hwnd
, first
, last
, PM_REMOVE
, FALSE
);
961 HOOK_CallHooks( WH_GETMESSAGE
, HC_ACTION
, 0, (LPARAM
)msg
);
962 return (((MSG
*)PTR_SEG_TO_LIN(msg
))->message
!= WM_QUIT
);
967 /***********************************************************************
968 * PostMessage (USER.110)
970 BOOL
PostMessage( HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
976 msg
.message
= message
;
979 msg
.time
= GetTickCount();
984 if (DDE_PostMessage(&msg
))
986 #endif /* CONFIG_IPC */
988 if (hwnd
== HWND_BROADCAST
) {
989 dprintf_msg(stddeb
,"PostMessage // HWND_BROADCAST !\n");
990 hwnd
= GetTopWindow(GetDesktopWindow());
992 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) break;
993 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
) {
994 dprintf_msg(stddeb
,"BROADCAST Message to hWnd="NPFMT
" m=%04X w=%04X l=%08lX !\n",
995 hwnd
, message
, wParam
, lParam
);
996 PostMessage(hwnd
, message
, wParam
, lParam
);
998 hwnd
= wndPtr
->hwndNext
;
1000 dprintf_msg(stddeb
,"PostMessage // End of HWND_BROADCAST !\n");
1004 wndPtr
= WIN_FindWndPtr( hwnd
);
1005 if (!wndPtr
|| !wndPtr
->hmemTaskQ
) return FALSE
;
1007 return MSG_AddMsg( wndPtr
->hmemTaskQ
, &msg
, 0 );
1010 /***********************************************************************
1011 * PostAppMessage (USER.116)
1013 BOOL
PostAppMessage( HTASK hTask
, WORD message
, WORD wParam
, LONG lParam
)
1017 if (GetTaskQueue(hTask
) == 0) return FALSE
;
1019 msg
.message
= message
;
1020 msg
.wParam
= wParam
;
1021 msg
.lParam
= lParam
;
1022 msg
.time
= GetTickCount();
1026 return MSG_AddMsg( GetTaskQueue(hTask
), &msg
, 0 );
1030 /***********************************************************************
1031 * SendMessage (USER.111)
1033 LRESULT
SendMessage( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1043 } msgstruct
= { lParam
, wParam
, msg
, hwnd
};
1046 MSG DDE_msg
= { hwnd
, msg
, wParam
, lParam
};
1047 if (DDE_SendMessage(&DDE_msg
)) return TRUE
;
1048 #endif /* CONFIG_IPC */
1050 if (hwnd
== HWND_BROADCAST
)
1052 dprintf_msg(stddeb
,"SendMessage // HWND_BROADCAST !\n");
1053 hwnd
= GetTopWindow(GetDesktopWindow());
1056 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) break;
1057 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
1059 dprintf_msg(stddeb
,"BROADCAST Message to hWnd="NPFMT
" m=%04X w=%04lX l=%08lX !\n",
1060 hwnd
, msg
, (DWORD
)wParam
, lParam
);
1061 ret
|= SendMessage( hwnd
, msg
, wParam
, lParam
);
1063 hwnd
= wndPtr
->hwndNext
;
1065 dprintf_msg(stddeb
,"SendMessage // End of HWND_BROADCAST !\n");
1069 EnterSpyMessage(SPY_SENDMESSAGE
, hwnd
, msg
, wParam
, lParam
);
1071 HOOK_CallHooks( 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 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1147 return CallWndProc( (WNDPROC
)msg
->lParam
, ds
, msg
->hwnd
,
1148 msg
->message
, msg
->wParam
, GetTickCount() );
1152 if (!msg
->hwnd
) return 0;
1153 if (!(wndPtr
= WIN_FindWndPtr( msg
->hwnd
))) return 0;
1154 if (!wndPtr
->lpfnWndProc
) return 0;
1155 painting
= (msg
->message
== WM_PAINT
);
1156 if (painting
) wndPtr
->flags
|= WIN_NEEDS_BEGINPAINT
;
1157 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1158 retval
= CallWindowProc( wndPtr
->lpfnWndProc
, msg
->hwnd
, msg
->message
,
1159 msg
->wParam
, msg
->lParam
);
1160 if (painting
&& IsWindow(msg
->hwnd
) &&
1161 (wndPtr
->flags
& WIN_NEEDS_BEGINPAINT
))
1163 fprintf(stderr
, "BeginPaint not called on WM_PAINT for hwnd "NPFMT
"!\n",
1165 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
1171 /***********************************************************************
1172 * GetMessagePos (USER.119)
1174 DWORD
GetMessagePos(void)
1176 MESSAGEQUEUE
*queue
;
1178 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
1179 return queue
->GetMessagePosVal
;
1183 /***********************************************************************
1184 * GetMessageTime (USER.120)
1186 LONG
GetMessageTime(void)
1188 MESSAGEQUEUE
*queue
;
1190 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
1191 return queue
->GetMessageTimeVal
;
1195 /***********************************************************************
1196 * GetMessageExtraInfo (USER.288)
1198 LONG
GetMessageExtraInfo(void)
1200 MESSAGEQUEUE
*queue
;
1202 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
1203 return queue
->GetMessageExtraInfoVal
;
1207 /***********************************************************************
1208 * RegisterWindowMessage (USER.118)
1210 WORD
RegisterWindowMessage( SEGPTR str
)
1212 dprintf_msg(stddeb
, "RegisterWindowMessage: '%08lx'\n", str
);
1213 return GlobalAddAtom( str
);
1217 /***********************************************************************
1218 * GetTickCount (USER.13) (KERNEL32.299)
1220 DWORD
GetTickCount(void)
1223 gettimeofday( &t
, NULL
);
1224 return (t
.tv_sec
* 1000) + (t
.tv_usec
/ 1000);
1227 /***********************************************************************
1228 * GetCurrentTime (effectively identical to GetTickCount)
1230 DWORD
GetCurrentTime(void)
1232 return GetTickCount();
1235 /***********************************************************************
1236 * InSendMessage (USER.192
1238 * According to the book, this should return true iff the current message
1239 * was send from another application. In that case, the application should
1240 * invoke ReplyMessage before calling message relevant API.
1241 * Currently, Wine will always return FALSE, as there is no other app.
1243 BOOL
InSendMessage()