Release 950216
[wine.git] / windows / message.c
blobd77c2b68000d18bebaeaa11d27655c53c3c8db25
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 "event.h"
23 #include "winpos.h"
24 #include "stddebug.h"
25 /* #define 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 */
37 /* System message queue (for hardware events) */
38 static HANDLE hmemSysMsgQueue = 0;
39 static MESSAGEQUEUE * sysMsgQueue = NULL;
41 /* Application message queue (should be a list, one queue per task) */
42 static HANDLE hmemAppMsgQueue = 0;
43 static MESSAGEQUEUE * appMsgQueue = NULL;
45 /* Double-click time */
46 static int doubleClickSpeed = 452;
49 /***********************************************************************
50 * MSG_CreateMsgQueue
52 * Create a message queue.
54 static HANDLE MSG_CreateMsgQueue( int size )
56 HANDLE hQueue;
57 MESSAGEQUEUE * msgQueue;
58 int queueSize;
60 queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
61 if (!(hQueue = GlobalAlloc( GMEM_FIXED, queueSize ))) return 0;
62 msgQueue = (MESSAGEQUEUE *) GlobalLock( hQueue );
63 msgQueue->next = 0;
64 msgQueue->hTask = 0;
65 msgQueue->msgSize = sizeof(QMSG);
66 msgQueue->msgCount = 0;
67 msgQueue->nextMessage = 0;
68 msgQueue->nextFreeMessage = 0;
69 msgQueue->queueSize = size;
70 msgQueue->GetMessageTimeVal = 0;
71 msgQueue->GetMessagePosVal = 0;
72 msgQueue->GetMessageExtraInfoVal = 0;
73 msgQueue->lParam = 0;
74 msgQueue->wParam = 0;
75 msgQueue->msg = 0;
76 msgQueue->hWnd = 0;
77 msgQueue->wPostQMsg = 0;
78 msgQueue->wExitCode = 0;
79 msgQueue->InSendMessageHandle = 0;
80 msgQueue->wPaintCount = 0;
81 msgQueue->wTimerCount = 0;
82 msgQueue->tempStatus = 0;
83 msgQueue->status = 0;
84 GlobalUnlock( hQueue );
85 return hQueue;
89 /***********************************************************************
90 * MSG_CreateSysMsgQueue
92 * Create the system message queue, and set the double-click speed.
93 * Must be called only once.
95 BOOL MSG_CreateSysMsgQueue( int size )
97 if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
98 else if (size <= 0) size = 1;
99 if (!(hmemSysMsgQueue = MSG_CreateMsgQueue( size ))) return FALSE;
100 sysMsgQueue = (MESSAGEQUEUE *) GlobalLock( hmemSysMsgQueue );
101 doubleClickSpeed = GetProfileInt( "windows", "DoubleClickSpeed", 452 );
102 return TRUE;
106 /***********************************************************************
107 * MSG_AddMsg
109 * Add a message to the queue. Return FALSE if queue is full.
111 static int MSG_AddMsg( MESSAGEQUEUE * msgQueue, MSG * msg, DWORD extraInfo )
113 int pos;
115 if (!msgQueue) return FALSE;
116 pos = msgQueue->nextFreeMessage;
118 /* Check if queue is full */
119 if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0)) {
120 fprintf(stderr,"MSG_AddMsg // queue is full !\n");
121 return FALSE;
124 /* Store message */
125 msgQueue->messages[pos].msg = *msg;
126 msgQueue->messages[pos].extraInfo = extraInfo;
127 if (pos < msgQueue->queueSize-1) pos++;
128 else pos = 0;
129 msgQueue->nextFreeMessage = pos;
130 msgQueue->msgCount++;
131 msgQueue->status |= QS_POSTMESSAGE;
132 msgQueue->tempStatus |= QS_POSTMESSAGE;
133 return TRUE;
137 /***********************************************************************
138 * MSG_FindMsg
140 * Find a message matching the given parameters. Return -1 if none available.
142 static int MSG_FindMsg(MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last)
144 int i, pos = msgQueue->nextMessage;
146 if (!msgQueue->msgCount) return -1;
147 if (!hwnd && !first && !last) return pos;
149 for (i = 0; i < msgQueue->msgCount; i++)
151 MSG * msg = &msgQueue->messages[pos].msg;
153 if (!hwnd || (msg->hwnd == hwnd))
155 if (!first && !last) return pos;
156 if ((msg->message >= first) && (msg->message <= last)) return pos;
158 if (pos < msgQueue->queueSize-1) pos++;
159 else pos = 0;
161 return -1;
165 /***********************************************************************
166 * MSG_RemoveMsg
168 * Remove a message from the queue (pos must be a valid position).
170 static void MSG_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
172 if (pos >= msgQueue->nextMessage)
174 for ( ; pos > msgQueue->nextMessage; pos--)
175 msgQueue->messages[pos] = msgQueue->messages[pos-1];
176 msgQueue->nextMessage++;
177 if (msgQueue->nextMessage >= msgQueue->queueSize)
178 msgQueue->nextMessage = 0;
180 else
182 for ( ; pos < msgQueue->nextFreeMessage; pos++)
183 msgQueue->messages[pos] = msgQueue->messages[pos+1];
184 if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
185 else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
187 msgQueue->msgCount--;
188 if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE;
189 msgQueue->tempStatus = 0;
193 /***********************************************************************
194 * MSG_TranslateMouseMsg
196 * Translate an mouse hardware event into a real mouse message.
197 * Return value indicates whether the translated message must be passed
198 * to the user.
199 * Actions performed:
200 * - Find the window for this message.
201 * - Translate button-down messages in double-clicks.
202 * - Send the WM_NCHITTEST message to find where the cursor is.
203 * - Activate the window if needed.
204 * - Translate the message into a non-client message, or translate
205 * the coordinates to client coordinates.
206 * - Send the WM_SETCURSOR message.
208 static BOOL MSG_TranslateMouseMsg( MSG *msg, BOOL remove )
210 BOOL eatMsg = FALSE;
211 INT hittest_result;
212 static DWORD lastClickTime = 0;
213 static WORD lastClickMsg = 0;
214 static POINT lastClickPos = { 0, 0 };
216 BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
217 (msg->message == WM_RBUTTONDOWN) ||
218 (msg->message == WM_MBUTTONDOWN));
220 /* Find the window */
222 if (GetCapture())
224 msg->hwnd = GetCapture();
225 msg->lParam = MAKELONG( msg->pt.x, msg->pt.y );
226 ScreenToClient( msg->hwnd, (LPPOINT)&msg->lParam );
227 return TRUE; /* No need to further process the message */
229 else msg->hwnd = WindowFromPoint( msg->pt );
231 /* Send the WM_NCHITTEST message */
233 hittest_result = (INT)SendMessage( msg->hwnd, WM_NCHITTEST, 0,
234 MAKELONG( msg->pt.x, msg->pt.y ) );
235 while ((hittest_result == HTTRANSPARENT) && (msg->hwnd))
237 msg->hwnd = WINPOS_NextWindowFromPoint( msg->hwnd, msg->pt );
238 if (msg->hwnd)
239 hittest_result = (INT)SendMessage( msg->hwnd, WM_NCHITTEST, 0,
240 MAKELONG( msg->pt.x, msg->pt.y ));
242 if (!msg->hwnd) msg->hwnd = GetDesktopWindow();
244 /* Send the WM_PARENTNOTIFY message */
246 if (mouseClick) WIN_SendParentNotify( msg->hwnd, msg->message,
247 MAKELONG( msg->pt.x, msg->pt.y ) );
249 /* Activate the window if needed */
251 if (mouseClick)
253 HWND parent, hwndTop = msg->hwnd;
254 while ((parent = GetParent(hwndTop)) != 0) hwndTop = parent;
255 if (hwndTop != GetActiveWindow())
257 LONG ret = SendMessage( msg->hwnd, WM_MOUSEACTIVATE, hwndTop,
258 MAKELONG( hittest_result, msg->message ) );
259 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
260 eatMsg = TRUE;
261 if ((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
263 SetWindowPos( hwndTop, HWND_TOP, 0, 0, 0, 0,
264 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
265 WINPOS_ChangeActiveWindow( hwndTop, TRUE );
270 /* Send the WM_SETCURSOR message */
272 SendMessage( msg->hwnd, WM_SETCURSOR, msg->hwnd,
273 MAKELONG( hittest_result, msg->message ));
274 if (eatMsg) return FALSE;
276 /* Check for double-click */
278 if (mouseClick)
280 BOOL dbl_click = FALSE;
282 if ((msg->message == lastClickMsg) &&
283 (msg->time - lastClickTime < doubleClickSpeed) &&
284 (abs(msg->pt.x - lastClickPos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
285 (abs(msg->pt.y - lastClickPos.y) < SYSMETRICS_CYDOUBLECLK/2))
286 dbl_click = TRUE;
288 if (dbl_click && (hittest_result == HTCLIENT))
290 /* Check whether window wants the double click message. */
291 WND * wndPtr = WIN_FindWndPtr( msg->hwnd );
292 if (!wndPtr || !(WIN_CLASS_STYLE(wndPtr) & CS_DBLCLKS))
293 dbl_click = FALSE;
296 if (dbl_click) switch(msg->message)
298 case WM_LBUTTONDOWN: msg->message = WM_LBUTTONDBLCLK; break;
299 case WM_RBUTTONDOWN: msg->message = WM_RBUTTONDBLCLK; break;
300 case WM_MBUTTONDOWN: msg->message = WM_MBUTTONDBLCLK; break;
303 if (remove)
305 lastClickTime = msg->time;
306 lastClickMsg = msg->message;
307 lastClickPos = msg->pt;
311 /* Build the translated message */
313 msg->lParam = MAKELONG( msg->pt.x, msg->pt.y );
314 if (hittest_result == HTCLIENT)
316 ScreenToClient( msg->hwnd, (LPPOINT)&msg->lParam );
318 else
320 msg->wParam = hittest_result;
321 msg->message += WM_NCLBUTTONDOWN - WM_LBUTTONDOWN;
324 return TRUE;
328 /***********************************************************************
329 * MSG_TranslateKeyboardMsg
331 * Translate an keyboard hardware event into a real message.
332 * Return value indicates whether the translated message must be passed
333 * to the user.
335 static BOOL MSG_TranslateKeyboardMsg( MSG *msg )
337 /* Should check Ctrl-Esc and PrintScreen here */
339 msg->hwnd = GetFocus();
340 if (!msg->hwnd)
342 /* Send the message to the active window instead, */
343 /* translating messages to their WM_SYS equivalent */
344 msg->hwnd = GetActiveWindow();
345 msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
347 return TRUE;
351 /***********************************************************************
352 * MSG_PeekHardwareMsg
354 * Peek for a hardware message matching the hwnd and message filters.
356 static BOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, WORD first, WORD last,
357 BOOL remove )
359 int i, pos = sysMsgQueue->nextMessage;
361 for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
363 *msg = sysMsgQueue->messages[pos].msg;
365 /* Translate message */
367 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
369 if (!MSG_TranslateMouseMsg( msg, remove )) continue;
371 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
373 if (!MSG_TranslateKeyboardMsg( msg )) continue;
375 else continue; /* Should never happen */
377 /* Check message against filters */
379 if (hwnd && (msg->hwnd != hwnd)) continue;
380 if ((first || last) &&
381 ((msg->message < first) || (msg->message > last))) continue;
382 if (remove) MSG_RemoveMsg( sysMsgQueue, pos );
383 return TRUE;
385 return FALSE;
389 /**********************************************************************
390 * SetDoubleClickTime (USER.20)
392 void SetDoubleClickTime( WORD interval )
394 if (interval == 0)
395 doubleClickSpeed = 500;
396 else
397 doubleClickSpeed = interval;
401 /**********************************************************************
402 * GetDoubleClickTime (USER.21)
404 WORD GetDoubleClickTime()
406 return (WORD)doubleClickSpeed;
410 /***********************************************************************
411 * MSG_IncPaintCount
413 void MSG_IncPaintCount( HANDLE hQueue )
415 if (hQueue != hmemAppMsgQueue) return;
416 appMsgQueue->wPaintCount++;
417 appMsgQueue->status |= QS_PAINT;
418 appMsgQueue->tempStatus |= QS_PAINT;
422 /***********************************************************************
423 * MSG_DecPaintCount
425 void MSG_DecPaintCount( HANDLE hQueue )
427 if (hQueue != hmemAppMsgQueue) return;
428 appMsgQueue->wPaintCount--;
429 if (!appMsgQueue->wPaintCount) appMsgQueue->status &= ~QS_PAINT;
433 /***********************************************************************
434 * MSG_IncTimerCount
436 void MSG_IncTimerCount( HANDLE hQueue )
438 if (hQueue != hmemAppMsgQueue) return;
439 appMsgQueue->wTimerCount++;
440 appMsgQueue->status |= QS_TIMER;
441 appMsgQueue->tempStatus |= QS_TIMER;
445 /***********************************************************************
446 * MSG_DecTimerCount
448 void MSG_DecTimerCount( HANDLE hQueue )
450 if (hQueue != hmemAppMsgQueue) return;
451 appMsgQueue->wTimerCount--;
452 if (!appMsgQueue->wTimerCount) appMsgQueue->status &= ~QS_TIMER;
456 /***********************************************************************
457 * hardware_event
459 * Add an event to the system message queue.
460 * Note: the position is relative to the desktop window.
462 void hardware_event( WORD message, WORD wParam, LONG lParam,
463 int xPos, int yPos, DWORD time, DWORD extraInfo )
465 MSG *msg;
466 int pos;
468 if (!sysMsgQueue) return;
469 pos = sysMsgQueue->nextFreeMessage;
471 /* Merge with previous event if possible */
473 if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
475 if (pos > 0) pos--;
476 else pos = sysMsgQueue->queueSize - 1;
477 msg = &sysMsgQueue->messages[pos].msg;
478 if ((msg->message == message) && (msg->wParam == wParam))
479 sysMsgQueue->msgCount--; /* Merge events */
480 else
481 pos = sysMsgQueue->nextFreeMessage; /* Don't merge */
484 /* Check if queue is full */
486 if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
488 /* Queue is full, beep (but not on every mouse motion...) */
489 if (message != WM_MOUSEMOVE) MessageBeep(0);
490 return;
493 /* Store message */
495 msg = &sysMsgQueue->messages[pos].msg;
496 msg->hwnd = 0;
497 msg->message = message;
498 msg->wParam = wParam;
499 msg->lParam = lParam;
500 msg->time = time;
501 msg->pt.x = xPos & 0xffff;
502 msg->pt.y = yPos & 0xffff;
503 sysMsgQueue->messages[pos].extraInfo = extraInfo;
504 if (pos < sysMsgQueue->queueSize - 1) pos++;
505 else pos = 0;
506 sysMsgQueue->nextFreeMessage = pos;
507 sysMsgQueue->msgCount++;
511 /***********************************************************************
512 * MSG_GetHardwareMessage
514 * Like GetMessage(), but only return mouse and keyboard events.
515 * Used internally for window moving and resizing. Mouse messages
516 * are not translated.
517 * Warning: msg->hwnd is always 0.
519 BOOL MSG_GetHardwareMessage( LPMSG msg )
521 int pos;
522 XEvent event;
524 while(1)
526 if ((pos = MSG_FindMsg( sysMsgQueue, 0, 0, 0 )) != -1)
528 *msg = sysMsgQueue->messages[pos].msg;
529 MSG_RemoveMsg( sysMsgQueue, pos );
530 break;
532 XNextEvent( display, &event );
533 EVENT_ProcessEvent( &event );
535 return TRUE;
539 /***********************************************************************
540 * SetTaskQueue (KERNEL.34)
542 WORD SetTaskQueue( HANDLE hTask, HANDLE hQueue )
544 HANDLE prev = hmemAppMsgQueue;
545 hmemAppMsgQueue = hQueue;
546 return prev;
550 /***********************************************************************
551 * GetTaskQueue (KERNEL.35)
553 WORD GetTaskQueue( HANDLE hTask )
555 return hmemAppMsgQueue;
559 /***********************************************************************
560 * SetMessageQueue (USER.266)
562 BOOL SetMessageQueue( int size )
564 HANDLE hQueue;
566 if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
568 /* Free the old message queue */
569 if ((hQueue = GetTaskQueue(0)) != 0)
571 GlobalUnlock( hQueue );
572 GlobalFree( hQueue );
575 if (!(hQueue = MSG_CreateMsgQueue( size ))) return FALSE;
576 SetTaskQueue( 0, hQueue );
577 appMsgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue );
578 return TRUE;
582 /***********************************************************************
583 * PostQuitMessage (USER.6)
585 void PostQuitMessage( int exitCode )
587 if (!appMsgQueue) return;
588 appMsgQueue->wPostQMsg = TRUE;
589 appMsgQueue->wExitCode = exitCode;
593 /***********************************************************************
594 * GetQueueStatus (USER.334)
596 DWORD GetQueueStatus( int flags )
598 unsigned long ret = (appMsgQueue->status << 16) | appMsgQueue->tempStatus;
599 appMsgQueue->tempStatus = 0;
600 return ret & ((flags << 16) | flags);
604 /***********************************************************************
605 * GetInputState (USER.335)
607 BOOL GetInputState()
609 return appMsgQueue->status & (QS_KEY | QS_MOUSEBUTTON);
613 /***********************************************************************
614 * MSG_Synchronize
616 * Synchronize with the X server. Should not be used too often.
618 void MSG_Synchronize()
620 XEvent event;
622 XSync( display, False );
623 while (XPending( display ))
625 XNextEvent( display, &event );
626 EVENT_ProcessEvent( &event );
631 /***********************************************************************
632 * MSG_WaitXEvent
634 * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
635 * Return TRUE if an event is pending, FALSE on timeout or error
636 * (for instance lost connection with the server).
638 BOOL MSG_WaitXEvent( LONG maxWait )
640 fd_set read_set;
641 struct timeval timeout;
642 XEvent event;
643 int fd = ConnectionNumber(display);
645 if (!XPending(display) && (maxWait != -1))
647 FD_ZERO( &read_set );
648 FD_SET( fd, &read_set );
649 timeout.tv_sec = maxWait / 1000;
650 timeout.tv_usec = (maxWait % 1000) * 1000;
651 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
652 return FALSE; /* Timeout or error */
655 /* Process the event (and possibly others that occurred in the meantime) */
658 XNextEvent( display, &event );
659 EVENT_ProcessEvent( &event );
661 while (XPending( display ));
662 return TRUE;
666 /***********************************************************************
667 * MSG_PeekMessage
669 static BOOL MSG_PeekMessage( MESSAGEQUEUE * msgQueue, LPMSG msg, HWND hwnd,
670 WORD first, WORD last, WORD flags, BOOL peek )
672 int pos, mask;
673 LONG nextExp; /* Next timer expiration time */
675 if (first || last)
677 mask = QS_POSTMESSAGE; /* Always selectioned */
678 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
679 if ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) mask |= QS_MOUSE;
680 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
681 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
682 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
684 else mask = QS_MOUSE | QS_KEY | QS_POSTMESSAGE | QS_TIMER | QS_PAINT;
686 while(1)
688 /* First handle a message put by SendMessage() */
689 if (msgQueue->status & QS_SENDMESSAGE)
691 if (!hwnd || (msgQueue->hWnd == hwnd))
693 if ((!first && !last) ||
694 ((msgQueue->msg >= first) && (msgQueue->msg <= last)))
696 msg->hwnd = msgQueue->hWnd;
697 msg->message = msgQueue->msg;
698 msg->wParam = msgQueue->wParam;
699 msg->lParam = msgQueue->lParam;
700 if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
701 break;
706 /* Now find a normal message */
707 pos = MSG_FindMsg( msgQueue, hwnd, first, last );
708 if (pos != -1)
710 QMSG *qmsg = &msgQueue->messages[pos];
711 *msg = qmsg->msg;
712 msgQueue->GetMessageTimeVal = msg->time;
713 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
714 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
716 if (flags & PM_REMOVE) MSG_RemoveMsg( msgQueue, pos );
717 break;
720 /* Now find a hardware event */
721 if (MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
723 /* Got one */
724 msgQueue->GetMessageTimeVal = msg->time;
725 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
726 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
727 break;
730 /* Now handle a WM_QUIT message */
731 if (msgQueue->wPostQMsg)
733 msg->hwnd = hwnd;
734 msg->message = WM_QUIT;
735 msg->wParam = msgQueue->wExitCode;
736 msg->lParam = 0;
737 break;
740 /* Now find a WM_PAINT message */
741 if ((msgQueue->status & QS_PAINT) && (mask & QS_PAINT))
743 msg->hwnd = WIN_FindWinToRepaint( hwnd );
744 msg->message = WM_PAINT;
745 msg->wParam = 0;
746 msg->lParam = 0;
747 if (msg->hwnd != 0) break;
750 /* Finally handle WM_TIMER messages */
751 if ((msgQueue->status & QS_TIMER) && (mask & QS_TIMER))
753 if (TIMER_CheckTimer( &nextExp, msg, hwnd, flags & PM_REMOVE ))
754 break; /* Got a timer msg */
756 else nextExp = -1; /* No timeout needed */
758 /* Wait until something happens */
759 if (peek)
761 if (!MSG_WaitXEvent( 0 )) return FALSE; /* No pending event */
763 else /* Wait for an event, then restart the loop */
764 MSG_WaitXEvent( nextExp );
767 /* We got a message */
768 if (peek) return TRUE;
769 else return (msg->message != WM_QUIT);
773 /***********************************************************************
774 * MSG_InternalGetMessage
776 * GetMessage() function for internal use. Behave like GetMessage(),
777 * but also call message filters and optionally send WM_ENTERIDLE messages.
778 * 'hwnd' must be the handle of the dialog or menu window.
779 * 'code' is the message filter value (MSGF_??? codes).
781 BOOL MSG_InternalGetMessage( LPMSG msg, HWND hwnd, HWND hwndOwner, short code,
782 WORD flags, BOOL sendIdle )
784 for (;;)
786 if (sendIdle)
788 if (!MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, flags, TRUE ))
790 /* No message present -> send ENTERIDLE and wait */
791 SendMessage( hwndOwner, WM_ENTERIDLE, code, (LPARAM)hwnd );
792 MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, flags, FALSE );
795 else /* Always wait for a message */
796 MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, flags, FALSE );
798 if (!CallMsgFilter( msg, code )) return (msg->message != WM_QUIT);
800 /* Message filtered -> remove it from the queue */
801 /* if it's still there. */
802 if (!(flags & PM_REMOVE))
803 MSG_PeekMessage( appMsgQueue, msg, 0, 0, 0, PM_REMOVE, TRUE );
808 /***********************************************************************
809 * PeekMessage (USER.109)
811 BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
813 return MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, flags, TRUE );
817 /***********************************************************************
818 * GetMessage (USER.108)
820 BOOL GetMessage( LPMSG msg, HWND hwnd, WORD first, WORD last )
822 MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, PM_REMOVE, FALSE );
823 CALL_SYSTEM_HOOK( WH_GETMESSAGE, 0, 0, (LPARAM)msg );
824 CALL_TASK_HOOK( WH_GETMESSAGE, 0, 0, (LPARAM)msg );
825 return (msg->message != WM_QUIT);
830 /***********************************************************************
831 * PostMessage (USER.110)
833 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
835 MSG msg;
836 WND *wndPtr;
838 if (hwnd == HWND_BROADCAST) {
839 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
840 hwnd = GetTopWindow(GetDesktopWindow());
841 while (hwnd) {
842 if (!(wndPtr = WIN_FindWndPtr(hwnd))) break;
843 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) {
844 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04X m=%04X w=%04X l=%08lX !\n",
845 hwnd, message, wParam, lParam);
846 PostMessage(hwnd, message, wParam, lParam);
848 /* {
849 char str[128];
850 GetWindowText(hwnd, str, sizeof(str));
851 dprintf_msg(stddeb, "BROADCAST GetWindowText()='%s' !\n", str);
853 hwnd = wndPtr->hwndNext;
855 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
856 return TRUE;
859 wndPtr = WIN_FindWndPtr( hwnd );
860 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
861 msg.hwnd = hwnd;
862 msg.message = message;
863 msg.wParam = wParam;
864 msg.lParam = lParam;
865 msg.time = GetTickCount();
866 msg.pt.x = 0;
867 msg.pt.y = 0;
869 return MSG_AddMsg( appMsgQueue, &msg, 0 );
873 /***********************************************************************
874 * SendMessage (USER.111)
876 LONG SendMessage( HWND hwnd, WORD msg, WORD wParam, LONG lParam )
878 WND * wndPtr;
880 wndPtr = WIN_FindWndPtr( hwnd );
881 if (!wndPtr) return 0;
882 return CallWindowProc( wndPtr->lpfnWndProc, hwnd, msg, wParam, lParam );
886 /***********************************************************************
887 * WaitMessage (USER.112)
889 void WaitMessage( void )
891 MSG msg;
892 LONG nextExp = -1; /* Next timer expiration time */
894 if ((appMsgQueue->wPostQMsg) ||
895 (appMsgQueue->status & (QS_SENDMESSAGE | QS_PAINT)) ||
896 (appMsgQueue->msgCount) || (sysMsgQueue->msgCount) )
897 return;
898 if ((appMsgQueue->status & QS_TIMER) &&
899 TIMER_CheckTimer( &nextExp, &msg, 0, FALSE))
900 return;
901 MSG_WaitXEvent( nextExp );
905 /***********************************************************************
906 * TranslateMessage (USER.113)
908 BOOL TranslateMessage( LPMSG msg )
910 int message = msg->message;
912 if ((message == WM_KEYDOWN) || (message == WM_KEYUP) ||
913 (message == WM_SYSKEYDOWN) || (message == WM_SYSKEYUP))
915 dprintf_msg(stddeb, "Translating key message\n" );
916 return TRUE;
918 return FALSE;
922 /***********************************************************************
923 * DispatchMessage (USER.114)
925 LONG DispatchMessage( LPMSG msg )
927 WND * wndPtr;
928 LONG retval;
929 int painting;
931 dprintf_msg(stddeb, "Dispatch message hwnd=%04x msg=0x%x w=%d l=%ld time=%lu pt=%d,%d\n",
932 msg->hwnd, msg->message, msg->wParam, msg->lParam,
933 msg->time, msg->pt.x, msg->pt.y );
935 /* Process timer messages */
936 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
938 if (msg->lParam)
939 return CallWindowProc( (WNDPROC)msg->lParam, msg->hwnd,
940 msg->message, msg->wParam, GetTickCount() );
943 if (!msg->hwnd) return 0;
944 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
945 if (!wndPtr->lpfnWndProc) return 0;
946 painting = (msg->message == WM_PAINT);
947 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
948 retval = CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message,
949 msg->wParam, msg->lParam );
950 if (painting && IsWindow(msg->hwnd) &&
951 (wndPtr->flags & WIN_NEEDS_BEGINPAINT))
953 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %d!\n",
954 msg->hwnd);
955 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
957 return retval;
961 /***********************************************************************
962 * GetMessagePos (USER.119)
964 DWORD GetMessagePos(void)
966 return appMsgQueue->GetMessagePosVal;
970 /***********************************************************************
971 * GetMessageTime (USER.120)
973 LONG GetMessageTime(void)
975 return appMsgQueue->GetMessageTimeVal;
979 /***********************************************************************
980 * GetMessageExtraInfo (USER.288)
982 LONG GetMessageExtraInfo(void)
984 return appMsgQueue->GetMessageExtraInfoVal;
988 /***********************************************************************
989 * RegisterWindowMessage (USER.118)
991 WORD RegisterWindowMessage( LPCSTR str )
993 WORD wRet;
994 dprintf_msg(stddeb, "RegisterWindowMessage: '%s'\n", str );
995 wRet = GlobalAddAtom( str );
996 return wRet;
1000 /***********************************************************************
1001 * GetTickCount (USER.13)
1003 DWORD GetTickCount()
1005 struct timeval t;
1006 gettimeofday( &t, NULL );
1007 return (t.tv_sec * 1000) + (t.tv_usec / 1000);