Release 951003
[wine/multimedia.git] / windows / message.c
blobadefb1475e9c25dfed35d84a87d8adc6eaf97008
1 /*
2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 #include <stdlib.h>
8 #include <sys/time.h>
9 #include <sys/types.h>
10 #include <errno.h>
12 #include "message.h"
13 #include "win.h"
14 #include "gdi.h"
15 #include "sysmetrics.h"
16 #include "hook.h"
17 #include "event.h"
18 #include "spy.h"
19 #include "winpos.h"
20 #include "atom.h"
21 #include "dde.h"
22 #include "stddebug.h"
23 /* #define DEBUG_MSG */
24 #include "debug.h"
27 #define HWND_BROADCAST ((HWND)0xffff)
29 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
32 extern BOOL TIMER_CheckTimer( LONG *next, MSG *msg,
33 HWND hwnd, BOOL remove ); /* timer.c */
35 /* System message queue (for hardware events) */
36 static HANDLE hmemSysMsgQueue = 0;
37 static MESSAGEQUEUE * sysMsgQueue = NULL;
39 /* Double-click time */
40 static int doubleClickSpeed = 452;
43 /***********************************************************************
44 * MSG_CreateMsgQueue
46 * Create a message queue.
48 static HANDLE MSG_CreateMsgQueue( int size )
50 HANDLE hQueue;
51 MESSAGEQUEUE * msgQueue;
52 int queueSize;
54 queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
55 if (!(hQueue = GlobalAlloc( GMEM_FIXED, queueSize ))) return 0;
56 msgQueue = (MESSAGEQUEUE *) GlobalLock( hQueue );
57 msgQueue->next = 0;
58 msgQueue->hTask = 0;
59 msgQueue->msgSize = sizeof(QMSG);
60 msgQueue->msgCount = 0;
61 msgQueue->nextMessage = 0;
62 msgQueue->nextFreeMessage = 0;
63 msgQueue->queueSize = size;
64 msgQueue->GetMessageTimeVal = 0;
65 msgQueue->GetMessagePosVal = 0;
66 msgQueue->GetMessageExtraInfoVal = 0;
67 msgQueue->lParam = 0;
68 msgQueue->wParam = 0;
69 msgQueue->msg = 0;
70 msgQueue->hWnd = 0;
71 msgQueue->wPostQMsg = 0;
72 msgQueue->wExitCode = 0;
73 msgQueue->InSendMessageHandle = 0;
74 msgQueue->wPaintCount = 0;
75 msgQueue->wTimerCount = 0;
76 msgQueue->tempStatus = 0;
77 msgQueue->status = 0;
78 GlobalUnlock( hQueue );
79 return hQueue;
83 /***********************************************************************
84 * MSG_CreateSysMsgQueue
86 * Create the system message queue, and set the double-click speed.
87 * Must be called only once.
89 BOOL MSG_CreateSysMsgQueue( int size )
91 if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
92 else if (size <= 0) size = 1;
93 if (!(hmemSysMsgQueue = MSG_CreateMsgQueue( size ))) return FALSE;
94 sysMsgQueue = (MESSAGEQUEUE *) GlobalLock( hmemSysMsgQueue );
95 doubleClickSpeed = GetProfileInt( "windows", "DoubleClickSpeed", 452 );
96 return TRUE;
100 /***********************************************************************
101 * MSG_AddMsg
103 * Add a message to the queue. Return FALSE if queue is full.
105 static int MSG_AddMsg( HANDLE hQueue, MSG * msg, DWORD extraInfo )
107 int pos;
108 MESSAGEQUEUE *msgQueue;
110 if (!(msgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return FALSE;
111 pos = msgQueue->nextFreeMessage;
113 /* Check if queue is full */
114 if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0)) {
115 fprintf(stderr,"MSG_AddMsg // queue is full !\n");
116 return FALSE;
119 /* Store message */
120 msgQueue->messages[pos].msg = *msg;
121 msgQueue->messages[pos].extraInfo = extraInfo;
122 if (pos < msgQueue->queueSize-1) pos++;
123 else pos = 0;
124 msgQueue->nextFreeMessage = pos;
125 msgQueue->msgCount++;
126 msgQueue->status |= QS_POSTMESSAGE;
127 msgQueue->tempStatus |= QS_POSTMESSAGE;
128 return TRUE;
132 /***********************************************************************
133 * MSG_FindMsg
135 * Find a message matching the given parameters. Return -1 if none available.
137 static int MSG_FindMsg(MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last)
139 int i, pos = msgQueue->nextMessage;
141 dprintf_msg(stddeb,"MSG_FindMsg: hwnd=0x"NPFMT"\n\n", hwnd );
143 if (!msgQueue->msgCount) return -1;
144 if (!hwnd && !first && !last) return pos;
146 for (i = 0; i < msgQueue->msgCount; i++)
148 MSG * msg = &msgQueue->messages[pos].msg;
150 if (!hwnd || (msg->hwnd == hwnd))
152 if (!first && !last) return pos;
153 if ((msg->message >= first) && (msg->message <= last)) return pos;
155 if (pos < msgQueue->queueSize-1) pos++;
156 else pos = 0;
158 return -1;
162 /***********************************************************************
163 * MSG_RemoveMsg
165 * Remove a message from the queue (pos must be a valid position).
167 static void MSG_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
169 if (pos >= msgQueue->nextMessage)
171 for ( ; pos > msgQueue->nextMessage; pos--)
172 msgQueue->messages[pos] = msgQueue->messages[pos-1];
173 msgQueue->nextMessage++;
174 if (msgQueue->nextMessage >= msgQueue->queueSize)
175 msgQueue->nextMessage = 0;
177 else
179 for ( ; pos < msgQueue->nextFreeMessage; pos++)
180 msgQueue->messages[pos] = msgQueue->messages[pos+1];
181 if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
182 else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
184 msgQueue->msgCount--;
185 if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE;
186 msgQueue->tempStatus = 0;
190 /***********************************************************************
191 * MSG_GetWindowForEvent
193 * Find the window and hittest for a mouse event.
195 static INT MSG_GetWindowForEvent( POINT pt, HWND *phwnd )
197 WND *wndPtr;
198 HWND hwnd;
199 INT hittest = HTERROR;
200 INT x, y;
202 *phwnd = hwnd = GetDesktopWindow();
203 x = pt.x;
204 y = pt.y;
205 while (hwnd)
207 /* If point is in window, and window is visible, and it */
208 /* is enabled (or it's a top-level window), then explore */
209 /* its children. Otherwise, go to the next window. */
211 wndPtr = WIN_FindWndPtr( hwnd );
212 if ((wndPtr->dwStyle & WS_VISIBLE) &&
213 (!(wndPtr->dwStyle & WS_DISABLED) ||
214 !(wndPtr->dwStyle & WS_CHILD)) &&
215 (x >= wndPtr->rectWindow.left) &&
216 (x < wndPtr->rectWindow.right) &&
217 (y >= wndPtr->rectWindow.top) &&
218 (y < wndPtr->rectWindow.bottom))
220 *phwnd = hwnd;
221 x -= wndPtr->rectClient.left;
222 y -= wndPtr->rectClient.top;
223 /* If window is minimized or disabled, ignore its children */
224 if ((wndPtr->dwStyle & WS_MINIMIZE) ||
225 (wndPtr->dwStyle & WS_DISABLED)) break;
226 hwnd = wndPtr->hwndChild;
228 else hwnd = wndPtr->hwndNext;
231 /* Make point relative to parent again */
233 wndPtr = WIN_FindWndPtr( *phwnd );
234 x += wndPtr->rectClient.left;
235 y += wndPtr->rectClient.top;
237 /* Send the WM_NCHITTEST message */
239 while (*phwnd)
241 wndPtr = WIN_FindWndPtr( *phwnd );
242 if (wndPtr->dwStyle & WS_DISABLED) hittest = HTERROR;
243 else hittest = (INT)SendMessage( *phwnd, WM_NCHITTEST, 0,
244 MAKELONG( pt.x, pt.y ) );
245 if (hittest != HTTRANSPARENT) break; /* Found the window */
246 hwnd = wndPtr->hwndNext;
247 while (hwnd)
249 WND *nextPtr = WIN_FindWndPtr( hwnd );
250 if ((nextPtr->dwStyle & WS_VISIBLE) &&
251 (x >= nextPtr->rectWindow.left) &&
252 (x < nextPtr->rectWindow.right) &&
253 (y >= nextPtr->rectWindow.top) &&
254 (y < nextPtr->rectWindow.bottom)) break;
255 hwnd = nextPtr->hwndNext;
257 if (hwnd) *phwnd = hwnd; /* Found a suitable sibling */
258 else /* Go back to the parent */
260 if (!(*phwnd = wndPtr->hwndParent)) break;
261 wndPtr = WIN_FindWndPtr( *phwnd );
262 x += wndPtr->rectClient.left;
263 y += wndPtr->rectClient.top;
267 if (!*phwnd) *phwnd = GetDesktopWindow();
268 return hittest;
272 /***********************************************************************
273 * MSG_TranslateMouseMsg
275 * Translate an mouse hardware event into a real mouse message.
276 * Return value indicates whether the translated message must be passed
277 * to the user.
278 * Actions performed:
279 * - Find the window for this message.
280 * - Translate button-down messages in double-clicks.
281 * - Send the WM_NCHITTEST message to find where the cursor is.
282 * - Activate the window if needed.
283 * - Translate the message into a non-client message, or translate
284 * the coordinates to client coordinates.
285 * - Send the WM_SETCURSOR message.
287 static BOOL MSG_TranslateMouseMsg( MSG *msg, BOOL remove )
289 BOOL eatMsg = FALSE;
290 INT hittest;
291 static DWORD lastClickTime = 0;
292 static WORD lastClickMsg = 0;
293 static POINT lastClickPos = { 0, 0 };
295 BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
296 (msg->message == WM_RBUTTONDOWN) ||
297 (msg->message == WM_MBUTTONDOWN));
299 /* Find the window */
301 if (GetCapture())
303 msg->hwnd = GetCapture();
304 msg->lParam = MAKELONG( msg->pt.x, msg->pt.y );
305 ScreenToClient( msg->hwnd, (LPPOINT)&msg->lParam );
306 return TRUE; /* No need to further process the message */
309 if ((hittest = MSG_GetWindowForEvent( msg->pt, &msg->hwnd )) != HTERROR)
312 /* Send the WM_PARENTNOTIFY message */
314 if (mouseClick) WIN_SendParentNotify( msg->hwnd, msg->message, 0,
315 MAKELONG( msg->pt.x, msg->pt.y ) );
317 /* Activate the window if needed */
319 if (mouseClick)
321 HWND hwndTop = WIN_GetTopParent( msg->hwnd );
322 if (hwndTop != GetActiveWindow())
324 LONG ret = SendMessage( msg->hwnd, WM_MOUSEACTIVATE,
325 (WPARAM)hwndTop,
326 MAKELONG( hittest, msg->message ) );
327 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
328 eatMsg = TRUE;
329 if ((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
331 SetWindowPos( hwndTop, HWND_TOP, 0, 0, 0, 0,
332 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
333 WINPOS_ChangeActiveWindow( hwndTop, TRUE );
339 /* Send the WM_SETCURSOR message */
341 SendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
342 MAKELONG( hittest, msg->message ));
343 if (eatMsg) return FALSE;
345 /* Check for double-click */
347 if (mouseClick)
349 BOOL dbl_click = FALSE;
351 if ((msg->message == lastClickMsg) &&
352 (msg->time - lastClickTime < doubleClickSpeed) &&
353 (abs(msg->pt.x - lastClickPos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
354 (abs(msg->pt.y - lastClickPos.y) < SYSMETRICS_CYDOUBLECLK/2))
355 dbl_click = TRUE;
357 if (dbl_click && (hittest == HTCLIENT))
359 /* Check whether window wants the double click message. */
360 WND * wndPtr = WIN_FindWndPtr( msg->hwnd );
361 if (!wndPtr || !(WIN_CLASS_STYLE(wndPtr) & CS_DBLCLKS))
362 dbl_click = FALSE;
365 if (dbl_click) switch(msg->message)
367 case WM_LBUTTONDOWN: msg->message = WM_LBUTTONDBLCLK; break;
368 case WM_RBUTTONDOWN: msg->message = WM_RBUTTONDBLCLK; break;
369 case WM_MBUTTONDOWN: msg->message = WM_MBUTTONDBLCLK; break;
372 if (remove)
374 lastClickTime = msg->time;
375 lastClickMsg = msg->message;
376 lastClickPos = msg->pt;
380 /* Build the translated message */
382 msg->lParam = MAKELONG( msg->pt.x, msg->pt.y );
383 if (hittest == HTCLIENT)
385 ScreenToClient( msg->hwnd, (LPPOINT)&msg->lParam );
387 else
389 msg->wParam = hittest;
390 msg->message += WM_NCLBUTTONDOWN - WM_LBUTTONDOWN;
393 return TRUE;
397 /***********************************************************************
398 * MSG_TranslateKeyboardMsg
400 * Translate an keyboard hardware event into a real message.
401 * Return value indicates whether the translated message must be passed
402 * to the user.
404 static BOOL MSG_TranslateKeyboardMsg( MSG *msg )
406 /* Should check Ctrl-Esc and PrintScreen here */
408 msg->hwnd = GetFocus();
409 if (!msg->hwnd)
411 /* Send the message to the active window instead, */
412 /* translating messages to their WM_SYS equivalent */
413 msg->hwnd = GetActiveWindow();
414 msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
416 return TRUE;
420 /***********************************************************************
421 * MSG_PeekHardwareMsg
423 * Peek for a hardware message matching the hwnd and message filters.
425 static BOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, WORD first, WORD last,
426 BOOL remove )
428 int i, pos = sysMsgQueue->nextMessage;
430 for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
432 if (pos >= sysMsgQueue->queueSize) pos = 0;
433 *msg = sysMsgQueue->messages[pos].msg;
435 /* Translate message */
437 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
439 if (!MSG_TranslateMouseMsg( msg, remove )) continue;
441 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
443 if (!MSG_TranslateKeyboardMsg( msg )) continue;
445 else continue; /* Should never happen */
447 /* Check message against filters */
449 if (hwnd && (msg->hwnd != hwnd)) continue;
450 if ((first || last) &&
451 ((msg->message < first) || (msg->message > last))) continue;
452 if ((msg->hwnd != GetDesktopWindow()) &&
453 (GetWindowTask(msg->hwnd) != GetCurrentTask()))
454 continue; /* Not for this task */
455 if (remove) MSG_RemoveMsg( sysMsgQueue, pos );
456 return TRUE;
458 return FALSE;
462 /**********************************************************************
463 * SetDoubleClickTime (USER.20)
465 void SetDoubleClickTime( WORD interval )
467 if (interval == 0)
468 doubleClickSpeed = 500;
469 else
470 doubleClickSpeed = interval;
474 /**********************************************************************
475 * GetDoubleClickTime (USER.21)
477 WORD GetDoubleClickTime()
479 return (WORD)doubleClickSpeed;
483 /***********************************************************************
484 * MSG_IncPaintCount
486 void MSG_IncPaintCount( HANDLE hQueue )
488 MESSAGEQUEUE *queue;
490 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
491 queue->wPaintCount++;
492 queue->status |= QS_PAINT;
493 queue->tempStatus |= QS_PAINT;
497 /***********************************************************************
498 * MSG_DecPaintCount
500 void MSG_DecPaintCount( HANDLE hQueue )
502 MESSAGEQUEUE *queue;
504 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
505 queue->wPaintCount--;
506 if (!queue->wPaintCount) queue->status &= ~QS_PAINT;
510 /***********************************************************************
511 * MSG_IncTimerCount
513 void MSG_IncTimerCount( HANDLE hQueue )
515 MESSAGEQUEUE *queue;
517 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
518 queue->wTimerCount++;
519 queue->status |= QS_TIMER;
520 queue->tempStatus |= QS_TIMER;
524 /***********************************************************************
525 * MSG_DecTimerCount
527 void MSG_DecTimerCount( HANDLE hQueue )
529 MESSAGEQUEUE *queue;
531 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
532 queue->wTimerCount--;
533 if (!queue->wTimerCount) queue->status &= ~QS_TIMER;
537 /***********************************************************************
538 * hardware_event
540 * Add an event to the system message queue.
541 * Note: the position is relative to the desktop window.
543 void hardware_event( WORD message, WORD wParam, LONG lParam,
544 int xPos, int yPos, DWORD time, DWORD extraInfo )
546 MSG *msg;
547 int pos;
549 if (!sysMsgQueue) return;
550 pos = sysMsgQueue->nextFreeMessage;
552 /* Merge with previous event if possible */
554 if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
556 if (pos > 0) pos--;
557 else pos = sysMsgQueue->queueSize - 1;
558 msg = &sysMsgQueue->messages[pos].msg;
559 if ((msg->message == message) && (msg->wParam == wParam))
560 sysMsgQueue->msgCount--; /* Merge events */
561 else
562 pos = sysMsgQueue->nextFreeMessage; /* Don't merge */
565 /* Check if queue is full */
567 if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
569 /* Queue is full, beep (but not on every mouse motion...) */
570 if (message != WM_MOUSEMOVE) MessageBeep(0);
571 return;
574 /* Store message */
576 msg = &sysMsgQueue->messages[pos].msg;
577 msg->hwnd = 0;
578 msg->message = message;
579 msg->wParam = wParam;
580 msg->lParam = lParam;
581 msg->time = time;
582 msg->pt.x = xPos & 0xffff;
583 msg->pt.y = yPos & 0xffff;
584 sysMsgQueue->messages[pos].extraInfo = extraInfo;
585 if (pos < sysMsgQueue->queueSize - 1) pos++;
586 else pos = 0;
587 sysMsgQueue->nextFreeMessage = pos;
588 sysMsgQueue->msgCount++;
592 /***********************************************************************
593 * MSG_GetHardwareMessage
595 * Like GetMessage(), but only return mouse and keyboard events.
596 * Used internally for window moving and resizing. Mouse messages
597 * are not translated.
598 * Warning: msg->hwnd is always 0.
600 BOOL MSG_GetHardwareMessage( LPMSG msg )
602 int pos;
603 XEvent event;
605 while(1)
607 if ((pos = MSG_FindMsg( sysMsgQueue, 0, 0, 0 )) != -1)
609 *msg = sysMsgQueue->messages[pos].msg;
610 MSG_RemoveMsg( sysMsgQueue, pos );
611 break;
613 XNextEvent( display, &event );
614 EVENT_ProcessEvent( &event );
616 return TRUE;
620 /***********************************************************************
621 * SetMessageQueue (USER.266)
623 BOOL SetMessageQueue( int size )
625 HGLOBAL hQueue;
626 MESSAGEQUEUE *queuePtr;
628 if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
630 /* Free the old message queue */
631 if ((hQueue = GetTaskQueue(0)) != 0)
633 GlobalUnlock( hQueue );
634 GlobalFree( hQueue );
637 if (!(hQueue = MSG_CreateMsgQueue( size ))) return FALSE;
638 queuePtr = (MESSAGEQUEUE *)GlobalLock( hQueue );
639 queuePtr->hTask = GetCurrentTask();
640 SetTaskQueue( 0, hQueue );
641 return TRUE;
645 /***********************************************************************
646 * GetWindowTask (USER.224)
648 HTASK GetWindowTask( HWND hwnd )
650 WND *wndPtr = WIN_FindWndPtr( hwnd );
651 MESSAGEQUEUE *queuePtr;
653 if (!wndPtr) return 0;
654 queuePtr = (MESSAGEQUEUE *)GlobalLock( wndPtr->hmemTaskQ );
655 if (!queuePtr) return 0;
656 return queuePtr->hTask;
660 /***********************************************************************
661 * PostQuitMessage (USER.6)
663 void PostQuitMessage( int exitCode )
665 MESSAGEQUEUE *queue;
667 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return;
668 queue->wPostQMsg = TRUE;
669 queue->wExitCode = exitCode;
673 /***********************************************************************
674 * GetQueueStatus (USER.334)
676 DWORD GetQueueStatus( int flags )
678 MESSAGEQUEUE *queue;
679 DWORD ret;
681 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
682 ret = MAKELONG( queue->tempStatus, queue->status );
683 queue->tempStatus = 0;
684 return ret & MAKELONG( flags, flags );
688 /***********************************************************************
689 * GetInputState (USER.335)
691 BOOL GetInputState()
693 MESSAGEQUEUE *queue;
695 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return FALSE;
696 return queue->status & (QS_KEY | QS_MOUSEBUTTON);
700 /***********************************************************************
701 * MSG_Synchronize
703 * Synchronize with the X server. Should not be used too often.
705 void MSG_Synchronize()
707 XEvent event;
709 XSync( display, False );
710 while (XPending( display ))
712 XNextEvent( display, &event );
713 EVENT_ProcessEvent( &event );
718 /***********************************************************************
719 * MSG_WaitXEvent
721 * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
722 * Return TRUE if an event is pending, FALSE on timeout or error
723 * (for instance lost connection with the server).
725 BOOL MSG_WaitXEvent( LONG maxWait )
727 fd_set read_set;
728 struct timeval timeout;
729 XEvent event;
730 int fd = ConnectionNumber(display);
732 if (!XPending(display) && (maxWait != -1))
734 FD_ZERO( &read_set );
735 FD_SET( fd, &read_set );
737 timeout.tv_usec = (maxWait % 1000) * 1000;
738 timeout.tv_sec = maxWait / 1000;
740 #ifdef CONFIG_IPC
741 sigsetjmp(env_wait_x, 1);
742 stop_wait_op= CONT;
744 if (DDE_GetRemoteMessage()) {
745 while(DDE_GetRemoteMessage())
747 return TRUE;
749 stop_wait_op= STOP_WAIT_X;
750 /* The code up to the next "stop_wait_op= CONT" must be reentrant */
751 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
752 !XPending(display)) {
753 stop_wait_op= CONT;
754 return FALSE;
755 } else {
756 stop_wait_op= CONT;
758 #else /* CONFIG_IPC */
759 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
760 return FALSE; /* Timeout or error */
761 #endif /* CONFIG_IPC */
765 /* Process the event (and possibly others that occurred in the meantime) */
769 #ifdef CONFIG_IPC
770 if (DDE_GetRemoteMessage())
772 while(DDE_GetRemoteMessage()) ;
773 return TRUE;
775 #endif /* CONFIG_IPC */
777 XNextEvent( display, &event );
778 EVENT_ProcessEvent( &event );
780 while (XPending( display ));
781 return TRUE;
785 /***********************************************************************
786 * MSG_PeekMessage
788 static BOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last,
789 WORD flags, BOOL peek )
791 int pos, mask;
792 MESSAGEQUEUE *msgQueue;
793 LONG nextExp; /* Next timer expiration time */
795 #ifdef CONFIG_IPC
796 DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
797 DDE_GetRemoteMessage();
798 #endif /* CONFIG_IPC */
800 if (first || last)
802 mask = QS_POSTMESSAGE; /* Always selectioned */
803 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
804 if ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) mask |= QS_MOUSE;
805 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
806 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
807 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
809 else mask = QS_MOUSE | QS_KEY | QS_POSTMESSAGE | QS_TIMER | QS_PAINT;
811 while(1)
813 msgQueue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) );
814 if (!msgQueue) return FALSE;
816 /* First handle a message put by SendMessage() */
817 if (msgQueue->status & QS_SENDMESSAGE)
819 if (!hwnd || (msgQueue->hWnd == hwnd))
821 if ((!first && !last) ||
822 ((msgQueue->msg >= first) && (msgQueue->msg <= last)))
824 msg->hwnd = msgQueue->hWnd;
825 msg->message = msgQueue->msg;
826 msg->wParam = msgQueue->wParam;
827 msg->lParam = msgQueue->lParam;
828 if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
829 break;
834 /* Now find a normal message */
835 pos = MSG_FindMsg( msgQueue, hwnd, first, last );
836 if (pos != -1)
838 QMSG *qmsg = &msgQueue->messages[pos];
839 *msg = qmsg->msg;
840 msgQueue->GetMessageTimeVal = msg->time;
841 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
842 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
844 if (flags & PM_REMOVE) MSG_RemoveMsg( msgQueue, pos );
845 break;
848 /* Now find a hardware event */
849 if (MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
851 /* Got one */
852 msgQueue->GetMessageTimeVal = msg->time;
853 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
854 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
855 break;
858 /* Now handle a WM_QUIT message */
859 if (msgQueue->wPostQMsg)
861 msg->hwnd = hwnd;
862 msg->message = WM_QUIT;
863 msg->wParam = msgQueue->wExitCode;
864 msg->lParam = 0;
865 break;
868 /* Now find a WM_PAINT message */
869 if ((msgQueue->status & QS_PAINT) && (mask & QS_PAINT))
871 msg->hwnd = WIN_FindWinToRepaint( hwnd );
872 msg->message = WM_PAINT;
873 msg->wParam = 0;
874 msg->lParam = 0;
875 if (msg->hwnd != 0) break;
878 /* Finally handle WM_TIMER messages */
879 if ((msgQueue->status & QS_TIMER) && (mask & QS_TIMER))
881 if (TIMER_CheckTimer( &nextExp, msg, hwnd, flags & PM_REMOVE ))
882 break; /* Got a timer msg */
884 else nextExp = -1; /* No timeout needed */
886 Yield();
888 /* Wait until something happens */
889 if (peek)
891 if (!MSG_WaitXEvent( 0 )) return FALSE; /* No pending event */
893 else /* Wait for an event, then restart the loop */
894 MSG_WaitXEvent( nextExp );
897 /* We got a message */
898 if (peek) return TRUE;
899 else return (msg->message != WM_QUIT);
903 /***********************************************************************
904 * MSG_InternalGetMessage
906 * GetMessage() function for internal use. Behave like GetMessage(),
907 * but also call message filters and optionally send WM_ENTERIDLE messages.
908 * 'hwnd' must be the handle of the dialog or menu window.
909 * 'code' is the message filter value (MSGF_??? codes).
911 BOOL MSG_InternalGetMessage( SEGPTR msg, HWND hwnd, HWND hwndOwner, short code,
912 WORD flags, BOOL sendIdle )
914 for (;;)
916 if (sendIdle)
918 if (!MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
919 0, 0, 0, flags, TRUE ))
921 /* No message present -> send ENTERIDLE and wait */
922 SendMessage( hwndOwner, WM_ENTERIDLE, code, (LPARAM)hwnd );
923 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
924 0, 0, 0, flags, FALSE );
927 else /* Always wait for a message */
928 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
929 0, 0, 0, flags, FALSE );
931 if (!CallMsgFilter( msg, code ))
932 return (((MSG *)PTR_SEG_TO_LIN(msg))->message != WM_QUIT);
934 /* Message filtered -> remove it from the queue */
935 /* if it's still there. */
936 if (!(flags & PM_REMOVE))
937 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
938 0, 0, 0, PM_REMOVE, TRUE );
943 /***********************************************************************
944 * PeekMessage (USER.109)
946 BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
948 return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
952 /***********************************************************************
953 * GetMessage (USER.108)
955 BOOL GetMessage( SEGPTR msg, HWND hwnd, WORD first, WORD last )
957 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
958 hwnd, first, last, PM_REMOVE, FALSE );
959 CALL_TASK_HOOK( WH_GETMESSAGE, 0, 0, (LPARAM)msg );
960 CALL_SYSTEM_HOOK( WH_GETMESSAGE, 0, 0, (LPARAM)msg );
961 return (((MSG *)PTR_SEG_TO_LIN(msg))->message != WM_QUIT);
966 /***********************************************************************
967 * PostMessage (USER.110)
969 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
971 MSG msg;
972 WND *wndPtr;
974 msg.hwnd = hwnd;
975 msg.message = message;
976 msg.wParam = wParam;
977 msg.lParam = lParam;
978 msg.time = GetTickCount();
979 msg.pt.x = 0;
980 msg.pt.y = 0;
982 #ifdef CONFIG_IPC
983 if (DDE_PostMessage(&msg))
984 return TRUE;
985 #endif /* CONFIG_IPC */
987 if (hwnd == HWND_BROADCAST) {
988 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
989 hwnd = GetTopWindow(GetDesktopWindow());
990 while (hwnd) {
991 if (!(wndPtr = WIN_FindWndPtr(hwnd))) break;
992 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) {
993 dprintf_msg(stddeb,"BROADCAST Message to hWnd="NPFMT" m=%04X w=%04X l=%08lX !\n",
994 hwnd, message, wParam, lParam);
995 PostMessage(hwnd, message, wParam, lParam);
997 hwnd = wndPtr->hwndNext;
999 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
1000 return TRUE;
1003 wndPtr = WIN_FindWndPtr( hwnd );
1004 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
1006 return MSG_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
1009 /***********************************************************************
1010 * PostAppMessage (USER.116)
1012 BOOL PostAppMessage( HTASK hTask, WORD message, WORD wParam, LONG lParam )
1014 MSG msg;
1016 if (GetTaskQueue(hTask) == 0) return FALSE;
1017 msg.hwnd = 0;
1018 msg.message = message;
1019 msg.wParam = wParam;
1020 msg.lParam = lParam;
1021 msg.time = GetTickCount();
1022 msg.pt.x = 0;
1023 msg.pt.y = 0;
1025 return MSG_AddMsg( GetTaskQueue(hTask), &msg, 0 );
1029 /***********************************************************************
1030 * SendMessage (USER.111)
1032 LRESULT SendMessage( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1034 WND * wndPtr;
1035 LONG ret;
1036 struct
1038 LPARAM lParam;
1039 WPARAM wParam;
1040 UINT wMsg;
1041 HWND hWnd;
1042 } msgstruct = { lParam, wParam, msg, hwnd };
1044 #ifdef CONFIG_IPC
1045 MSG DDE_msg = { hwnd, msg, wParam, lParam };
1046 if (DDE_SendMessage(&DDE_msg)) return TRUE;
1047 #endif /* CONFIG_IPC */
1049 if (hwnd == HWND_BROADCAST)
1051 dprintf_msg(stddeb,"SendMessage // HWND_BROADCAST !\n");
1052 hwnd = GetTopWindow(GetDesktopWindow());
1053 while (hwnd)
1055 if (!(wndPtr = WIN_FindWndPtr(hwnd))) break;
1056 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1058 dprintf_msg(stddeb,"BROADCAST Message to hWnd="NPFMT" m=%04X w=%04lX l=%08lX !\n",
1059 hwnd, msg, (DWORD)wParam, lParam);
1060 ret |= SendMessage( hwnd, msg, wParam, lParam );
1062 hwnd = wndPtr->hwndNext;
1064 dprintf_msg(stddeb,"SendMessage // End of HWND_BROADCAST !\n");
1065 return TRUE;
1068 EnterSpyMessage(SPY_SENDMESSAGE, hwnd, msg, wParam, lParam);
1070 CALL_TASK_HOOK( WH_CALLWNDPROC, HC_ACTION, 1, MAKE_SEGPTR(&msgstruct) );
1071 CALL_SYSTEM_HOOK( WH_CALLWNDPROC, HC_ACTION, 1, MAKE_SEGPTR(&msgstruct) );
1072 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1074 ExitSpyMessage(SPY_RESULT_INVALIDHWND,hwnd,msg,0);
1075 return 0;
1077 ret = CallWindowProc( wndPtr->lpfnWndProc, msgstruct.hWnd, msgstruct.wMsg,
1078 msgstruct.wParam, msgstruct.lParam );
1079 ExitSpyMessage(SPY_RESULT_OK,hwnd,msg,ret);
1080 return ret;
1084 /***********************************************************************
1085 * WaitMessage (USER.112)
1087 void WaitMessage( void )
1089 MSG msg;
1090 MESSAGEQUEUE *queue;
1091 LONG nextExp = -1; /* Next timer expiration time */
1093 #ifdef CONFIG_IPC
1094 DDE_GetRemoteMessage();
1095 #endif /* CONFIG_IPC */
1097 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return;
1098 if ((queue->wPostQMsg) ||
1099 (queue->status & (QS_SENDMESSAGE | QS_PAINT)) ||
1100 (queue->msgCount) || (sysMsgQueue->msgCount) )
1101 return;
1102 if ((queue->status & QS_TIMER) &&
1103 TIMER_CheckTimer( &nextExp, &msg, 0, FALSE))
1104 return;
1105 /* FIXME: (dde) must check DDE & X-events simultaneously */
1106 MSG_WaitXEvent( nextExp );
1110 /***********************************************************************
1111 * TranslateMessage (USER.113)
1113 BOOL TranslateMessage( LPMSG msg )
1115 int message = msg->message;
1117 if ((message == WM_KEYDOWN) || (message == WM_KEYUP) ||
1118 (message == WM_SYSKEYDOWN) || (message == WM_SYSKEYUP))
1120 dprintf_msg(stddeb, "Translating key message\n" );
1121 return TRUE;
1123 return FALSE;
1127 /***********************************************************************
1128 * DispatchMessage (USER.114)
1130 LONG DispatchMessage( LPMSG msg )
1132 WND * wndPtr;
1133 LONG retval;
1134 int painting;
1136 EnterSpyMessage( SPY_DISPATCHMESSAGE, msg->hwnd, msg->message,
1137 msg->wParam, msg->lParam );
1139 /* Process timer messages */
1140 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1142 if (msg->lParam)
1144 HINSTANCE ds = msg->hwnd ? WIN_GetWindowInstance( msg->hwnd )
1145 : (HINSTANCE)CURRENT_DS;
1146 return CallWndProc( (WNDPROC)msg->lParam, ds, msg->hwnd,
1147 msg->message, msg->wParam, GetTickCount() );
1151 if (!msg->hwnd) return 0;
1152 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1153 if (!wndPtr->lpfnWndProc) return 0;
1154 painting = (msg->message == WM_PAINT);
1155 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1156 retval = CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message,
1157 msg->wParam, msg->lParam );
1158 if (painting && IsWindow(msg->hwnd) &&
1159 (wndPtr->flags & WIN_NEEDS_BEGINPAINT))
1161 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd "NPFMT"!\n",
1162 msg->hwnd);
1163 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1165 return retval;
1169 /***********************************************************************
1170 * GetMessagePos (USER.119)
1172 DWORD GetMessagePos(void)
1174 MESSAGEQUEUE *queue;
1176 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1177 return queue->GetMessagePosVal;
1181 /***********************************************************************
1182 * GetMessageTime (USER.120)
1184 LONG GetMessageTime(void)
1186 MESSAGEQUEUE *queue;
1188 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1189 return queue->GetMessageTimeVal;
1193 /***********************************************************************
1194 * GetMessageExtraInfo (USER.288)
1196 LONG GetMessageExtraInfo(void)
1198 MESSAGEQUEUE *queue;
1200 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1201 return queue->GetMessageExtraInfoVal;
1205 /***********************************************************************
1206 * RegisterWindowMessage (USER.118)
1208 WORD RegisterWindowMessage( SEGPTR str )
1210 dprintf_msg(stddeb, "RegisterWindowMessage: '%08lx'\n", str );
1211 return GlobalAddAtom( str );
1215 /***********************************************************************
1216 * GetTickCount (USER.13) (KERNEL32.299)
1218 DWORD GetTickCount(void)
1220 struct timeval t;
1221 gettimeofday( &t, NULL );
1222 return (t.tv_sec * 1000) + (t.tv_usec / 1000);
1225 /***********************************************************************
1226 * InSendMessage (USER.192
1228 * According to the book, this should return true iff the current message
1229 * was send from another application. In that case, the application should
1230 * invoke ReplyMessage before calling message relevant API.
1231 * Currently, Wine will always return FALSE, as there is no other app.
1233 BOOL InSendMessage()
1235 return FALSE;