Release 941017
[wine.git] / windows / message.c
blob137ffe083e337e6258d0069444b928898ec8a99f
1 /*
2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 /*
8 * This code assumes that there is only one Windows task (hence
9 * one message queue).
12 static char Copyright[] = "Copyright Alexandre Julliard, 1993, 1994";
14 #include <stdlib.h>
15 #include <sys/time.h>
16 #include <sys/types.h>
18 #include "message.h"
19 #include "win.h"
20 #include "wineopts.h"
21 #include "sysmetrics.h"
22 #include "hook.h"
23 #include "stddebug.h"
24 /* #define DEBUG_MSG /* */
25 /* #undef DEBUG_MSG /* */
26 #include "debug.h"
29 #define HWND_BROADCAST ((HWND)0xffff)
31 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
34 extern BOOL TIMER_CheckTimer( LONG *next, MSG *msg,
35 HWND hwnd, BOOL remove ); /* timer.c */
36 extern void EVENT_ProcessEvent( XEvent *event ); /* event.c */
37 extern void WINPOS_ChangeActiveWindow( HWND hwnd, BOOL mouseMsg ); /*winpos.c*/
38 extern void WIN_SendParentNotify( HWND hwnd, WORD event,
39 LONG lParam ); /* win.c */
41 extern Display * display;
43 /* System message queue (for hardware events) */
44 static HANDLE hmemSysMsgQueue = 0;
45 static MESSAGEQUEUE * sysMsgQueue = NULL;
47 /* Application message queue (should be a list, one queue per task) */
48 static HANDLE hmemAppMsgQueue = 0;
49 static MESSAGEQUEUE * appMsgQueue = NULL;
51 /* Double-click time */
52 static int doubleClickSpeed = 452;
55 /***********************************************************************
56 * MSG_CreateMsgQueue
58 * Create a message queue.
60 static HANDLE MSG_CreateMsgQueue( int size )
62 HANDLE hQueue;
63 MESSAGEQUEUE * msgQueue;
64 int queueSize;
66 queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
67 if (!(hQueue = GlobalAlloc( GMEM_FIXED, queueSize ))) return 0;
68 msgQueue = (MESSAGEQUEUE *) GlobalLock( hQueue );
69 msgQueue->next = 0;
70 msgQueue->hTask = 0;
71 msgQueue->msgSize = sizeof(QMSG);
72 msgQueue->msgCount = 0;
73 msgQueue->nextMessage = 0;
74 msgQueue->nextFreeMessage = 0;
75 msgQueue->queueSize = size;
76 msgQueue->GetMessageTimeVal = 0;
77 msgQueue->GetMessagePosVal = 0;
78 msgQueue->GetMessageExtraInfoVal = 0;
79 msgQueue->lParam = 0;
80 msgQueue->wParam = 0;
81 msgQueue->msg = 0;
82 msgQueue->hWnd = 0;
83 msgQueue->wPostQMsg = 0;
84 msgQueue->wExitCode = 0;
85 msgQueue->InSendMessageHandle = 0;
86 msgQueue->wPaintCount = 0;
87 msgQueue->wTimerCount = 0;
88 msgQueue->tempStatus = 0;
89 msgQueue->status = 0;
90 GlobalUnlock( hQueue );
91 return hQueue;
95 /***********************************************************************
96 * MSG_CreateSysMsgQueue
98 * Create the system message queue, and set the double-click speed.
99 * Must be called only once.
101 BOOL MSG_CreateSysMsgQueue( int size )
103 if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
104 else if (size <= 0) size = 1;
105 if (!(hmemSysMsgQueue = MSG_CreateMsgQueue( size ))) return FALSE;
106 sysMsgQueue = (MESSAGEQUEUE *) GlobalLock( hmemSysMsgQueue );
107 doubleClickSpeed = GetProfileInt( "windows", "DoubleClickSpeed", 452 );
108 return TRUE;
112 /***********************************************************************
113 * MSG_AddMsg
115 * Add a message to the queue. Return FALSE if queue is full.
117 static int MSG_AddMsg( MESSAGEQUEUE * msgQueue, MSG * msg, DWORD extraInfo )
119 int pos;
121 if (!msgQueue) return FALSE;
122 pos = msgQueue->nextFreeMessage;
124 /* Check if queue is full */
125 if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0)) {
126 fprintf(stderr,"MSG_AddMsg // queue is full !\n");
127 return FALSE;
130 /* Store message */
131 msgQueue->messages[pos].msg = *msg;
132 msgQueue->messages[pos].extraInfo = extraInfo;
133 if (pos < msgQueue->queueSize-1) pos++;
134 else pos = 0;
135 msgQueue->nextFreeMessage = pos;
136 msgQueue->msgCount++;
137 msgQueue->status |= QS_POSTMESSAGE;
138 msgQueue->tempStatus |= QS_POSTMESSAGE;
139 return TRUE;
143 /***********************************************************************
144 * MSG_FindMsg
146 * Find a message matching the given parameters. Return -1 if none available.
148 static int MSG_FindMsg(MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last)
150 int i, pos = msgQueue->nextMessage;
152 if (!msgQueue->msgCount) return -1;
153 if (!hwnd && !first && !last) return pos;
155 for (i = 0; i < msgQueue->msgCount; i++)
157 MSG * msg = &msgQueue->messages[pos].msg;
159 if (!hwnd || (msg->hwnd == hwnd))
161 if (!first && !last) return pos;
162 if ((msg->message >= first) && (msg->message <= last)) return pos;
164 if (pos < msgQueue->queueSize-1) pos++;
165 else pos = 0;
167 return -1;
171 /***********************************************************************
172 * MSG_RemoveMsg
174 * Remove a message from the queue (pos must be a valid position).
176 static void MSG_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
178 if (pos >= msgQueue->nextMessage)
180 for ( ; pos > msgQueue->nextMessage; pos--)
181 msgQueue->messages[pos] = msgQueue->messages[pos-1];
182 msgQueue->nextMessage++;
183 if (msgQueue->nextMessage >= msgQueue->queueSize)
184 msgQueue->nextMessage = 0;
186 else
188 for ( ; pos < msgQueue->nextFreeMessage; pos++)
189 msgQueue->messages[pos] = msgQueue->messages[pos+1];
190 if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
191 else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
193 msgQueue->msgCount--;
194 if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE;
195 msgQueue->tempStatus = 0;
199 /***********************************************************************
200 * MSG_TranslateMouseMsg
202 * Translate an mouse hardware event into a real mouse message.
203 * Return value indicates whether the translated message must be passed
204 * to the user.
205 * Actions performed:
206 * - Find the window for this message.
207 * - Translate button-down messages in double-clicks.
208 * - Send the WM_NCHITTEST message to find where the cursor is.
209 * - Activate the window if needed.
210 * - Translate the message into a non-client message, or translate
211 * the coordinates to client coordinates.
212 * - Send the WM_SETCURSOR message.
214 static BOOL MSG_TranslateMouseMsg( MSG *msg, BOOL remove )
216 BOOL eatMsg = FALSE;
217 LONG hittest_result;
218 static DWORD lastClickTime = 0;
219 static WORD lastClickMsg = 0;
220 static POINT lastClickPos = { 0, 0 };
222 BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
223 (msg->message == WM_RBUTTONDOWN) ||
224 (msg->message == WM_MBUTTONDOWN));
226 /* Find the window */
228 if (GetCapture())
230 msg->hwnd = GetCapture();
231 msg->lParam = MAKELONG( msg->pt.x, msg->pt.y );
232 ScreenToClient( msg->hwnd, (LPPOINT)&msg->lParam );
233 return TRUE; /* No need to further process the message */
235 else msg->hwnd = WindowFromPoint( msg->pt );
237 /* Send the WM_NCHITTEST message */
239 hittest_result = SendMessage( msg->hwnd, WM_NCHITTEST, 0,
240 MAKELONG( msg->pt.x, msg->pt.y ) );
241 while ((hittest_result == HTTRANSPARENT) && (msg->hwnd))
243 msg->hwnd = GetParent(msg->hwnd);
244 if (!msg->hwnd)
245 hittest_result = SendMessage( msg->hwnd, WM_NCHITTEST, 0,
246 MAKELONG( msg->pt.x, msg->pt.y ) );
248 if (!msg->hwnd) msg->hwnd = GetDesktopWindow();
250 /* Send the WM_PARENTNOTIFY message */
252 if (mouseClick) WIN_SendParentNotify( msg->hwnd, msg->message,
253 MAKELONG( msg->pt.x, msg->pt.y ) );
255 /* Activate the window if needed */
257 if (mouseClick)
259 HWND parent, hwndTop = msg->hwnd;
260 while ((parent = GetParent(hwndTop)) != 0) hwndTop = parent;
261 if (hwndTop != GetActiveWindow())
263 LONG ret = SendMessage( msg->hwnd, WM_MOUSEACTIVATE, hwndTop,
264 MAKELONG( hittest_result, msg->message ) );
265 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
266 eatMsg = TRUE;
267 if ((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
269 SetWindowPos( hwndTop, HWND_TOP, 0, 0, 0, 0,
270 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
271 WINPOS_ChangeActiveWindow( hwndTop, TRUE );
276 /* Send the WM_SETCURSOR message */
278 SendMessage( msg->hwnd, WM_SETCURSOR, msg->hwnd,
279 MAKELONG( hittest_result, msg->message ));
280 if (eatMsg) return FALSE;
282 /* Check for double-click */
284 if (mouseClick)
286 BOOL dbl_click = FALSE;
288 if ((msg->message == lastClickMsg) &&
289 (msg->time - lastClickTime < doubleClickSpeed) &&
290 (abs(msg->pt.x - lastClickPos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
291 (abs(msg->pt.y - lastClickPos.y) < SYSMETRICS_CYDOUBLECLK/2))
292 dbl_click = TRUE;
294 if (dbl_click && (hittest_result == HTCLIENT))
296 /* Check whether window wants the double click message. */
297 WND * wndPtr = WIN_FindWndPtr( msg->hwnd );
298 if (!wndPtr || !(WIN_CLASS_STYLE(wndPtr) & CS_DBLCLKS))
299 dbl_click = FALSE;
302 if (dbl_click) switch(msg->message)
304 case WM_LBUTTONDOWN: msg->message = WM_LBUTTONDBLCLK; break;
305 case WM_RBUTTONDOWN: msg->message = WM_RBUTTONDBLCLK; break;
306 case WM_MBUTTONDOWN: msg->message = WM_MBUTTONDBLCLK; break;
309 if (remove)
311 lastClickTime = msg->time;
312 lastClickMsg = msg->message;
313 lastClickPos = msg->pt;
317 /* Build the translated message */
319 msg->lParam = MAKELONG( msg->pt.x, msg->pt.y );
320 if (hittest_result == HTCLIENT)
322 ScreenToClient( msg->hwnd, (LPPOINT)&msg->lParam );
324 else
326 msg->wParam = hittest_result;
327 msg->message += WM_NCLBUTTONDOWN - WM_LBUTTONDOWN;
330 return TRUE;
334 /***********************************************************************
335 * MSG_TranslateKeyboardMsg
337 * Translate an keyboard hardware event into a real message.
338 * Return value indicates whether the translated message must be passed
339 * to the user.
341 static BOOL MSG_TranslateKeyboardMsg( MSG *msg )
343 /* Should check Ctrl-Esc and PrintScreen here */
345 msg->hwnd = GetFocus();
346 if (!msg->hwnd)
348 /* Send the message to the active window instead, */
349 /* translating messages to their WM_SYS equivalent */
350 msg->hwnd = GetActiveWindow();
351 msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
353 return TRUE;
357 /***********************************************************************
358 * MSG_PeekHardwareMsg
360 * Peek for a hardware message matching the hwnd and message filters.
362 static BOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, WORD first, WORD last,
363 BOOL remove )
365 int i, pos = sysMsgQueue->nextMessage;
367 for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
369 *msg = sysMsgQueue->messages[pos].msg;
371 /* Translate message */
373 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
375 if (!MSG_TranslateMouseMsg( msg, remove )) continue;
377 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
379 if (!MSG_TranslateKeyboardMsg( msg )) continue;
381 else continue; /* Should never happen */
383 /* Check message against filters */
385 if (hwnd && (msg->hwnd != hwnd)) continue;
386 if ((first || last) &&
387 ((msg->message < first) || (msg->message > last))) continue;
388 if (remove) MSG_RemoveMsg( sysMsgQueue, pos );
389 return TRUE;
391 return FALSE;
395 /**********************************************************************
396 * SetDoubleClickTime (USER.20)
398 void SetDoubleClickTime( WORD interval )
400 if (interval == 0)
401 doubleClickSpeed = 500;
402 else
403 doubleClickSpeed = interval;
407 /**********************************************************************
408 * GetDoubleClickTime (USER.21)
410 WORD GetDoubleClickTime()
412 return (WORD)doubleClickSpeed;
416 /***********************************************************************
417 * MSG_IncPaintCount
419 void MSG_IncPaintCount( HANDLE hQueue )
421 if (hQueue != hmemAppMsgQueue) return;
422 appMsgQueue->wPaintCount++;
423 appMsgQueue->status |= QS_PAINT;
424 appMsgQueue->tempStatus |= QS_PAINT;
428 /***********************************************************************
429 * MSG_DecPaintCount
431 void MSG_DecPaintCount( HANDLE hQueue )
433 if (hQueue != hmemAppMsgQueue) return;
434 appMsgQueue->wPaintCount--;
435 if (!appMsgQueue->wPaintCount) appMsgQueue->status &= ~QS_PAINT;
439 /***********************************************************************
440 * MSG_IncTimerCount
442 void MSG_IncTimerCount( HANDLE hQueue )
444 if (hQueue != hmemAppMsgQueue) return;
445 appMsgQueue->wTimerCount++;
446 appMsgQueue->status |= QS_TIMER;
447 appMsgQueue->tempStatus |= QS_TIMER;
451 /***********************************************************************
452 * MSG_DecTimerCount
454 void MSG_DecTimerCount( HANDLE hQueue )
456 if (hQueue != hmemAppMsgQueue) return;
457 appMsgQueue->wTimerCount--;
458 if (!appMsgQueue->wTimerCount) appMsgQueue->status &= ~QS_TIMER;
462 /***********************************************************************
463 * hardware_event
465 * Add an event to the system message queue.
466 * Note: the position is relative to the desktop window.
468 void hardware_event( WORD message, WORD wParam, LONG lParam,
469 int xPos, int yPos, DWORD time, DWORD extraInfo )
471 MSG *msg;
472 int pos;
474 if (!sysMsgQueue) return;
475 pos = sysMsgQueue->nextFreeMessage;
477 /* Merge with previous event if possible */
479 if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
481 if (pos > 0) pos--;
482 else pos = sysMsgQueue->queueSize - 1;
483 msg = &sysMsgQueue->messages[pos].msg;
484 if ((msg->message == message) && (msg->wParam == wParam))
485 sysMsgQueue->msgCount--; /* Merge events */
486 else
487 pos = sysMsgQueue->nextFreeMessage; /* Don't merge */
490 /* Check if queue is full */
492 if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
494 /* Queue is full, beep (but not on every mouse motion...) */
495 if (message != WM_MOUSEMOVE) MessageBeep(0);
496 return;
499 /* Store message */
501 msg = &sysMsgQueue->messages[pos].msg;
502 msg->hwnd = 0;
503 msg->message = message;
504 msg->wParam = wParam;
505 msg->lParam = lParam;
506 msg->time = time;
507 msg->pt.x = xPos & 0xffff;
508 msg->pt.y = yPos & 0xffff;
509 sysMsgQueue->messages[pos].extraInfo = extraInfo;
510 if (pos < sysMsgQueue->queueSize - 1) pos++;
511 else pos = 0;
512 sysMsgQueue->nextFreeMessage = pos;
513 sysMsgQueue->msgCount++;
517 /***********************************************************************
518 * MSG_GetHardwareMessage
520 * Like GetMessage(), but only return mouse and keyboard events.
521 * Used internally for window moving and resizing. Mouse messages
522 * are not translated.
523 * Warning: msg->hwnd is always 0.
525 BOOL MSG_GetHardwareMessage( LPMSG msg )
527 int pos;
528 XEvent event;
530 while(1)
532 if ((pos = MSG_FindMsg( sysMsgQueue, 0, 0, 0 )) != -1)
534 *msg = sysMsgQueue->messages[pos].msg;
535 MSG_RemoveMsg( sysMsgQueue, pos );
536 break;
538 XNextEvent( display, &event );
539 EVENT_ProcessEvent( &event );
541 return TRUE;
545 /***********************************************************************
546 * SetTaskQueue (KERNEL.34)
548 WORD SetTaskQueue( HANDLE hTask, HANDLE hQueue )
550 HANDLE prev = hmemAppMsgQueue;
551 hmemAppMsgQueue = hQueue;
552 return prev;
556 /***********************************************************************
557 * GetTaskQueue (KERNEL.35)
559 WORD GetTaskQueue( HANDLE hTask )
561 return hmemAppMsgQueue;
565 /***********************************************************************
566 * SetMessageQueue (USER.266)
568 BOOL SetMessageQueue( int size )
570 HANDLE hQueue;
572 if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
574 /* Free the old message queue */
575 if ((hQueue = GetTaskQueue(0)) != 0)
577 GlobalUnlock( hQueue );
578 GlobalFree( hQueue );
581 if (!(hQueue = MSG_CreateMsgQueue( size ))) return FALSE;
582 SetTaskQueue( 0, hQueue );
583 appMsgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue );
584 return TRUE;
588 /***********************************************************************
589 * PostQuitMessage (USER.6)
591 void PostQuitMessage( int exitCode )
593 if (!appMsgQueue) return;
594 appMsgQueue->wPostQMsg = TRUE;
595 appMsgQueue->wExitCode = exitCode;
599 /***********************************************************************
600 * GetQueueStatus (USER.334)
602 DWORD GetQueueStatus( int flags )
604 unsigned long ret = (appMsgQueue->status << 16) | appMsgQueue->tempStatus;
605 appMsgQueue->tempStatus = 0;
606 return ret & ((flags << 16) | flags);
610 /***********************************************************************
611 * GetInputState (USER.335)
613 BOOL GetInputState()
615 return appMsgQueue->status & (QS_KEY | QS_MOUSEBUTTON);
619 /***********************************************************************
620 * MSG_Synchronize
622 * Synchronize with the X server. Should not be used too often.
624 void MSG_Synchronize()
626 XEvent event;
628 XSync( display, False );
629 while (XPending( display ))
631 XNextEvent( display, &event );
632 EVENT_ProcessEvent( &event );
637 /***********************************************************************
638 * MSG_WaitXEvent
640 * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
641 * Return TRUE if an event is pending, FALSE on timeout or error
642 * (for instance lost connection with the server).
644 static BOOL MSG_WaitXEvent( LONG maxWait )
646 fd_set read_set;
647 struct timeval timeout;
648 XEvent event;
649 int fd = ConnectionNumber(display);
651 if (!XPending(display) && (maxWait != -1))
653 FD_ZERO( &read_set );
654 FD_SET( fd, &read_set );
655 timeout.tv_sec = maxWait / 1000;
656 timeout.tv_usec = (maxWait % 1000) * 1000;
657 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
658 return FALSE; /* Timeout or error */
661 /* Process the event (and possibly others that occurred in the meantime) */
664 XNextEvent( display, &event );
665 EVENT_ProcessEvent( &event );
667 while (XPending( display ));
668 return TRUE;
672 /***********************************************************************
673 * MSG_PeekMessage
675 static BOOL MSG_PeekMessage( MESSAGEQUEUE * msgQueue, LPMSG msg, HWND hwnd,
676 WORD first, WORD last, WORD flags, BOOL peek )
678 int pos, mask;
679 LONG nextExp; /* Next timer expiration time */
681 if (first || last)
683 mask = QS_POSTMESSAGE; /* Always selectioned */
684 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
685 if ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) mask |= QS_MOUSE;
686 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
687 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
688 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
690 else mask = QS_MOUSE | QS_KEY | QS_POSTMESSAGE | QS_TIMER | QS_PAINT;
692 while(1)
694 /* First handle a message put by SendMessage() */
695 if (msgQueue->status & QS_SENDMESSAGE)
697 if (!hwnd || (msgQueue->hWnd == hwnd))
699 if ((!first && !last) ||
700 ((msgQueue->msg >= first) && (msgQueue->msg <= last)))
702 msg->hwnd = msgQueue->hWnd;
703 msg->message = msgQueue->msg;
704 msg->wParam = msgQueue->wParam;
705 msg->lParam = msgQueue->lParam;
706 if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
707 break;
712 /* Now find a normal message */
713 pos = MSG_FindMsg( msgQueue, hwnd, first, last );
714 if (pos != -1)
716 QMSG *qmsg = &msgQueue->messages[pos];
717 *msg = qmsg->msg;
718 msgQueue->GetMessageTimeVal = msg->time;
719 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
720 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
722 if (flags & PM_REMOVE) MSG_RemoveMsg( msgQueue, pos );
723 break;
726 /* Now find a hardware event */
727 if (MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
729 /* Got one */
730 msgQueue->GetMessageTimeVal = msg->time;
731 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
732 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
733 break;
736 /* Now handle a WM_QUIT message */
737 if (msgQueue->wPostQMsg)
739 msg->hwnd = hwnd;
740 msg->message = WM_QUIT;
741 msg->wParam = msgQueue->wExitCode;
742 msg->lParam = 0;
743 break;
746 /* Now find a WM_PAINT message */
747 if ((msgQueue->status & QS_PAINT) && (mask & QS_PAINT))
749 msg->hwnd = WIN_FindWinToRepaint( hwnd );
750 msg->message = WM_PAINT;
751 msg->wParam = 0;
752 msg->lParam = 0;
753 if (msg->hwnd != 0) break;
756 /* Finally handle WM_TIMER messages */
757 if ((msgQueue->status & QS_TIMER) && (mask & QS_TIMER))
759 if (TIMER_CheckTimer( &nextExp, msg, hwnd, flags & PM_REMOVE ))
760 break; /* Got a timer msg */
762 else nextExp = -1; /* No timeout needed */
764 /* Wait until something happens */
765 if (peek)
767 if (!MSG_WaitXEvent( 0 )) return FALSE; /* No pending event */
769 else /* Wait for an event, then restart the loop */
770 MSG_WaitXEvent( nextExp );
773 /* We got a message */
774 if (peek) return TRUE;
775 else return (msg->message != WM_QUIT);
779 /***********************************************************************
780 * MSG_InternalGetMessage
782 * GetMessage() function for internal use. Behave like GetMessage(),
783 * but also call message filters and optionally send WM_ENTERIDLE messages.
784 * 'hwnd' must be the handle of the dialog or menu window.
785 * 'code' is the message filter value (MSGF_??? codes).
787 BOOL MSG_InternalGetMessage( LPMSG msg, HWND hwnd, HWND hwndOwner, short code,
788 WORD flags, BOOL sendIdle )
790 for (;;)
792 if (sendIdle)
794 if (!MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, flags, TRUE ))
796 /* No message present -> send ENTERIDLE and wait */
797 SendMessage( hwndOwner, WM_ENTERIDLE, code, (LPARAM)hwnd );
798 MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, flags, FALSE );
801 else /* Always wait for a message */
802 MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, flags, FALSE );
804 if (!CallMsgFilter( msg, code )) return (msg->message != WM_QUIT);
806 /* Message filtered -> remove it from the queue */
807 /* if it's still there. */
808 if (!(flags & PM_REMOVE))
809 MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, PM_REMOVE, TRUE );
814 /***********************************************************************
815 * PeekMessage (USER.109)
817 BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
819 return MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, flags, TRUE );
823 /***********************************************************************
824 * GetMessage (USER.108)
826 BOOL GetMessage( LPMSG msg, HWND hwnd, WORD first, WORD last )
828 MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, PM_REMOVE, FALSE );
829 CALL_SYSTEM_HOOK( WH_GETMESSAGE, 0, 0, (LPARAM)msg );
830 CALL_TASK_HOOK( WH_GETMESSAGE, 0, 0, (LPARAM)msg );
831 return (msg->message != WM_QUIT);
836 /***********************************************************************
837 * PostMessage (USER.110)
839 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
841 MSG msg;
842 WND *wndPtr;
844 if (hwnd == HWND_BROADCAST) {
845 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
846 hwnd = GetTopWindow(GetDesktopWindow());
847 while (hwnd) {
848 if (!(wndPtr = WIN_FindWndPtr(hwnd))) break;
849 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) {
850 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04X m=%04X w=%04X l=%08X !\n",
851 hwnd, message, wParam, lParam);
852 PostMessage(hwnd, message, wParam, lParam);
854 /* {
855 char str[128];
856 GetWindowText(hwnd, str, sizeof(str));
857 printf("BROADCAST GetWindowText()='%s' !\n", str);
859 hwnd = wndPtr->hwndNext;
861 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
862 return TRUE;
865 wndPtr = WIN_FindWndPtr( hwnd );
866 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
867 msg.hwnd = hwnd;
868 msg.message = message;
869 msg.wParam = wParam;
870 msg.lParam = lParam;
871 msg.time = GetTickCount();
872 msg.pt.x = 0;
873 msg.pt.y = 0;
875 return MSG_AddMsg( appMsgQueue, &msg, 0 );
879 /***********************************************************************
880 * SendMessage (USER.111)
882 LONG SendMessage( HWND hwnd, WORD msg, WORD wParam, LONG lParam )
884 WND * wndPtr;
886 wndPtr = WIN_FindWndPtr( hwnd );
887 if (!wndPtr) return 0;
888 return CallWindowProc( wndPtr->lpfnWndProc, hwnd, msg, wParam, lParam );
892 /***********************************************************************
893 * WaitMessage (USER.112)
895 void WaitMessage( void )
897 MSG msg;
898 LONG nextExp = -1; /* Next timer expiration time */
900 if ((appMsgQueue->wPostQMsg) ||
901 (appMsgQueue->status & (QS_SENDMESSAGE | QS_PAINT)) ||
902 (appMsgQueue->msgCount) || (sysMsgQueue->msgCount) )
903 return;
904 if ((appMsgQueue->status & QS_TIMER) &&
905 TIMER_CheckTimer( &nextExp, &msg, 0, FALSE))
906 return;
907 MSG_WaitXEvent( nextExp );
911 /***********************************************************************
912 * TranslateMessage (USER.113)
914 BOOL TranslateMessage( LPMSG msg )
916 int message = msg->message;
918 if ((message == WM_KEYDOWN) || (message == WM_KEYUP) ||
919 (message == WM_SYSKEYDOWN) || (message == WM_SYSKEYUP))
921 dprintf_msg(stddeb, "Translating key message\n" );
922 return TRUE;
924 return FALSE;
928 /***********************************************************************
929 * DispatchMessage (USER.114)
931 LONG DispatchMessage( LPMSG msg )
933 WND * wndPtr;
934 LONG retval;
935 int painting;
937 dprintf_msg(stddeb, "Dispatch message hwnd=%08x msg=0x%x w=%d l=%d time=%u pt=%d,%d\n",
938 msg->hwnd, msg->message, msg->wParam, msg->lParam,
939 msg->time, msg->pt.x, msg->pt.y );
941 /* Process timer messages */
942 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
944 if (msg->lParam)
945 return CallWindowProc( (WNDPROC)msg->lParam, msg->hwnd,
946 msg->message, msg->wParam, GetTickCount() );
949 if (!msg->hwnd) return 0;
950 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
951 if (!wndPtr->lpfnWndProc) return 0;
952 painting = (msg->message == WM_PAINT);
953 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
954 retval = CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message,
955 msg->wParam, msg->lParam );
956 if (painting && IsWindow(msg->hwnd) &&
957 (wndPtr->flags & WIN_NEEDS_BEGINPAINT))
959 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %d!\n",
960 msg->hwnd);
961 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
963 return retval;
967 /***********************************************************************
968 * GetMessagePos (USER.119)
970 DWORD GetMessagePos(void)
972 return appMsgQueue->GetMessagePosVal;
976 /***********************************************************************
977 * GetMessageTime (USER.120)
979 LONG GetMessageTime(void)
981 return appMsgQueue->GetMessageTimeVal;
985 /***********************************************************************
986 * GetMessageExtraInfo (USER.288)
988 LONG GetMessageExtraInfo(void)
990 return appMsgQueue->GetMessageExtraInfoVal;
994 /***********************************************************************
995 * RegisterWindowMessage (USER.118)
997 WORD RegisterWindowMessage( LPCSTR str )
999 WORD wRet;
1000 dprintf_msg(stddeb, "RegisterWindowMessage: '%s'\n", str );
1001 wRet = GlobalAddAtom( str );
1002 return wRet;
1006 /***********************************************************************
1007 * GetTickCount (USER.13)
1009 DWORD GetTickCount()
1011 struct timeval t;
1012 gettimeofday( &t, NULL );
1013 return (t.tv_sec * 1000) + (t.tv_usec / 1000);