Release 950122
[wine/multimedia.git] / windows / message.c
blob2fd510e3350160a10afc976d1855b0ca4728c425
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 #include <stdlib.h>
13 #include <sys/time.h>
14 #include <sys/types.h>
16 #include "message.h"
17 #include "win.h"
18 #include "gdi.h"
19 #include "wineopts.h"
20 #include "sysmetrics.h"
21 #include "hook.h"
22 #include "win.h"
23 #include "event.h"
24 #include "winpos.h"
25 #include "stddebug.h"
26 /* #define DEBUG_MSG */
27 #include "debug.h"
30 #define HWND_BROADCAST ((HWND)0xffff)
32 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
35 extern BOOL TIMER_CheckTimer( LONG *next, MSG *msg,
36 HWND hwnd, BOOL remove ); /* timer.c */
38 /* System message queue (for hardware events) */
39 static HANDLE hmemSysMsgQueue = 0;
40 static MESSAGEQUEUE * sysMsgQueue = NULL;
42 /* Application message queue (should be a list, one queue per task) */
43 static HANDLE hmemAppMsgQueue = 0;
44 static MESSAGEQUEUE * appMsgQueue = NULL;
46 /* Double-click time */
47 static int doubleClickSpeed = 452;
50 /***********************************************************************
51 * MSG_CreateMsgQueue
53 * Create a message queue.
55 static HANDLE MSG_CreateMsgQueue( int size )
57 HANDLE hQueue;
58 MESSAGEQUEUE * msgQueue;
59 int queueSize;
61 queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
62 if (!(hQueue = GlobalAlloc( GMEM_FIXED, queueSize ))) return 0;
63 msgQueue = (MESSAGEQUEUE *) GlobalLock( hQueue );
64 msgQueue->next = 0;
65 msgQueue->hTask = 0;
66 msgQueue->msgSize = sizeof(QMSG);
67 msgQueue->msgCount = 0;
68 msgQueue->nextMessage = 0;
69 msgQueue->nextFreeMessage = 0;
70 msgQueue->queueSize = size;
71 msgQueue->GetMessageTimeVal = 0;
72 msgQueue->GetMessagePosVal = 0;
73 msgQueue->GetMessageExtraInfoVal = 0;
74 msgQueue->lParam = 0;
75 msgQueue->wParam = 0;
76 msgQueue->msg = 0;
77 msgQueue->hWnd = 0;
78 msgQueue->wPostQMsg = 0;
79 msgQueue->wExitCode = 0;
80 msgQueue->InSendMessageHandle = 0;
81 msgQueue->wPaintCount = 0;
82 msgQueue->wTimerCount = 0;
83 msgQueue->tempStatus = 0;
84 msgQueue->status = 0;
85 GlobalUnlock( hQueue );
86 return hQueue;
90 /***********************************************************************
91 * MSG_CreateSysMsgQueue
93 * Create the system message queue, and set the double-click speed.
94 * Must be called only once.
96 BOOL MSG_CreateSysMsgQueue( int size )
98 if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
99 else if (size <= 0) size = 1;
100 if (!(hmemSysMsgQueue = MSG_CreateMsgQueue( size ))) return FALSE;
101 sysMsgQueue = (MESSAGEQUEUE *) GlobalLock( hmemSysMsgQueue );
102 doubleClickSpeed = GetProfileInt( "windows", "DoubleClickSpeed", 452 );
103 return TRUE;
107 /***********************************************************************
108 * MSG_AddMsg
110 * Add a message to the queue. Return FALSE if queue is full.
112 static int MSG_AddMsg( MESSAGEQUEUE * msgQueue, MSG * msg, DWORD extraInfo )
114 int pos;
116 if (!msgQueue) return FALSE;
117 pos = msgQueue->nextFreeMessage;
119 /* Check if queue is full */
120 if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0)) {
121 fprintf(stderr,"MSG_AddMsg // queue is full !\n");
122 return FALSE;
125 /* Store message */
126 msgQueue->messages[pos].msg = *msg;
127 msgQueue->messages[pos].extraInfo = extraInfo;
128 if (pos < msgQueue->queueSize-1) pos++;
129 else pos = 0;
130 msgQueue->nextFreeMessage = pos;
131 msgQueue->msgCount++;
132 msgQueue->status |= QS_POSTMESSAGE;
133 msgQueue->tempStatus |= QS_POSTMESSAGE;
134 return TRUE;
138 /***********************************************************************
139 * MSG_FindMsg
141 * Find a message matching the given parameters. Return -1 if none available.
143 static int MSG_FindMsg(MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last)
145 int i, pos = msgQueue->nextMessage;
147 if (!msgQueue->msgCount) return -1;
148 if (!hwnd && !first && !last) return pos;
150 for (i = 0; i < msgQueue->msgCount; i++)
152 MSG * msg = &msgQueue->messages[pos].msg;
154 if (!hwnd || (msg->hwnd == hwnd))
156 if (!first && !last) return pos;
157 if ((msg->message >= first) && (msg->message <= last)) return pos;
159 if (pos < msgQueue->queueSize-1) pos++;
160 else pos = 0;
162 return -1;
166 /***********************************************************************
167 * MSG_RemoveMsg
169 * Remove a message from the queue (pos must be a valid position).
171 static void MSG_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
173 if (pos >= msgQueue->nextMessage)
175 for ( ; pos > msgQueue->nextMessage; pos--)
176 msgQueue->messages[pos] = msgQueue->messages[pos-1];
177 msgQueue->nextMessage++;
178 if (msgQueue->nextMessage >= msgQueue->queueSize)
179 msgQueue->nextMessage = 0;
181 else
183 for ( ; pos < msgQueue->nextFreeMessage; pos++)
184 msgQueue->messages[pos] = msgQueue->messages[pos+1];
185 if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
186 else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
188 msgQueue->msgCount--;
189 if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE;
190 msgQueue->tempStatus = 0;
194 /***********************************************************************
195 * MSG_TranslateMouseMsg
197 * Translate an mouse hardware event into a real mouse message.
198 * Return value indicates whether the translated message must be passed
199 * to the user.
200 * Actions performed:
201 * - Find the window for this message.
202 * - Translate button-down messages in double-clicks.
203 * - Send the WM_NCHITTEST message to find where the cursor is.
204 * - Activate the window if needed.
205 * - Translate the message into a non-client message, or translate
206 * the coordinates to client coordinates.
207 * - Send the WM_SETCURSOR message.
209 static BOOL MSG_TranslateMouseMsg( MSG *msg, BOOL remove )
211 BOOL eatMsg = FALSE;
212 INT hittest_result;
213 static DWORD lastClickTime = 0;
214 static WORD lastClickMsg = 0;
215 static POINT lastClickPos = { 0, 0 };
217 BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
218 (msg->message == WM_RBUTTONDOWN) ||
219 (msg->message == WM_MBUTTONDOWN));
221 /* Find the window */
223 if (GetCapture())
225 msg->hwnd = GetCapture();
226 msg->lParam = MAKELONG( msg->pt.x, msg->pt.y );
227 ScreenToClient( msg->hwnd, (LPPOINT)&msg->lParam );
228 return TRUE; /* No need to further process the message */
230 else msg->hwnd = WindowFromPoint( msg->pt );
232 /* Send the WM_NCHITTEST message */
234 hittest_result = (INT)SendMessage( msg->hwnd, WM_NCHITTEST, 0,
235 MAKELONG( msg->pt.x, msg->pt.y ) );
236 while ((hittest_result == HTTRANSPARENT) && (msg->hwnd))
238 msg->hwnd = WINPOS_NextWindowFromPoint( msg->hwnd, msg->pt );
239 if (msg->hwnd)
240 hittest_result = (INT)SendMessage( msg->hwnd, WM_NCHITTEST, 0,
241 MAKELONG( msg->pt.x, msg->pt.y ));
243 if (!msg->hwnd) msg->hwnd = GetDesktopWindow();
245 /* Send the WM_PARENTNOTIFY message */
247 if (mouseClick) WIN_SendParentNotify( msg->hwnd, msg->message,
248 MAKELONG( msg->pt.x, msg->pt.y ) );
250 /* Activate the window if needed */
252 if (mouseClick)
254 HWND parent, hwndTop = msg->hwnd;
255 while ((parent = GetParent(hwndTop)) != 0) hwndTop = parent;
256 if (hwndTop != GetActiveWindow())
258 LONG ret = SendMessage( msg->hwnd, WM_MOUSEACTIVATE, hwndTop,
259 MAKELONG( hittest_result, msg->message ) );
260 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
261 eatMsg = TRUE;
262 if ((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
264 SetWindowPos( hwndTop, HWND_TOP, 0, 0, 0, 0,
265 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
266 WINPOS_ChangeActiveWindow( hwndTop, TRUE );
271 /* Send the WM_SETCURSOR message */
273 SendMessage( msg->hwnd, WM_SETCURSOR, msg->hwnd,
274 MAKELONG( hittest_result, msg->message ));
275 if (eatMsg) return FALSE;
277 /* Check for double-click */
279 if (mouseClick)
281 BOOL dbl_click = FALSE;
283 if ((msg->message == lastClickMsg) &&
284 (msg->time - lastClickTime < doubleClickSpeed) &&
285 (abs(msg->pt.x - lastClickPos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
286 (abs(msg->pt.y - lastClickPos.y) < SYSMETRICS_CYDOUBLECLK/2))
287 dbl_click = TRUE;
289 if (dbl_click && (hittest_result == HTCLIENT))
291 /* Check whether window wants the double click message. */
292 WND * wndPtr = WIN_FindWndPtr( msg->hwnd );
293 if (!wndPtr || !(WIN_CLASS_STYLE(wndPtr) & CS_DBLCLKS))
294 dbl_click = FALSE;
297 if (dbl_click) switch(msg->message)
299 case WM_LBUTTONDOWN: msg->message = WM_LBUTTONDBLCLK; break;
300 case WM_RBUTTONDOWN: msg->message = WM_RBUTTONDBLCLK; break;
301 case WM_MBUTTONDOWN: msg->message = WM_MBUTTONDBLCLK; break;
304 if (remove)
306 lastClickTime = msg->time;
307 lastClickMsg = msg->message;
308 lastClickPos = msg->pt;
312 /* Build the translated message */
314 msg->lParam = MAKELONG( msg->pt.x, msg->pt.y );
315 if (hittest_result == HTCLIENT)
317 ScreenToClient( msg->hwnd, (LPPOINT)&msg->lParam );
319 else
321 msg->wParam = hittest_result;
322 msg->message += WM_NCLBUTTONDOWN - WM_LBUTTONDOWN;
325 return TRUE;
329 /***********************************************************************
330 * MSG_TranslateKeyboardMsg
332 * Translate an keyboard hardware event into a real message.
333 * Return value indicates whether the translated message must be passed
334 * to the user.
336 static BOOL MSG_TranslateKeyboardMsg( MSG *msg )
338 /* Should check Ctrl-Esc and PrintScreen here */
340 msg->hwnd = GetFocus();
341 if (!msg->hwnd)
343 /* Send the message to the active window instead, */
344 /* translating messages to their WM_SYS equivalent */
345 msg->hwnd = GetActiveWindow();
346 msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
348 return TRUE;
352 /***********************************************************************
353 * MSG_PeekHardwareMsg
355 * Peek for a hardware message matching the hwnd and message filters.
357 static BOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, WORD first, WORD last,
358 BOOL remove )
360 int i, pos = sysMsgQueue->nextMessage;
362 for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
364 *msg = sysMsgQueue->messages[pos].msg;
366 /* Translate message */
368 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
370 if (!MSG_TranslateMouseMsg( msg, remove )) continue;
372 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
374 if (!MSG_TranslateKeyboardMsg( msg )) continue;
376 else continue; /* Should never happen */
378 /* Check message against filters */
380 if (hwnd && (msg->hwnd != hwnd)) continue;
381 if ((first || last) &&
382 ((msg->message < first) || (msg->message > last))) continue;
383 if (remove) MSG_RemoveMsg( sysMsgQueue, pos );
384 return TRUE;
386 return FALSE;
390 /**********************************************************************
391 * SetDoubleClickTime (USER.20)
393 void SetDoubleClickTime( WORD interval )
395 if (interval == 0)
396 doubleClickSpeed = 500;
397 else
398 doubleClickSpeed = interval;
402 /**********************************************************************
403 * GetDoubleClickTime (USER.21)
405 WORD GetDoubleClickTime()
407 return (WORD)doubleClickSpeed;
411 /***********************************************************************
412 * MSG_IncPaintCount
414 void MSG_IncPaintCount( HANDLE hQueue )
416 if (hQueue != hmemAppMsgQueue) return;
417 appMsgQueue->wPaintCount++;
418 appMsgQueue->status |= QS_PAINT;
419 appMsgQueue->tempStatus |= QS_PAINT;
423 /***********************************************************************
424 * MSG_DecPaintCount
426 void MSG_DecPaintCount( HANDLE hQueue )
428 if (hQueue != hmemAppMsgQueue) return;
429 appMsgQueue->wPaintCount--;
430 if (!appMsgQueue->wPaintCount) appMsgQueue->status &= ~QS_PAINT;
434 /***********************************************************************
435 * MSG_IncTimerCount
437 void MSG_IncTimerCount( HANDLE hQueue )
439 if (hQueue != hmemAppMsgQueue) return;
440 appMsgQueue->wTimerCount++;
441 appMsgQueue->status |= QS_TIMER;
442 appMsgQueue->tempStatus |= QS_TIMER;
446 /***********************************************************************
447 * MSG_DecTimerCount
449 void MSG_DecTimerCount( HANDLE hQueue )
451 if (hQueue != hmemAppMsgQueue) return;
452 appMsgQueue->wTimerCount--;
453 if (!appMsgQueue->wTimerCount) appMsgQueue->status &= ~QS_TIMER;
457 /***********************************************************************
458 * hardware_event
460 * Add an event to the system message queue.
461 * Note: the position is relative to the desktop window.
463 void hardware_event( WORD message, WORD wParam, LONG lParam,
464 int xPos, int yPos, DWORD time, DWORD extraInfo )
466 MSG *msg;
467 int pos;
469 if (!sysMsgQueue) return;
470 pos = sysMsgQueue->nextFreeMessage;
472 /* Merge with previous event if possible */
474 if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
476 if (pos > 0) pos--;
477 else pos = sysMsgQueue->queueSize - 1;
478 msg = &sysMsgQueue->messages[pos].msg;
479 if ((msg->message == message) && (msg->wParam == wParam))
480 sysMsgQueue->msgCount--; /* Merge events */
481 else
482 pos = sysMsgQueue->nextFreeMessage; /* Don't merge */
485 /* Check if queue is full */
487 if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
489 /* Queue is full, beep (but not on every mouse motion...) */
490 if (message != WM_MOUSEMOVE) MessageBeep(0);
491 return;
494 /* Store message */
496 msg = &sysMsgQueue->messages[pos].msg;
497 msg->hwnd = 0;
498 msg->message = message;
499 msg->wParam = wParam;
500 msg->lParam = lParam;
501 msg->time = time;
502 msg->pt.x = xPos & 0xffff;
503 msg->pt.y = yPos & 0xffff;
504 sysMsgQueue->messages[pos].extraInfo = extraInfo;
505 if (pos < sysMsgQueue->queueSize - 1) pos++;
506 else pos = 0;
507 sysMsgQueue->nextFreeMessage = pos;
508 sysMsgQueue->msgCount++;
512 /***********************************************************************
513 * MSG_GetHardwareMessage
515 * Like GetMessage(), but only return mouse and keyboard events.
516 * Used internally for window moving and resizing. Mouse messages
517 * are not translated.
518 * Warning: msg->hwnd is always 0.
520 BOOL MSG_GetHardwareMessage( LPMSG msg )
522 int pos;
523 XEvent event;
525 while(1)
527 if ((pos = MSG_FindMsg( sysMsgQueue, 0, 0, 0 )) != -1)
529 *msg = sysMsgQueue->messages[pos].msg;
530 MSG_RemoveMsg( sysMsgQueue, pos );
531 break;
533 XNextEvent( display, &event );
534 EVENT_ProcessEvent( &event );
536 return TRUE;
540 /***********************************************************************
541 * SetTaskQueue (KERNEL.34)
543 WORD SetTaskQueue( HANDLE hTask, HANDLE hQueue )
545 HANDLE prev = hmemAppMsgQueue;
546 hmemAppMsgQueue = hQueue;
547 return prev;
551 /***********************************************************************
552 * GetTaskQueue (KERNEL.35)
554 WORD GetTaskQueue( HANDLE hTask )
556 return hmemAppMsgQueue;
560 /***********************************************************************
561 * SetMessageQueue (USER.266)
563 BOOL SetMessageQueue( int size )
565 HANDLE hQueue;
567 if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
569 /* Free the old message queue */
570 if ((hQueue = GetTaskQueue(0)) != 0)
572 GlobalUnlock( hQueue );
573 GlobalFree( hQueue );
576 if (!(hQueue = MSG_CreateMsgQueue( size ))) return FALSE;
577 SetTaskQueue( 0, hQueue );
578 appMsgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue );
579 return TRUE;
583 /***********************************************************************
584 * PostQuitMessage (USER.6)
586 void PostQuitMessage( int exitCode )
588 if (!appMsgQueue) return;
589 appMsgQueue->wPostQMsg = TRUE;
590 appMsgQueue->wExitCode = exitCode;
594 /***********************************************************************
595 * GetQueueStatus (USER.334)
597 DWORD GetQueueStatus( int flags )
599 unsigned long ret = (appMsgQueue->status << 16) | appMsgQueue->tempStatus;
600 appMsgQueue->tempStatus = 0;
601 return ret & ((flags << 16) | flags);
605 /***********************************************************************
606 * GetInputState (USER.335)
608 BOOL GetInputState()
610 return appMsgQueue->status & (QS_KEY | QS_MOUSEBUTTON);
614 /***********************************************************************
615 * MSG_Synchronize
617 * Synchronize with the X server. Should not be used too often.
619 void MSG_Synchronize()
621 XEvent event;
623 XSync( display, False );
624 while (XPending( display ))
626 XNextEvent( display, &event );
627 EVENT_ProcessEvent( &event );
632 /***********************************************************************
633 * MSG_WaitXEvent
635 * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
636 * Return TRUE if an event is pending, FALSE on timeout or error
637 * (for instance lost connection with the server).
639 BOOL MSG_WaitXEvent( LONG maxWait )
641 fd_set read_set;
642 struct timeval timeout;
643 XEvent event;
644 int fd = ConnectionNumber(display);
646 if (!XPending(display) && (maxWait != -1))
648 FD_ZERO( &read_set );
649 FD_SET( fd, &read_set );
650 timeout.tv_sec = maxWait / 1000;
651 timeout.tv_usec = (maxWait % 1000) * 1000;
652 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
653 return FALSE; /* Timeout or error */
656 /* Process the event (and possibly others that occurred in the meantime) */
659 XNextEvent( display, &event );
660 EVENT_ProcessEvent( &event );
662 while (XPending( display ));
663 return TRUE;
667 /***********************************************************************
668 * MSG_PeekMessage
670 static BOOL MSG_PeekMessage( MESSAGEQUEUE * msgQueue, LPMSG msg, HWND hwnd,
671 WORD first, WORD last, WORD flags, BOOL peek )
673 int pos, mask;
674 LONG nextExp; /* Next timer expiration time */
676 if (first || last)
678 mask = QS_POSTMESSAGE; /* Always selectioned */
679 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
680 if ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) mask |= QS_MOUSE;
681 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
682 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
683 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
685 else mask = QS_MOUSE | QS_KEY | QS_POSTMESSAGE | QS_TIMER | QS_PAINT;
687 while(1)
689 /* First handle a message put by SendMessage() */
690 if (msgQueue->status & QS_SENDMESSAGE)
692 if (!hwnd || (msgQueue->hWnd == hwnd))
694 if ((!first && !last) ||
695 ((msgQueue->msg >= first) && (msgQueue->msg <= last)))
697 msg->hwnd = msgQueue->hWnd;
698 msg->message = msgQueue->msg;
699 msg->wParam = msgQueue->wParam;
700 msg->lParam = msgQueue->lParam;
701 if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
702 break;
707 /* Now find a normal message */
708 pos = MSG_FindMsg( msgQueue, hwnd, first, last );
709 if (pos != -1)
711 QMSG *qmsg = &msgQueue->messages[pos];
712 *msg = qmsg->msg;
713 msgQueue->GetMessageTimeVal = msg->time;
714 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
715 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
717 if (flags & PM_REMOVE) MSG_RemoveMsg( msgQueue, pos );
718 break;
721 /* Now find a hardware event */
722 if (MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
724 /* Got one */
725 msgQueue->GetMessageTimeVal = msg->time;
726 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
727 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
728 break;
731 /* Now handle a WM_QUIT message */
732 if (msgQueue->wPostQMsg)
734 msg->hwnd = hwnd;
735 msg->message = WM_QUIT;
736 msg->wParam = msgQueue->wExitCode;
737 msg->lParam = 0;
738 break;
741 /* Now find a WM_PAINT message */
742 if ((msgQueue->status & QS_PAINT) && (mask & QS_PAINT))
744 msg->hwnd = WIN_FindWinToRepaint( hwnd );
745 msg->message = WM_PAINT;
746 msg->wParam = 0;
747 msg->lParam = 0;
748 if (msg->hwnd != 0) break;
751 /* Finally handle WM_TIMER messages */
752 if ((msgQueue->status & QS_TIMER) && (mask & QS_TIMER))
754 if (TIMER_CheckTimer( &nextExp, msg, hwnd, flags & PM_REMOVE ))
755 break; /* Got a timer msg */
757 else nextExp = -1; /* No timeout needed */
759 /* Wait until something happens */
760 if (peek)
762 if (!MSG_WaitXEvent( 0 )) return FALSE; /* No pending event */
764 else /* Wait for an event, then restart the loop */
765 MSG_WaitXEvent( nextExp );
768 /* We got a message */
769 if (peek) return TRUE;
770 else return (msg->message != WM_QUIT);
774 /***********************************************************************
775 * MSG_InternalGetMessage
777 * GetMessage() function for internal use. Behave like GetMessage(),
778 * but also call message filters and optionally send WM_ENTERIDLE messages.
779 * 'hwnd' must be the handle of the dialog or menu window.
780 * 'code' is the message filter value (MSGF_??? codes).
782 BOOL MSG_InternalGetMessage( LPMSG msg, HWND hwnd, HWND hwndOwner, short code,
783 WORD flags, BOOL sendIdle )
785 for (;;)
787 if (sendIdle)
789 if (!MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, flags, TRUE ))
791 /* No message present -> send ENTERIDLE and wait */
792 SendMessage( hwndOwner, WM_ENTERIDLE, code, (LPARAM)hwnd );
793 MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, flags, FALSE );
796 else /* Always wait for a message */
797 MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, flags, FALSE );
799 if (!CallMsgFilter( msg, code )) return (msg->message != WM_QUIT);
801 /* Message filtered -> remove it from the queue */
802 /* if it's still there. */
803 if (!(flags & PM_REMOVE))
804 MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, PM_REMOVE, TRUE );
809 /***********************************************************************
810 * PeekMessage (USER.109)
812 BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
814 return MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, flags, TRUE );
818 /***********************************************************************
819 * GetMessage (USER.108)
821 BOOL GetMessage( LPMSG msg, HWND hwnd, WORD first, WORD last )
823 MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, PM_REMOVE, FALSE );
824 CALL_SYSTEM_HOOK( WH_GETMESSAGE, 0, 0, (LPARAM)msg );
825 CALL_TASK_HOOK( WH_GETMESSAGE, 0, 0, (LPARAM)msg );
826 return (msg->message != WM_QUIT);
831 /***********************************************************************
832 * PostMessage (USER.110)
834 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
836 MSG msg;
837 WND *wndPtr;
839 if (hwnd == HWND_BROADCAST) {
840 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
841 hwnd = GetTopWindow(GetDesktopWindow());
842 while (hwnd) {
843 if (!(wndPtr = WIN_FindWndPtr(hwnd))) break;
844 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) {
845 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04X m=%04X w=%04X l=%08lX !\n",
846 hwnd, message, wParam, lParam);
847 PostMessage(hwnd, message, wParam, lParam);
849 /* {
850 char str[128];
851 GetWindowText(hwnd, str, sizeof(str));
852 dprintf_msg(stddeb, "BROADCAST GetWindowText()='%s' !\n", str);
854 hwnd = wndPtr->hwndNext;
856 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
857 return TRUE;
860 wndPtr = WIN_FindWndPtr( hwnd );
861 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
862 msg.hwnd = hwnd;
863 msg.message = message;
864 msg.wParam = wParam;
865 msg.lParam = lParam;
866 msg.time = GetTickCount();
867 msg.pt.x = 0;
868 msg.pt.y = 0;
870 return MSG_AddMsg( appMsgQueue, &msg, 0 );
874 /***********************************************************************
875 * SendMessage (USER.111)
877 LONG SendMessage( HWND hwnd, WORD msg, WORD wParam, LONG lParam )
879 WND * wndPtr;
881 wndPtr = WIN_FindWndPtr( hwnd );
882 if (!wndPtr) return 0;
883 return CallWindowProc( wndPtr->lpfnWndProc, hwnd, msg, wParam, lParam );
887 /***********************************************************************
888 * WaitMessage (USER.112)
890 void WaitMessage( void )
892 MSG msg;
893 LONG nextExp = -1; /* Next timer expiration time */
895 if ((appMsgQueue->wPostQMsg) ||
896 (appMsgQueue->status & (QS_SENDMESSAGE | QS_PAINT)) ||
897 (appMsgQueue->msgCount) || (sysMsgQueue->msgCount) )
898 return;
899 if ((appMsgQueue->status & QS_TIMER) &&
900 TIMER_CheckTimer( &nextExp, &msg, 0, FALSE))
901 return;
902 MSG_WaitXEvent( nextExp );
906 /***********************************************************************
907 * TranslateMessage (USER.113)
909 BOOL TranslateMessage( LPMSG msg )
911 int message = msg->message;
913 if ((message == WM_KEYDOWN) || (message == WM_KEYUP) ||
914 (message == WM_SYSKEYDOWN) || (message == WM_SYSKEYUP))
916 dprintf_msg(stddeb, "Translating key message\n" );
917 return TRUE;
919 return FALSE;
923 /***********************************************************************
924 * DispatchMessage (USER.114)
926 LONG DispatchMessage( LPMSG msg )
928 WND * wndPtr;
929 LONG retval;
930 int painting;
932 dprintf_msg(stddeb, "Dispatch message hwnd=%04x msg=0x%x w=%d l=%ld time=%lu pt=%d,%d\n",
933 msg->hwnd, msg->message, msg->wParam, msg->lParam,
934 msg->time, msg->pt.x, msg->pt.y );
936 /* Process timer messages */
937 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
939 if (msg->lParam)
940 return CallWindowProc( (WNDPROC)msg->lParam, msg->hwnd,
941 msg->message, msg->wParam, GetTickCount() );
944 if (!msg->hwnd) return 0;
945 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
946 if (!wndPtr->lpfnWndProc) return 0;
947 painting = (msg->message == WM_PAINT);
948 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
949 retval = CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message,
950 msg->wParam, msg->lParam );
951 if (painting && IsWindow(msg->hwnd) &&
952 (wndPtr->flags & WIN_NEEDS_BEGINPAINT))
954 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %d!\n",
955 msg->hwnd);
956 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
958 return retval;
962 /***********************************************************************
963 * GetMessagePos (USER.119)
965 DWORD GetMessagePos(void)
967 return appMsgQueue->GetMessagePosVal;
971 /***********************************************************************
972 * GetMessageTime (USER.120)
974 LONG GetMessageTime(void)
976 return appMsgQueue->GetMessageTimeVal;
980 /***********************************************************************
981 * GetMessageExtraInfo (USER.288)
983 LONG GetMessageExtraInfo(void)
985 return appMsgQueue->GetMessageExtraInfoVal;
989 /***********************************************************************
990 * RegisterWindowMessage (USER.118)
992 WORD RegisterWindowMessage( LPCSTR str )
994 WORD wRet;
995 dprintf_msg(stddeb, "RegisterWindowMessage: '%s'\n", str );
996 wRet = GlobalAddAtom( str );
997 return wRet;
1001 /***********************************************************************
1002 * GetTickCount (USER.13)
1004 DWORD GetTickCount()
1006 struct timeval t;
1007 gettimeofday( &t, NULL );
1008 return (t.tv_sec * 1000) + (t.tv_usec / 1000);