Release 951124
[wine/multimedia.git] / windows / message.c
blob836097450a7412373a3d581e010aaa263dfa522b
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 | GMEM_ZEROINIT, queueSize )))
56 return 0;
57 msgQueue = (MESSAGEQUEUE *) GlobalLock( hQueue );
58 msgQueue->msgSize = sizeof(QMSG);
59 msgQueue->queueSize = size;
60 msgQueue->wWinVersion = 0; /* FIXME? */
61 GlobalUnlock( hQueue );
62 return hQueue;
66 /***********************************************************************
67 * MSG_CreateSysMsgQueue
69 * Create the system message queue, and set the double-click speed.
70 * Must be called only once.
72 BOOL MSG_CreateSysMsgQueue( int size )
74 if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
75 else if (size <= 0) size = 1;
76 if (!(hmemSysMsgQueue = MSG_CreateMsgQueue( size ))) return FALSE;
77 sysMsgQueue = (MESSAGEQUEUE *) GlobalLock( hmemSysMsgQueue );
78 doubleClickSpeed = GetProfileInt( "windows", "DoubleClickSpeed", 452 );
79 return TRUE;
83 /***********************************************************************
84 * MSG_AddMsg
86 * Add a message to the queue. Return FALSE if queue is full.
88 static int MSG_AddMsg( HANDLE hQueue, MSG * msg, DWORD extraInfo )
90 int pos;
91 MESSAGEQUEUE *msgQueue;
93 if (!(msgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return FALSE;
94 pos = msgQueue->nextFreeMessage;
96 /* Check if queue is full */
97 if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0)) {
98 fprintf(stderr,"MSG_AddMsg // queue is full !\n");
99 return FALSE;
102 /* Store message */
103 msgQueue->messages[pos].msg = *msg;
104 msgQueue->messages[pos].extraInfo = extraInfo;
105 if (pos < msgQueue->queueSize-1) pos++;
106 else pos = 0;
107 msgQueue->nextFreeMessage = pos;
108 msgQueue->msgCount++;
109 msgQueue->status |= QS_POSTMESSAGE;
110 msgQueue->tempStatus |= QS_POSTMESSAGE;
111 return TRUE;
115 /***********************************************************************
116 * MSG_FindMsg
118 * Find a message matching the given parameters. Return -1 if none available.
120 static int MSG_FindMsg(MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last)
122 int i, pos = msgQueue->nextMessage;
124 dprintf_msg(stddeb,"MSG_FindMsg: hwnd=0x"NPFMT"\n\n", hwnd );
126 if (!msgQueue->msgCount) return -1;
127 if (!hwnd && !first && !last) return pos;
129 for (i = 0; i < msgQueue->msgCount; i++)
131 MSG * msg = &msgQueue->messages[pos].msg;
133 if (!hwnd || (msg->hwnd == hwnd))
135 if (!first && !last) return pos;
136 if ((msg->message >= first) && (msg->message <= last)) return pos;
138 if (pos < msgQueue->queueSize-1) pos++;
139 else pos = 0;
141 return -1;
145 /***********************************************************************
146 * MSG_RemoveMsg
148 * Remove a message from the queue (pos must be a valid position).
150 static void MSG_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
152 if (pos >= msgQueue->nextMessage)
154 for ( ; pos > msgQueue->nextMessage; pos--)
155 msgQueue->messages[pos] = msgQueue->messages[pos-1];
156 msgQueue->nextMessage++;
157 if (msgQueue->nextMessage >= msgQueue->queueSize)
158 msgQueue->nextMessage = 0;
160 else
162 for ( ; pos < msgQueue->nextFreeMessage; pos++)
163 msgQueue->messages[pos] = msgQueue->messages[pos+1];
164 if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
165 else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
167 msgQueue->msgCount--;
168 if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE;
169 msgQueue->tempStatus = 0;
173 /***********************************************************************
174 * MSG_GetWindowForEvent
176 * Find the window and hittest for a mouse event.
178 static INT MSG_GetWindowForEvent( POINT pt, HWND *phwnd )
180 WND *wndPtr;
181 HWND hwnd;
182 INT hittest = HTERROR;
183 INT x, y;
185 *phwnd = hwnd = GetDesktopWindow();
186 x = pt.x;
187 y = pt.y;
188 while (hwnd)
190 /* If point is in window, and window is visible, and it */
191 /* is enabled (or it's a top-level window), then explore */
192 /* its children. Otherwise, go to the next window. */
194 wndPtr = WIN_FindWndPtr( hwnd );
195 if ((wndPtr->dwStyle & WS_VISIBLE) &&
196 (!(wndPtr->dwStyle & WS_DISABLED) ||
197 !(wndPtr->dwStyle & WS_CHILD)) &&
198 (x >= wndPtr->rectWindow.left) &&
199 (x < wndPtr->rectWindow.right) &&
200 (y >= wndPtr->rectWindow.top) &&
201 (y < wndPtr->rectWindow.bottom))
203 *phwnd = hwnd;
204 x -= wndPtr->rectClient.left;
205 y -= wndPtr->rectClient.top;
206 /* If window is minimized or disabled, ignore its children */
207 if ((wndPtr->dwStyle & WS_MINIMIZE) ||
208 (wndPtr->dwStyle & WS_DISABLED)) break;
209 hwnd = wndPtr->hwndChild;
211 else hwnd = wndPtr->hwndNext;
214 /* Make point relative to parent again */
216 wndPtr = WIN_FindWndPtr( *phwnd );
217 x += wndPtr->rectClient.left;
218 y += wndPtr->rectClient.top;
220 /* Send the WM_NCHITTEST message */
222 while (*phwnd)
224 wndPtr = WIN_FindWndPtr( *phwnd );
225 if (wndPtr->dwStyle & WS_DISABLED) hittest = HTERROR;
226 else hittest = (INT)SendMessage( *phwnd, WM_NCHITTEST, 0,
227 MAKELONG( pt.x, pt.y ) );
228 if (hittest != HTTRANSPARENT) break; /* Found the window */
229 hwnd = wndPtr->hwndNext;
230 while (hwnd)
232 WND *nextPtr = WIN_FindWndPtr( hwnd );
233 if ((nextPtr->dwStyle & WS_VISIBLE) &&
234 (x >= nextPtr->rectWindow.left) &&
235 (x < nextPtr->rectWindow.right) &&
236 (y >= nextPtr->rectWindow.top) &&
237 (y < nextPtr->rectWindow.bottom)) break;
238 hwnd = nextPtr->hwndNext;
240 if (hwnd) *phwnd = hwnd; /* Found a suitable sibling */
241 else /* Go back to the parent */
243 if (!(*phwnd = wndPtr->hwndParent)) break;
244 wndPtr = WIN_FindWndPtr( *phwnd );
245 x += wndPtr->rectClient.left;
246 y += wndPtr->rectClient.top;
250 if (!*phwnd) *phwnd = GetDesktopWindow();
251 return hittest;
255 /***********************************************************************
256 * MSG_TranslateMouseMsg
258 * Translate an mouse hardware event into a real mouse message.
259 * Return value indicates whether the translated message must be passed
260 * to the user.
261 * Actions performed:
262 * - Find the window for this message.
263 * - Translate button-down messages in double-clicks.
264 * - Send the WM_NCHITTEST message to find where the cursor is.
265 * - Activate the window if needed.
266 * - Translate the message into a non-client message, or translate
267 * the coordinates to client coordinates.
268 * - Send the WM_SETCURSOR message.
270 static BOOL MSG_TranslateMouseMsg( MSG *msg, BOOL remove )
272 BOOL eatMsg = FALSE;
273 INT hittest;
274 static DWORD lastClickTime = 0;
275 static WORD lastClickMsg = 0;
276 static POINT lastClickPos = { 0, 0 };
277 POINT pt = msg->pt;
278 MOUSEHOOKSTRUCT hook = { msg->pt, 0, HTCLIENT, 0 };
280 BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
281 (msg->message == WM_RBUTTONDOWN) ||
282 (msg->message == WM_MBUTTONDOWN));
284 /* Find the window */
286 if (GetCapture())
288 msg->hwnd = GetCapture();
289 ScreenToClient( msg->hwnd, &pt );
290 msg->lParam = MAKELONG( pt.x, pt.y );
291 /* No need to further process the message */
292 hook.hwnd = msg->hwnd;
293 return !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
294 msg->message, (LPARAM)MAKE_SEGPTR(&hook));
297 if ((hittest = MSG_GetWindowForEvent( msg->pt, &msg->hwnd )) != HTERROR)
300 /* Send the WM_PARENTNOTIFY message */
302 if (mouseClick) WIN_SendParentNotify( msg->hwnd, msg->message, 0,
303 MAKELONG( msg->pt.x, msg->pt.y ) );
305 /* Activate the window if needed */
307 if (mouseClick)
309 HWND hwndTop = WIN_GetTopParent( msg->hwnd );
310 if (hwndTop != GetActiveWindow())
312 LONG ret = SendMessage( msg->hwnd, WM_MOUSEACTIVATE,
313 (WPARAM)hwndTop,
314 MAKELONG( hittest, msg->message ) );
315 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
316 eatMsg = TRUE;
317 if ((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
319 SetWindowPos( hwndTop, HWND_TOP, 0, 0, 0, 0,
320 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
321 WINPOS_ChangeActiveWindow( hwndTop, TRUE );
327 /* Send the WM_SETCURSOR message */
329 SendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
330 MAKELONG( hittest, msg->message ));
331 if (eatMsg) return FALSE;
333 /* Check for double-click */
335 if (mouseClick)
337 BOOL dbl_click = FALSE;
339 if ((msg->message == lastClickMsg) &&
340 (msg->time - lastClickTime < doubleClickSpeed) &&
341 (abs(msg->pt.x - lastClickPos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
342 (abs(msg->pt.y - lastClickPos.y) < SYSMETRICS_CYDOUBLECLK/2))
343 dbl_click = TRUE;
345 if (dbl_click && (hittest == HTCLIENT))
347 /* Check whether window wants the double click message. */
348 WND * wndPtr = WIN_FindWndPtr( msg->hwnd );
349 if (!wndPtr || !(WIN_CLASS_STYLE(wndPtr) & CS_DBLCLKS))
350 dbl_click = FALSE;
353 if (dbl_click) switch(msg->message)
355 case WM_LBUTTONDOWN: msg->message = WM_LBUTTONDBLCLK; break;
356 case WM_RBUTTONDOWN: msg->message = WM_RBUTTONDBLCLK; break;
357 case WM_MBUTTONDOWN: msg->message = WM_MBUTTONDBLCLK; break;
360 if (remove)
362 lastClickTime = msg->time;
363 lastClickMsg = msg->message;
364 lastClickPos = msg->pt;
368 /* Build the translated message */
370 if (hittest == HTCLIENT)
371 ScreenToClient( msg->hwnd, &pt );
372 else
374 msg->wParam = hittest;
375 msg->message += WM_NCLBUTTONDOWN - WM_LBUTTONDOWN;
377 msg->lParam = MAKELONG( pt.x, pt.y );
379 hook.hwnd = msg->hwnd;
380 hook.wHitTestCode = hittest;
381 return !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
382 msg->message, (LPARAM)MAKE_SEGPTR(&hook));
386 /***********************************************************************
387 * MSG_TranslateKeyboardMsg
389 * Translate an keyboard hardware event into a real message.
390 * Return value indicates whether the translated message must be passed
391 * to the user.
393 static BOOL MSG_TranslateKeyboardMsg( MSG *msg, BOOL remove )
395 /* Should check Ctrl-Esc and PrintScreen here */
397 msg->hwnd = GetFocus();
398 if (!msg->hwnd)
400 /* Send the message to the active window instead, */
401 /* translating messages to their WM_SYS equivalent */
402 msg->hwnd = GetActiveWindow();
403 msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
405 return !HOOK_CallHooks( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
406 msg->wParam, msg->lParam );
410 /***********************************************************************
411 * MSG_PeekHardwareMsg
413 * Peek for a hardware message matching the hwnd and message filters.
415 static BOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, WORD first, WORD last,
416 BOOL remove )
418 int i, pos = sysMsgQueue->nextMessage;
420 for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
422 if (pos >= sysMsgQueue->queueSize) pos = 0;
423 *msg = sysMsgQueue->messages[pos].msg;
425 /* Translate message */
427 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
429 if (!MSG_TranslateMouseMsg( msg, remove )) continue;
431 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
433 if (!MSG_TranslateKeyboardMsg( msg, remove )) continue;
435 else /* Non-standard hardware event */
437 HARDWAREHOOKSTRUCT hook = { msg->hwnd, msg->message,
438 msg->wParam, msg->lParam };
439 if (HOOK_CallHooks( WH_HARDWARE, remove ? HC_ACTION : HC_NOREMOVE,
440 0, (LPARAM)MAKE_SEGPTR(&hook) )) continue;
443 /* Check message against filters */
445 if (hwnd && (msg->hwnd != hwnd)) continue;
446 if ((first || last) &&
447 ((msg->message < first) || (msg->message > last))) continue;
448 if ((msg->hwnd != GetDesktopWindow()) &&
449 (GetWindowTask(msg->hwnd) != GetCurrentTask()))
450 continue; /* Not for this task */
451 if (remove)
453 MSG tmpMsg = *msg; /* FIXME */
454 HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION,
455 0, (LPARAM)MAKE_SEGPTR(&tmpMsg) );
456 MSG_RemoveMsg( sysMsgQueue, pos );
458 return TRUE;
460 return FALSE;
464 /**********************************************************************
465 * SetDoubleClickTime (USER.20)
467 void SetDoubleClickTime( WORD interval )
469 if (interval == 0)
470 doubleClickSpeed = 500;
471 else
472 doubleClickSpeed = interval;
476 /**********************************************************************
477 * GetDoubleClickTime (USER.21)
479 WORD GetDoubleClickTime()
481 return (WORD)doubleClickSpeed;
485 /***********************************************************************
486 * MSG_IncPaintCount
488 void MSG_IncPaintCount( HANDLE hQueue )
490 MESSAGEQUEUE *queue;
492 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
493 queue->wPaintCount++;
494 queue->status |= QS_PAINT;
495 queue->tempStatus |= QS_PAINT;
499 /***********************************************************************
500 * MSG_DecPaintCount
502 void MSG_DecPaintCount( HANDLE hQueue )
504 MESSAGEQUEUE *queue;
506 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
507 queue->wPaintCount--;
508 if (!queue->wPaintCount) queue->status &= ~QS_PAINT;
512 /***********************************************************************
513 * MSG_IncTimerCount
515 void MSG_IncTimerCount( HANDLE hQueue )
517 MESSAGEQUEUE *queue;
519 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
520 queue->wTimerCount++;
521 queue->status |= QS_TIMER;
522 queue->tempStatus |= QS_TIMER;
526 /***********************************************************************
527 * MSG_DecTimerCount
529 void MSG_DecTimerCount( HANDLE hQueue )
531 MESSAGEQUEUE *queue;
533 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
534 queue->wTimerCount--;
535 if (!queue->wTimerCount) queue->status &= ~QS_TIMER;
539 /***********************************************************************
540 * hardware_event
542 * Add an event to the system message queue.
543 * Note: the position is relative to the desktop window.
545 void hardware_event( WORD message, WORD wParam, LONG lParam,
546 int xPos, int yPos, DWORD time, DWORD extraInfo )
548 MSG *msg;
549 int pos;
551 if (!sysMsgQueue) return;
552 pos = sysMsgQueue->nextFreeMessage;
554 /* Merge with previous event if possible */
556 if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
558 if (pos > 0) pos--;
559 else pos = sysMsgQueue->queueSize - 1;
560 msg = &sysMsgQueue->messages[pos].msg;
561 if ((msg->message == message) && (msg->wParam == wParam))
562 sysMsgQueue->msgCount--; /* Merge events */
563 else
564 pos = sysMsgQueue->nextFreeMessage; /* Don't merge */
567 /* Check if queue is full */
569 if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
571 /* Queue is full, beep (but not on every mouse motion...) */
572 if (message != WM_MOUSEMOVE) MessageBeep(0);
573 return;
576 /* Store message */
578 msg = &sysMsgQueue->messages[pos].msg;
579 msg->hwnd = 0;
580 msg->message = message;
581 msg->wParam = wParam;
582 msg->lParam = lParam;
583 msg->time = time;
584 msg->pt.x = xPos & 0xffff;
585 msg->pt.y = yPos & 0xffff;
586 sysMsgQueue->messages[pos].extraInfo = extraInfo;
587 if (pos < sysMsgQueue->queueSize - 1) pos++;
588 else pos = 0;
589 sysMsgQueue->nextFreeMessage = pos;
590 sysMsgQueue->msgCount++;
594 /***********************************************************************
595 * MSG_GetHardwareMessage
597 * Like GetMessage(), but only return mouse and keyboard events.
598 * Used internally for window moving and resizing. Mouse messages
599 * are not translated.
600 * Warning: msg->hwnd is always 0.
602 BOOL MSG_GetHardwareMessage( LPMSG msg )
604 int pos;
605 XEvent event;
607 while(1)
609 if ((pos = MSG_FindMsg( sysMsgQueue, 0, 0, 0 )) != -1)
611 *msg = sysMsgQueue->messages[pos].msg;
612 MSG_RemoveMsg( sysMsgQueue, pos );
613 break;
615 XNextEvent( display, &event );
616 EVENT_ProcessEvent( &event );
618 return TRUE;
622 /***********************************************************************
623 * SetMessageQueue (USER.266)
625 BOOL SetMessageQueue( int size )
627 HGLOBAL hQueue;
628 MESSAGEQUEUE *queuePtr;
630 if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
632 /* Free the old message queue */
633 if ((hQueue = GetTaskQueue(0)) != 0)
635 GlobalUnlock( hQueue );
636 GlobalFree( hQueue );
639 if (!(hQueue = MSG_CreateMsgQueue( size ))) return FALSE;
640 queuePtr = (MESSAGEQUEUE *)GlobalLock( hQueue );
641 queuePtr->hTask = GetCurrentTask();
642 SetTaskQueue( 0, hQueue );
643 return TRUE;
647 /***********************************************************************
648 * GetWindowTask (USER.224)
650 HTASK GetWindowTask( HWND hwnd )
652 WND *wndPtr = WIN_FindWndPtr( hwnd );
653 MESSAGEQUEUE *queuePtr;
655 if (!wndPtr) return 0;
656 queuePtr = (MESSAGEQUEUE *)GlobalLock( wndPtr->hmemTaskQ );
657 if (!queuePtr) return 0;
658 return queuePtr->hTask;
662 /***********************************************************************
663 * PostQuitMessage (USER.6)
665 void PostQuitMessage( int exitCode )
667 MESSAGEQUEUE *queue;
669 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return;
670 queue->wPostQMsg = TRUE;
671 queue->wExitCode = exitCode;
675 /***********************************************************************
676 * GetQueueStatus (USER.334)
678 DWORD GetQueueStatus( int flags )
680 MESSAGEQUEUE *queue;
681 DWORD ret;
683 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
684 ret = MAKELONG( queue->tempStatus, queue->status );
685 queue->tempStatus = 0;
686 return ret & MAKELONG( flags, flags );
690 /***********************************************************************
691 * GetInputState (USER.335)
693 BOOL GetInputState()
695 MESSAGEQUEUE *queue;
697 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return FALSE;
698 return queue->status & (QS_KEY | QS_MOUSEBUTTON);
702 /***********************************************************************
703 * MSG_Synchronize
705 * Synchronize with the X server. Should not be used too often.
707 void MSG_Synchronize()
709 XEvent event;
711 XSync( display, False );
712 while (XPending( display ))
714 XNextEvent( display, &event );
715 EVENT_ProcessEvent( &event );
720 /***********************************************************************
721 * MSG_WaitXEvent
723 * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
724 * Return TRUE if an event is pending, FALSE on timeout or error
725 * (for instance lost connection with the server).
727 BOOL MSG_WaitXEvent( LONG maxWait )
729 fd_set read_set;
730 struct timeval timeout;
731 XEvent event;
732 int fd = ConnectionNumber(display);
734 if (!XPending(display) && (maxWait != -1))
736 FD_ZERO( &read_set );
737 FD_SET( fd, &read_set );
739 timeout.tv_usec = (maxWait % 1000) * 1000;
740 timeout.tv_sec = maxWait / 1000;
742 #ifdef CONFIG_IPC
743 sigsetjmp(env_wait_x, 1);
744 stop_wait_op= CONT;
746 if (DDE_GetRemoteMessage()) {
747 while(DDE_GetRemoteMessage())
749 return TRUE;
751 stop_wait_op= STOP_WAIT_X;
752 /* The code up to the next "stop_wait_op= CONT" must be reentrant */
753 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
754 !XPending(display)) {
755 stop_wait_op= CONT;
756 return FALSE;
757 } else {
758 stop_wait_op= CONT;
760 #else /* CONFIG_IPC */
761 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
762 return FALSE; /* Timeout or error */
763 #endif /* CONFIG_IPC */
767 /* Process the event (and possibly others that occurred in the meantime) */
771 #ifdef CONFIG_IPC
772 if (DDE_GetRemoteMessage())
774 while(DDE_GetRemoteMessage()) ;
775 return TRUE;
777 #endif /* CONFIG_IPC */
779 XNextEvent( display, &event );
780 EVENT_ProcessEvent( &event );
782 while (XPending( display ));
783 return TRUE;
787 /***********************************************************************
788 * MSG_PeekMessage
790 static BOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last,
791 WORD flags, BOOL peek )
793 int pos, mask;
794 MESSAGEQUEUE *msgQueue;
795 LONG nextExp; /* Next timer expiration time */
797 #ifdef CONFIG_IPC
798 DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
799 DDE_GetRemoteMessage();
800 #endif /* CONFIG_IPC */
802 if (first || last)
804 mask = QS_POSTMESSAGE; /* Always selectioned */
805 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
806 if ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) mask |= QS_MOUSE;
807 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
808 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
809 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
811 else mask = QS_MOUSE | QS_KEY | QS_POSTMESSAGE | QS_TIMER | QS_PAINT;
813 while(1)
815 msgQueue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) );
816 if (!msgQueue) return FALSE;
818 /* First handle a message put by SendMessage() */
819 if (msgQueue->status & QS_SENDMESSAGE)
821 if (!hwnd || (msgQueue->hWnd == hwnd))
823 if ((!first && !last) ||
824 ((msgQueue->msg >= first) && (msgQueue->msg <= last)))
826 msg->hwnd = msgQueue->hWnd;
827 msg->message = msgQueue->msg;
828 msg->wParam = msgQueue->wParam;
829 msg->lParam = msgQueue->lParam;
830 if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
831 break;
836 /* Now find a normal message */
837 pos = MSG_FindMsg( msgQueue, hwnd, first, last );
838 if (pos != -1)
840 QMSG *qmsg = &msgQueue->messages[pos];
841 *msg = qmsg->msg;
842 msgQueue->GetMessageTimeVal = msg->time;
843 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
844 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
846 if (flags & PM_REMOVE) MSG_RemoveMsg( msgQueue, pos );
847 break;
850 /* Now find a hardware event */
851 if (MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
853 /* Got one */
854 msgQueue->GetMessageTimeVal = msg->time;
855 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
856 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
857 break;
860 /* Now handle a WM_QUIT message */
861 if (msgQueue->wPostQMsg)
863 msg->hwnd = hwnd;
864 msg->message = WM_QUIT;
865 msg->wParam = msgQueue->wExitCode;
866 msg->lParam = 0;
867 break;
870 /* Now find a WM_PAINT message */
871 if ((msgQueue->status & QS_PAINT) && (mask & QS_PAINT))
873 msg->hwnd = WIN_FindWinToRepaint( hwnd );
874 msg->message = WM_PAINT;
875 msg->wParam = 0;
876 msg->lParam = 0;
877 if (msg->hwnd != 0) break;
880 /* Finally handle WM_TIMER messages */
881 if ((msgQueue->status & QS_TIMER) && (mask & QS_TIMER))
883 if (TIMER_CheckTimer( &nextExp, msg, hwnd, flags & PM_REMOVE ))
884 break; /* Got a timer msg */
886 else nextExp = -1; /* No timeout needed */
888 Yield();
890 /* Wait until something happens */
891 if (peek)
893 if (!MSG_WaitXEvent( 0 )) return FALSE; /* No pending event */
895 else /* Wait for an event, then restart the loop */
896 MSG_WaitXEvent( nextExp );
899 /* We got a message */
900 if (peek) return TRUE;
901 else return (msg->message != WM_QUIT);
905 /***********************************************************************
906 * MSG_InternalGetMessage
908 * GetMessage() function for internal use. Behave like GetMessage(),
909 * but also call message filters and optionally send WM_ENTERIDLE messages.
910 * 'hwnd' must be the handle of the dialog or menu window.
911 * 'code' is the message filter value (MSGF_??? codes).
913 BOOL MSG_InternalGetMessage( SEGPTR msg, HWND hwnd, HWND hwndOwner, short code,
914 WORD flags, BOOL sendIdle )
916 for (;;)
918 if (sendIdle)
920 if (!MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
921 0, 0, 0, flags, TRUE ))
923 /* No message present -> send ENTERIDLE and wait */
924 SendMessage( hwndOwner, WM_ENTERIDLE, code, (LPARAM)hwnd );
925 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
926 0, 0, 0, flags, FALSE );
929 else /* Always wait for a message */
930 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
931 0, 0, 0, flags, FALSE );
933 if (!CallMsgFilter( msg, code ))
934 return (((MSG *)PTR_SEG_TO_LIN(msg))->message != WM_QUIT);
936 /* Message filtered -> remove it from the queue */
937 /* if it's still there. */
938 if (!(flags & PM_REMOVE))
939 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
940 0, 0, 0, PM_REMOVE, TRUE );
945 /***********************************************************************
946 * PeekMessage (USER.109)
948 BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
950 return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
954 /***********************************************************************
955 * GetMessage (USER.108)
957 BOOL GetMessage( SEGPTR msg, HWND hwnd, UINT first, UINT last )
959 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
960 hwnd, first, last, PM_REMOVE, FALSE );
961 HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
962 return (((MSG *)PTR_SEG_TO_LIN(msg))->message != WM_QUIT);
967 /***********************************************************************
968 * PostMessage (USER.110)
970 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
972 MSG msg;
973 WND *wndPtr;
975 msg.hwnd = hwnd;
976 msg.message = message;
977 msg.wParam = wParam;
978 msg.lParam = lParam;
979 msg.time = GetTickCount();
980 msg.pt.x = 0;
981 msg.pt.y = 0;
983 #ifdef CONFIG_IPC
984 if (DDE_PostMessage(&msg))
985 return TRUE;
986 #endif /* CONFIG_IPC */
988 if (hwnd == HWND_BROADCAST) {
989 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
990 hwnd = GetTopWindow(GetDesktopWindow());
991 while (hwnd) {
992 if (!(wndPtr = WIN_FindWndPtr(hwnd))) break;
993 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) {
994 dprintf_msg(stddeb,"BROADCAST Message to hWnd="NPFMT" m=%04X w=%04X l=%08lX !\n",
995 hwnd, message, wParam, lParam);
996 PostMessage(hwnd, message, wParam, lParam);
998 hwnd = wndPtr->hwndNext;
1000 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
1001 return TRUE;
1004 wndPtr = WIN_FindWndPtr( hwnd );
1005 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
1007 return MSG_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
1010 /***********************************************************************
1011 * PostAppMessage (USER.116)
1013 BOOL PostAppMessage( HTASK hTask, WORD message, WORD wParam, LONG lParam )
1015 MSG msg;
1017 if (GetTaskQueue(hTask) == 0) return FALSE;
1018 msg.hwnd = 0;
1019 msg.message = message;
1020 msg.wParam = wParam;
1021 msg.lParam = lParam;
1022 msg.time = GetTickCount();
1023 msg.pt.x = 0;
1024 msg.pt.y = 0;
1026 return MSG_AddMsg( GetTaskQueue(hTask), &msg, 0 );
1030 /***********************************************************************
1031 * SendMessage (USER.111)
1033 LRESULT SendMessage( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
1035 WND * wndPtr;
1036 LONG ret;
1037 struct
1039 LPARAM lParam;
1040 WPARAM wParam;
1041 UINT wMsg;
1042 HWND hWnd;
1043 } msgstruct = { lParam, wParam, msg, hwnd };
1045 #ifdef CONFIG_IPC
1046 MSG DDE_msg = { hwnd, msg, wParam, lParam };
1047 if (DDE_SendMessage(&DDE_msg)) return TRUE;
1048 #endif /* CONFIG_IPC */
1050 if (hwnd == HWND_BROADCAST)
1052 dprintf_msg(stddeb,"SendMessage // HWND_BROADCAST !\n");
1053 hwnd = GetTopWindow(GetDesktopWindow());
1054 while (hwnd)
1056 if (!(wndPtr = WIN_FindWndPtr(hwnd))) break;
1057 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1059 dprintf_msg(stddeb,"BROADCAST Message to hWnd="NPFMT" m=%04X w=%04lX l=%08lX !\n",
1060 hwnd, msg, (DWORD)wParam, lParam);
1061 ret |= SendMessage( hwnd, msg, wParam, lParam );
1063 hwnd = wndPtr->hwndNext;
1065 dprintf_msg(stddeb,"SendMessage // End of HWND_BROADCAST !\n");
1066 return TRUE;
1069 EnterSpyMessage(SPY_SENDMESSAGE, hwnd, msg, wParam, lParam);
1071 HOOK_CallHooks( 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 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1147 return CallWndProc( (WNDPROC)msg->lParam, ds, msg->hwnd,
1148 msg->message, msg->wParam, GetTickCount() );
1152 if (!msg->hwnd) return 0;
1153 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1154 if (!wndPtr->lpfnWndProc) return 0;
1155 painting = (msg->message == WM_PAINT);
1156 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1157 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1158 retval = CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message,
1159 msg->wParam, msg->lParam );
1160 if (painting && IsWindow(msg->hwnd) &&
1161 (wndPtr->flags & WIN_NEEDS_BEGINPAINT))
1163 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd "NPFMT"!\n",
1164 msg->hwnd);
1165 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1167 return retval;
1171 /***********************************************************************
1172 * GetMessagePos (USER.119)
1174 DWORD GetMessagePos(void)
1176 MESSAGEQUEUE *queue;
1178 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1179 return queue->GetMessagePosVal;
1183 /***********************************************************************
1184 * GetMessageTime (USER.120)
1186 LONG GetMessageTime(void)
1188 MESSAGEQUEUE *queue;
1190 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1191 return queue->GetMessageTimeVal;
1195 /***********************************************************************
1196 * GetMessageExtraInfo (USER.288)
1198 LONG GetMessageExtraInfo(void)
1200 MESSAGEQUEUE *queue;
1202 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1203 return queue->GetMessageExtraInfoVal;
1207 /***********************************************************************
1208 * RegisterWindowMessage (USER.118)
1210 WORD RegisterWindowMessage( SEGPTR str )
1212 dprintf_msg(stddeb, "RegisterWindowMessage: '%08lx'\n", str );
1213 return GlobalAddAtom( str );
1217 /***********************************************************************
1218 * GetTickCount (USER.13) (KERNEL32.299)
1220 DWORD GetTickCount(void)
1222 struct timeval t;
1223 gettimeofday( &t, NULL );
1224 return (t.tv_sec * 1000) + (t.tv_usec / 1000);
1227 /***********************************************************************
1228 * GetCurrentTime (effectively identical to GetTickCount)
1230 DWORD GetCurrentTime(void)
1232 return GetTickCount();
1235 /***********************************************************************
1236 * InSendMessage (USER.192
1238 * According to the book, this should return true iff the current message
1239 * was send from another application. In that case, the application should
1240 * invoke ReplyMessage before calling message relevant API.
1241 * Currently, Wine will always return FALSE, as there is no other app.
1243 BOOL InSendMessage()
1245 return FALSE;