2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
15 #include "sysmetrics.h"
23 /* #define DEBUG_MSG */
26 #define HWND_BROADCAST ((HWND)0xffff)
27 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
30 extern BOOL TIMER_CheckTimer( LONG *next, MSG *msg,
31 HWND hwnd, BOOL remove ); /* timer.c */
33 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
35 /* ------- Internal Queues ------ */
37 static HANDLE hmemSysMsgQueue = 0;
38 static MESSAGEQUEUE *sysMsgQueue = NULL;
39 static HANDLE hFirstQueue = 0;
41 /* ------- Miscellaneous ------ */
42 static int doubleClickSpeed = 452;
45 /***********************************************************************
48 * Creates a message queue. Doesn't link it into queue list!
50 static HANDLE MSG_CreateMsgQueue( int size )
53 MESSAGEQUEUE * msgQueue;
56 queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
57 if (!(hQueue = GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, queueSize )))
59 msgQueue = (MESSAGEQUEUE *) GlobalLock( hQueue );
60 msgQueue->msgSize = sizeof(QMSG);
61 msgQueue->queueSize = size;
62 msgQueue->wWinVersion = 0; /* FIXME? */
63 GlobalUnlock( hQueue );
68 /***********************************************************************
71 * Unlinks and deletes a message queue.
73 BOOL MSG_DeleteMsgQueue( HANDLE hQueue )
75 MESSAGEQUEUE * msgQueue = (MESSAGEQUEUE*)GlobalLock(hQueue);
78 if (!hQueue || !msgQueue)
80 dprintf_msg(stddeb,"DeleteMsgQueue: invalid argument.\n");
85 while (*pPrev && (*pPrev != hQueue))
87 MESSAGEQUEUE *msgQ = (MESSAGEQUEUE*)GlobalLock(*pPrev);
90 if (*pPrev) *pPrev = msgQueue->next;
96 /***********************************************************************
97 * MSG_CreateSysMsgQueue
99 * Create the system message queue, and set the double-click speed.
100 * Must be called only once.
102 BOOL MSG_CreateSysMsgQueue( int size )
104 if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
105 else if (size <= 0) size = 1;
106 if (!(hmemSysMsgQueue = MSG_CreateMsgQueue( size ))) return FALSE;
107 sysMsgQueue = (MESSAGEQUEUE *) GlobalLock( hmemSysMsgQueue );
108 doubleClickSpeed = GetProfileInt( "windows", "DoubleClickSpeed", 452 );
113 /***********************************************************************
116 * Add a message to the queue. Return FALSE if queue is full.
118 static int MSG_AddMsg( HANDLE hQueue, MSG * msg, DWORD extraInfo )
121 MESSAGEQUEUE *msgQueue;
123 if (!(msgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return FALSE;
124 pos = msgQueue->nextFreeMessage;
126 /* Check if queue is full */
127 if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0)) {
128 fprintf(stderr,"MSG_AddMsg // queue is full !\n");
133 msgQueue->messages[pos].msg = *msg;
134 msgQueue->messages[pos].extraInfo = extraInfo;
135 if (pos < msgQueue->queueSize-1) pos++;
137 msgQueue->nextFreeMessage = pos;
138 msgQueue->msgCount++;
139 msgQueue->status |= QS_POSTMESSAGE;
140 msgQueue->tempStatus |= QS_POSTMESSAGE;
145 /***********************************************************************
148 * Find a message matching the given parameters. Return -1 if none available.
150 static int MSG_FindMsg(MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last)
152 int i, pos = msgQueue->nextMessage;
154 dprintf_msg(stddeb,"MSG_FindMsg: hwnd=0x"NPFMT"\n\n", hwnd );
156 if (!msgQueue->msgCount) return -1;
157 if (!hwnd && !first && !last) return pos;
159 for (i = 0; i < msgQueue->msgCount; i++)
161 MSG * msg = &msgQueue->messages[pos].msg;
163 if (!hwnd || (msg->hwnd == hwnd))
165 if (!first && !last) return pos;
166 if ((msg->message >= first) && (msg->message <= last)) return pos;
168 if (pos < msgQueue->queueSize-1) pos++;
175 /***********************************************************************
178 * Remove a message from the queue (pos must be a valid position).
180 static void MSG_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
182 if (pos >= msgQueue->nextMessage)
184 for ( ; pos > msgQueue->nextMessage; pos--)
185 msgQueue->messages[pos] = msgQueue->messages[pos-1];
186 msgQueue->nextMessage++;
187 if (msgQueue->nextMessage >= msgQueue->queueSize)
188 msgQueue->nextMessage = 0;
192 for ( ; pos < msgQueue->nextFreeMessage; pos++)
193 msgQueue->messages[pos] = msgQueue->messages[pos+1];
194 if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
195 else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
197 msgQueue->msgCount--;
198 if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE;
199 msgQueue->tempStatus = 0;
202 /***********************************************************************
205 HTASK MSG_GetQueueTask( HANDLE hQueue )
207 MESSAGEQUEUE *msgQ = GlobalLock( hQueue );
209 return (msgQ) ? msgQ->hTask : 0 ;
212 /***********************************************************************
213 * MSG_TranslateMouseMsg
215 * Translate an mouse hardware event into a real mouse message.
216 * Return value indicates whether the translated message must be passed
219 * - Find the window for this message.
220 * - Translate button-down messages in double-clicks.
221 * - Send the WM_NCHITTEST message to find where the cursor is.
222 * - Activate the window if needed.
223 * - Translate the message into a non-client message, or translate
224 * the coordinates to client coordinates.
225 * - Send the WM_SETCURSOR message.
227 static BOOL MSG_TranslateMouseMsg( MSG *msg, BOOL remove )
231 static DWORD lastClickTime = 0;
232 static WORD lastClickMsg = 0;
233 static POINT lastClickPos = { 0, 0 };
235 MOUSEHOOKSTRUCT hook = { msg->pt, 0, HTCLIENT, 0 };
237 BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
238 (msg->message == WM_RBUTTONDOWN) ||
239 (msg->message == WM_MBUTTONDOWN));
241 /* Find the window */
245 msg->hwnd = GetCapture();
246 ScreenToClient( msg->hwnd, &pt );
247 msg->lParam = MAKELONG( pt.x, pt.y );
248 /* No need to further process the message */
249 hook.hwnd = msg->hwnd;
250 return !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
251 msg->message, (LPARAM)MAKE_SEGPTR(&hook));
254 if ((hittest = WINPOS_WindowFromPoint( msg->pt, &msg->hwnd )) != HTERROR)
257 /* Send the WM_PARENTNOTIFY message */
259 if (mouseClick) WIN_SendParentNotify( msg->hwnd, msg->message, 0,
260 MAKELONG( msg->pt.x, msg->pt.y ) );
262 /* Activate the window if needed */
266 HWND hwndTop = WIN_GetTopParent( msg->hwnd );
267 if (hwndTop != GetActiveWindow())
269 LONG ret = SendMessage( msg->hwnd, WM_MOUSEACTIVATE,
271 MAKELONG( hittest, msg->message ) );
272 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
274 if ((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
276 SetWindowPos( hwndTop, HWND_TOP, 0, 0, 0, 0,
277 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
278 WINPOS_ChangeActiveWindow( hwndTop, TRUE );
284 /* Send the WM_SETCURSOR message */
286 SendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
287 MAKELONG( hittest, msg->message ));
288 if (eatMsg) return FALSE;
290 /* Check for double-click */
294 BOOL dbl_click = FALSE;
296 if ((msg->message == lastClickMsg) &&
297 (msg->time - lastClickTime < doubleClickSpeed) &&
298 (abs(msg->pt.x - lastClickPos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
299 (abs(msg->pt.y - lastClickPos.y) < SYSMETRICS_CYDOUBLECLK/2))
302 if (dbl_click && (hittest == HTCLIENT))
304 /* Check whether window wants the double click message. */
305 WND * wndPtr = WIN_FindWndPtr( msg->hwnd );
306 if (!wndPtr || !(WIN_CLASS_STYLE(wndPtr) & CS_DBLCLKS))
310 if (dbl_click) switch(msg->message)
312 case WM_LBUTTONDOWN: msg->message = WM_LBUTTONDBLCLK; break;
313 case WM_RBUTTONDOWN: msg->message = WM_RBUTTONDBLCLK; break;
314 case WM_MBUTTONDOWN: msg->message = WM_MBUTTONDBLCLK; break;
319 lastClickTime = msg->time;
320 lastClickMsg = msg->message;
321 lastClickPos = msg->pt;
325 /* Build the translated message */
327 if (hittest == HTCLIENT)
328 ScreenToClient( msg->hwnd, &pt );
331 msg->wParam = hittest;
332 msg->message += WM_NCLBUTTONDOWN - WM_LBUTTONDOWN;
334 msg->lParam = MAKELONG( pt.x, pt.y );
336 hook.hwnd = msg->hwnd;
337 hook.wHitTestCode = hittest;
338 return !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
339 msg->message, (LPARAM)MAKE_SEGPTR(&hook));
343 /***********************************************************************
344 * MSG_TranslateKeyboardMsg
346 * Translate an keyboard hardware event into a real message.
347 * Return value indicates whether the translated message must be passed
350 static BOOL MSG_TranslateKeyboardMsg( MSG *msg, BOOL remove )
352 /* Should check Ctrl-Esc and PrintScreen here */
354 msg->hwnd = GetFocus();
357 /* Send the message to the active window instead, */
358 /* translating messages to their WM_SYS equivalent */
359 msg->hwnd = GetActiveWindow();
360 msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
362 return !HOOK_CallHooks( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
363 msg->wParam, msg->lParam );
367 /***********************************************************************
368 * MSG_PeekHardwareMsg
370 * Peek for a hardware message matching the hwnd and message filters.
372 static BOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, WORD first, WORD last,
375 int i, pos = sysMsgQueue->nextMessage;
377 for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
379 if (pos >= sysMsgQueue->queueSize) pos = 0;
380 *msg = sysMsgQueue->messages[pos].msg;
382 /* Translate message */
384 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
386 if (!MSG_TranslateMouseMsg( msg, remove )) continue;
388 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
390 if (!MSG_TranslateKeyboardMsg( msg, remove )) continue;
392 else /* Non-standard hardware event */
394 HARDWAREHOOKSTRUCT hook = { msg->hwnd, msg->message,
395 msg->wParam, msg->lParam };
396 if (HOOK_CallHooks( WH_HARDWARE, remove ? HC_ACTION : HC_NOREMOVE,
397 0, (LPARAM)MAKE_SEGPTR(&hook) )) continue;
400 /* Check message against filters */
402 if (hwnd && (msg->hwnd != hwnd)) continue;
403 if ((first || last) &&
404 ((msg->message < first) || (msg->message > last))) continue;
405 if ((msg->hwnd != GetDesktopWindow()) &&
406 (GetWindowTask(msg->hwnd) != GetCurrentTask()))
407 continue; /* Not for this task */
410 MSG tmpMsg = *msg; /* FIXME */
411 HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION,
412 0, (LPARAM)MAKE_SEGPTR(&tmpMsg) );
413 MSG_RemoveMsg( sysMsgQueue, pos );
421 /**********************************************************************
422 * SetDoubleClickTime (USER.20)
424 void SetDoubleClickTime( WORD interval )
427 doubleClickSpeed = 500;
429 doubleClickSpeed = interval;
433 /**********************************************************************
434 * GetDoubleClickTime (USER.21)
436 WORD GetDoubleClickTime()
438 return (WORD)doubleClickSpeed;
442 /***********************************************************************
445 void MSG_IncPaintCount( HANDLE hQueue )
449 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
450 queue->wPaintCount++;
451 queue->status |= QS_PAINT;
452 queue->tempStatus |= QS_PAINT;
456 /***********************************************************************
459 void MSG_DecPaintCount( HANDLE hQueue )
463 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
464 queue->wPaintCount--;
465 if (!queue->wPaintCount) queue->status &= ~QS_PAINT;
469 /***********************************************************************
472 void MSG_IncTimerCount( HANDLE hQueue )
476 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
477 queue->wTimerCount++;
478 queue->status |= QS_TIMER;
479 queue->tempStatus |= QS_TIMER;
483 /***********************************************************************
486 void MSG_DecTimerCount( HANDLE hQueue )
490 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
491 queue->wTimerCount--;
492 if (!queue->wTimerCount) queue->status &= ~QS_TIMER;
496 /***********************************************************************
499 * Add an event to the system message queue.
500 * Note: the position is relative to the desktop window.
502 void hardware_event( WORD message, WORD wParam, LONG lParam,
503 int xPos, int yPos, DWORD time, DWORD extraInfo )
508 if (!sysMsgQueue) return;
509 pos = sysMsgQueue->nextFreeMessage;
511 /* Merge with previous event if possible */
513 if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
516 else pos = sysMsgQueue->queueSize - 1;
517 msg = &sysMsgQueue->messages[pos].msg;
518 if ((msg->message == message) && (msg->wParam == wParam))
519 sysMsgQueue->msgCount--; /* Merge events */
521 pos = sysMsgQueue->nextFreeMessage; /* Don't merge */
524 /* Check if queue is full */
526 if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
528 /* Queue is full, beep (but not on every mouse motion...) */
529 if (message != WM_MOUSEMOVE) MessageBeep(0);
535 msg = &sysMsgQueue->messages[pos].msg;
537 msg->message = message;
538 msg->wParam = wParam;
539 msg->lParam = lParam;
541 msg->pt.x = xPos & 0xffff;
542 msg->pt.y = yPos & 0xffff;
543 sysMsgQueue->messages[pos].extraInfo = extraInfo;
544 if (pos < sysMsgQueue->queueSize - 1) pos++;
546 sysMsgQueue->nextFreeMessage = pos;
547 sysMsgQueue->msgCount++;
551 /***********************************************************************
552 * MSG_GetHardwareMessage
554 * Like GetMessage(), but only return mouse and keyboard events.
555 * Used internally for window moving and resizing. Mouse messages
556 * are not translated.
557 * Warning: msg->hwnd is always 0.
559 BOOL MSG_GetHardwareMessage( LPMSG msg )
566 if ((pos = MSG_FindMsg( sysMsgQueue, 0, 0, 0 )) != -1)
568 *msg = sysMsgQueue->messages[pos].msg;
569 MSG_RemoveMsg( sysMsgQueue, pos );
572 XNextEvent( display, &event );
573 EVENT_ProcessEvent( &event );
579 /***********************************************************************
580 * SetMessageQueue (USER.266)
582 BOOL SetMessageQueue( int size )
584 HANDLE hQueue, hNewQueue;
585 MESSAGEQUEUE *queuePtr;
587 if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
589 if( !(hNewQueue = MSG_CreateMsgQueue( size )))
591 dprintf_msg(stddeb,"SetMessageQueue: failed!\n");
595 /* Free the old message queue */
596 if ((hQueue = GetTaskQueue(0)) != 0) MSG_DeleteMsgQueue( hQueue );
598 /* Link new queue into list */
599 queuePtr = (MESSAGEQUEUE *)GlobalLock( hNewQueue );
600 queuePtr->hTask = GetCurrentTask();
601 queuePtr->next = hFirstQueue;
602 hFirstQueue = hNewQueue;
604 SetTaskQueue( 0, hNewQueue );
609 /***********************************************************************
610 * GetWindowTask (USER.224)
612 HTASK GetWindowTask( HWND hwnd )
614 WND *wndPtr = WIN_FindWndPtr( hwnd );
615 MESSAGEQUEUE *queuePtr;
617 if (!wndPtr) return 0;
618 queuePtr = (MESSAGEQUEUE *)GlobalLock( wndPtr->hmemTaskQ );
619 if (!queuePtr) return 0;
620 return queuePtr->hTask;
624 /***********************************************************************
625 * PostQuitMessage (USER.6)
627 void PostQuitMessage( int exitCode )
631 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return;
632 queue->wPostQMsg = TRUE;
633 queue->wExitCode = exitCode;
637 /***********************************************************************
638 * GetQueueStatus (USER.334)
640 DWORD GetQueueStatus( UINT flags )
645 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
646 ret = MAKELONG( queue->tempStatus, queue->status );
647 queue->tempStatus = 0;
648 return ret & MAKELONG( flags, flags );
652 /***********************************************************************
653 * GetInputState (USER.335)
659 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return FALSE;
660 return queue->status & (QS_KEY | QS_MOUSEBUTTON);
664 /***********************************************************************
667 * Synchronize with the X server. Should not be used too often.
669 void MSG_Synchronize()
673 XSync( display, False );
674 while (XPending( display ))
676 XNextEvent( display, &event );
677 EVENT_ProcessEvent( &event );
682 /***********************************************************************
685 * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
686 * Return TRUE if an event is pending, FALSE on timeout or error
687 * (for instance lost connection with the server).
689 BOOL MSG_WaitXEvent( LONG maxWait )
692 struct timeval timeout;
694 int fd = ConnectionNumber(display);
696 if (!XPending(display) && (maxWait != -1))
698 FD_ZERO( &read_set );
699 FD_SET( fd, &read_set );
701 timeout.tv_usec = (maxWait % 1000) * 1000;
702 timeout.tv_sec = maxWait / 1000;
705 sigsetjmp(env_wait_x, 1);
708 if (DDE_GetRemoteMessage()) {
709 while(DDE_GetRemoteMessage())
713 stop_wait_op= STOP_WAIT_X;
714 /* The code up to the next "stop_wait_op= CONT" must be reentrant */
715 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
716 !XPending(display)) {
722 #else /* CONFIG_IPC */
723 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
724 return FALSE; /* Timeout or error */
725 #endif /* CONFIG_IPC */
729 /* Process the event (and possibly others that occurred in the meantime) */
734 if (DDE_GetRemoteMessage())
736 while(DDE_GetRemoteMessage()) ;
739 #endif /* CONFIG_IPC */
741 XNextEvent( display, &event );
742 EVENT_ProcessEvent( &event );
744 while (XPending( display ));
749 /***********************************************************************
752 static BOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last,
753 WORD flags, BOOL peek )
756 MESSAGEQUEUE *msgQueue;
757 LONG nextExp; /* Next timer expiration time */
760 DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
761 DDE_GetRemoteMessage();
762 #endif /* CONFIG_IPC */
766 mask = QS_POSTMESSAGE; /* Always selectioned */
767 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
768 if ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) mask |= QS_MOUSE;
769 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
770 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
771 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
773 else mask = QS_MOUSE | QS_KEY | QS_POSTMESSAGE | QS_TIMER | QS_PAINT;
777 msgQueue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) );
778 if (!msgQueue) return FALSE;
780 /* First handle a message put by SendMessage() */
781 if (msgQueue->status & QS_SENDMESSAGE)
783 if (!hwnd || (msgQueue->hWnd == hwnd))
785 if ((!first && !last) ||
786 ((msgQueue->msg >= first) && (msgQueue->msg <= last)))
788 msg->hwnd = msgQueue->hWnd;
789 msg->message = msgQueue->msg;
790 msg->wParam = msgQueue->wParam;
791 msg->lParam = msgQueue->lParam;
792 if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
798 /* Now find a normal message */
799 pos = MSG_FindMsg( msgQueue, hwnd, first, last );
802 QMSG *qmsg = &msgQueue->messages[pos];
804 msgQueue->GetMessageTimeVal = msg->time;
805 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
806 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
808 if (flags & PM_REMOVE) MSG_RemoveMsg( msgQueue, pos );
812 /* Now find a hardware event */
813 if (MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
816 msgQueue->GetMessageTimeVal = msg->time;
817 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
818 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
822 /* Now handle a WM_QUIT message */
823 if (msgQueue->wPostQMsg)
826 msg->message = WM_QUIT;
827 msg->wParam = msgQueue->wExitCode;
832 /* Now find a WM_PAINT message */
833 if ((msgQueue->status & QS_PAINT) && (mask & QS_PAINT))
835 msg->hwnd = WIN_FindWinToRepaint( hwnd );
836 msg->message = WM_PAINT;
839 if (msg->hwnd != 0) break;
842 /* Finally handle WM_TIMER messages */
843 if ((msgQueue->status & QS_TIMER) && (mask & QS_TIMER))
845 if (TIMER_CheckTimer( &nextExp, msg, hwnd, flags & PM_REMOVE ))
846 break; /* Got a timer msg */
848 else nextExp = -1; /* No timeout needed */
852 /* Wait until something happens */
855 if (!MSG_WaitXEvent( 0 )) return FALSE; /* No pending event */
857 else /* Wait for an event, then restart the loop */
858 MSG_WaitXEvent( nextExp );
861 /* We got a message */
862 if (peek) return TRUE;
863 else return (msg->message != WM_QUIT);
867 /***********************************************************************
868 * MSG_InternalGetMessage
870 * GetMessage() function for internal use. Behave like GetMessage(),
871 * but also call message filters and optionally send WM_ENTERIDLE messages.
872 * 'hwnd' must be the handle of the dialog or menu window.
873 * 'code' is the message filter value (MSGF_??? codes).
875 BOOL MSG_InternalGetMessage( SEGPTR msg, HWND hwnd, HWND hwndOwner, short code,
876 WORD flags, BOOL sendIdle )
882 if (!MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
883 0, 0, 0, flags, TRUE ))
885 /* No message present -> send ENTERIDLE and wait */
886 SendMessage( hwndOwner, WM_ENTERIDLE, code, (LPARAM)hwnd );
887 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
888 0, 0, 0, flags, FALSE );
891 else /* Always wait for a message */
892 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
893 0, 0, 0, flags, FALSE );
895 if (!CallMsgFilter( msg, code ))
896 return (((MSG *)PTR_SEG_TO_LIN(msg))->message != WM_QUIT);
898 /* Message filtered -> remove it from the queue */
899 /* if it's still there. */
900 if (!(flags & PM_REMOVE))
901 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
902 0, 0, 0, PM_REMOVE, TRUE );
907 /***********************************************************************
908 * PeekMessage (USER.109)
910 BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
912 return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
916 /***********************************************************************
917 * GetMessage (USER.108)
919 BOOL GetMessage( SEGPTR msg, HWND hwnd, UINT first, UINT last )
921 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
922 hwnd, first, last, PM_REMOVE, FALSE );
923 HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
924 return (((MSG *)PTR_SEG_TO_LIN(msg))->message != WM_QUIT);
929 /***********************************************************************
930 * PostMessage (USER.110)
932 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
938 msg.message = message;
941 msg.time = GetTickCount();
946 if (DDE_PostMessage(&msg))
948 #endif /* CONFIG_IPC */
950 if (hwnd == HWND_BROADCAST) {
951 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
952 hwnd = GetTopWindow(GetDesktopWindow());
954 if (!(wndPtr = WIN_FindWndPtr(hwnd))) break;
955 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) {
956 dprintf_msg(stddeb,"BROADCAST Message to hWnd="NPFMT" m=%04X w=%04X l=%08lX !\n",
957 hwnd, message, wParam, lParam);
958 PostMessage(hwnd, message, wParam, lParam);
960 hwnd = wndPtr->hwndNext;
962 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
966 wndPtr = WIN_FindWndPtr( hwnd );
967 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
969 return MSG_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
972 /***********************************************************************
973 * PostAppMessage (USER.116)
975 BOOL PostAppMessage( HTASK hTask, WORD message, WORD wParam, LONG lParam )
979 if (GetTaskQueue(hTask) == 0) return FALSE;
981 msg.message = message;
984 msg.time = GetTickCount();
988 return MSG_AddMsg( GetTaskQueue(hTask), &msg, 0 );
992 /***********************************************************************
993 * SendMessage (USER.111)
995 LRESULT SendMessage( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1005 } msgstruct = { lParam, wParam, msg, hwnd };
1008 MSG DDE_msg = { hwnd, msg, wParam, lParam };
1009 if (DDE_SendMessage(&DDE_msg)) return TRUE;
1010 #endif /* CONFIG_IPC */
1012 if (hwnd == HWND_BROADCAST)
1014 dprintf_msg(stddeb,"SendMessage // HWND_BROADCAST !\n");
1015 hwnd = GetTopWindow(GetDesktopWindow());
1018 if (!(wndPtr = WIN_FindWndPtr(hwnd))) break;
1019 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1021 dprintf_msg(stddeb,"BROADCAST Message to hWnd="NPFMT" m=%04X w=%04lX l=%08lX !\n",
1022 hwnd, msg, (DWORD)wParam, lParam);
1023 ret |= SendMessage( hwnd, msg, wParam, lParam );
1025 hwnd = wndPtr->hwndNext;
1027 dprintf_msg(stddeb,"SendMessage // End of HWND_BROADCAST !\n");
1031 EnterSpyMessage(SPY_SENDMESSAGE, hwnd, msg, wParam, lParam);
1033 HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)MAKE_SEGPTR(&msgstruct) );
1034 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1036 ExitSpyMessage(SPY_RESULT_INVALIDHWND,hwnd,msg,0);
1039 ret = CallWindowProc( wndPtr->lpfnWndProc, msgstruct.hWnd, msgstruct.wMsg,
1040 msgstruct.wParam, msgstruct.lParam );
1041 ExitSpyMessage(SPY_RESULT_OK,hwnd,msg,ret);
1046 /***********************************************************************
1047 * WaitMessage (USER.112)
1049 void WaitMessage( void )
1052 MESSAGEQUEUE *queue;
1053 LONG nextExp = -1; /* Next timer expiration time */
1056 DDE_GetRemoteMessage();
1057 #endif /* CONFIG_IPC */
1059 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return;
1060 if ((queue->wPostQMsg) ||
1061 (queue->status & (QS_SENDMESSAGE | QS_PAINT)) ||
1062 (queue->msgCount) || (sysMsgQueue->msgCount) )
1064 if ((queue->status & QS_TIMER) &&
1065 TIMER_CheckTimer( &nextExp, &msg, 0, FALSE))
1067 /* FIXME: (dde) must check DDE & X-events simultaneously */
1068 MSG_WaitXEvent( nextExp );
1072 /***********************************************************************
1073 * TranslateMessage (USER.113)
1075 BOOL TranslateMessage( LPMSG msg )
1077 int message = msg->message;
1079 if ((message == WM_KEYDOWN) || (message == WM_KEYUP) ||
1080 (message == WM_SYSKEYDOWN) || (message == WM_SYSKEYUP))
1082 dprintf_msg(stddeb, "Translating key message\n" );
1089 /***********************************************************************
1090 * DispatchMessage (USER.114)
1092 LONG DispatchMessage( const MSG* msg )
1098 EnterSpyMessage( SPY_DISPATCHMESSAGE, msg->hwnd, msg->message,
1099 msg->wParam, msg->lParam );
1101 /* Process timer messages */
1102 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1107 HINSTANCE ds = msg->hwnd ? WIN_GetWindowInstance( msg->hwnd )
1108 : (HINSTANCE)CURRENT_DS;
1110 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1111 return CallWndProc( (WNDPROC)msg->lParam, ds, msg->hwnd,
1112 msg->message, msg->wParam, GetTickCount() );
1116 if (!msg->hwnd) return 0;
1117 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1118 if (!wndPtr->lpfnWndProc) return 0;
1119 painting = (msg->message == WM_PAINT);
1120 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1121 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1122 retval = CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message,
1123 msg->wParam, msg->lParam );
1124 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1125 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1127 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd "NPFMT"!\n",
1129 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1130 /* Validate the update region to avoid infinite WM_PAINT loop */
1131 ValidateRect( msg->hwnd, NULL );
1137 /***********************************************************************
1138 * GetMessagePos (USER.119)
1140 DWORD GetMessagePos(void)
1142 MESSAGEQUEUE *queue;
1144 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1145 return queue->GetMessagePosVal;
1149 /***********************************************************************
1150 * GetMessageTime (USER.120)
1152 LONG GetMessageTime(void)
1154 MESSAGEQUEUE *queue;
1156 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1157 return queue->GetMessageTimeVal;
1161 /***********************************************************************
1162 * GetMessageExtraInfo (USER.288)
1164 LONG GetMessageExtraInfo(void)
1166 MESSAGEQUEUE *queue;
1168 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1169 return queue->GetMessageExtraInfoVal;
1173 /***********************************************************************
1174 * RegisterWindowMessage (USER.118)
1176 WORD RegisterWindowMessage( SEGPTR str )
1178 dprintf_msg(stddeb, "RegisterWindowMessage: '"SPFMT"'\n", str );
1179 return GlobalAddAtom( str );
1183 /***********************************************************************
1184 * GetTickCount (USER.13) (KERNEL32.299)
1186 DWORD GetTickCount(void)
1189 gettimeofday( &t, NULL );
1190 return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
1193 /***********************************************************************
1194 * GetCurrentTime (effectively identical to GetTickCount)
1196 DWORD GetCurrentTime(void)
1198 return GetTickCount();
1201 /***********************************************************************
1202 * InSendMessage (USER.192
1204 * According to the book, this should return true iff the current message
1205 * was send from another application. In that case, the application should
1206 * invoke ReplyMessage before calling message relevant API.
1207 * Currently, Wine will always return FALSE, as there is no other app.
1209 BOOL InSendMessage()