Release 950522
[wine.git] / windows / message.c
blobc219424fa70c33fb689c6d93c433b4da01e02139
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>
11 #include "message.h"
12 #include "win.h"
13 #include "gdi.h"
14 #include "wineopts.h"
15 #include "sysmetrics.h"
16 #include "hook.h"
17 #include "event.h"
18 #include "winpos.h"
19 #include "stddebug.h"
20 /* #define DEBUG_MSG */
21 #include "debug.h"
24 #define HWND_BROADCAST ((HWND)0xffff)
26 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
29 extern BOOL TIMER_CheckTimer( LONG *next, MSG *msg,
30 HWND hwnd, BOOL remove ); /* timer.c */
32 /* System message queue (for hardware events) */
33 static HANDLE hmemSysMsgQueue = 0;
34 static MESSAGEQUEUE * sysMsgQueue = NULL;
36 /* Double-click time */
37 static int doubleClickSpeed = 452;
40 /***********************************************************************
41 * MSG_CreateMsgQueue
43 * Create a message queue.
45 static HANDLE MSG_CreateMsgQueue( int size )
47 HANDLE hQueue;
48 MESSAGEQUEUE * msgQueue;
49 int queueSize;
51 queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
52 if (!(hQueue = GlobalAlloc( GMEM_FIXED, queueSize ))) return 0;
53 msgQueue = (MESSAGEQUEUE *) GlobalLock( hQueue );
54 msgQueue->next = 0;
55 msgQueue->hTask = 0;
56 msgQueue->msgSize = sizeof(QMSG);
57 msgQueue->msgCount = 0;
58 msgQueue->nextMessage = 0;
59 msgQueue->nextFreeMessage = 0;
60 msgQueue->queueSize = size;
61 msgQueue->GetMessageTimeVal = 0;
62 msgQueue->GetMessagePosVal = 0;
63 msgQueue->GetMessageExtraInfoVal = 0;
64 msgQueue->lParam = 0;
65 msgQueue->wParam = 0;
66 msgQueue->msg = 0;
67 msgQueue->hWnd = 0;
68 msgQueue->wPostQMsg = 0;
69 msgQueue->wExitCode = 0;
70 msgQueue->InSendMessageHandle = 0;
71 msgQueue->wPaintCount = 0;
72 msgQueue->wTimerCount = 0;
73 msgQueue->tempStatus = 0;
74 msgQueue->status = 0;
75 GlobalUnlock( hQueue );
76 return hQueue;
80 /***********************************************************************
81 * MSG_CreateSysMsgQueue
83 * Create the system message queue, and set the double-click speed.
84 * Must be called only once.
86 BOOL MSG_CreateSysMsgQueue( int size )
88 if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
89 else if (size <= 0) size = 1;
90 if (!(hmemSysMsgQueue = MSG_CreateMsgQueue( size ))) return FALSE;
91 sysMsgQueue = (MESSAGEQUEUE *) GlobalLock( hmemSysMsgQueue );
92 doubleClickSpeed = GetProfileInt( "windows", "DoubleClickSpeed", 452 );
93 return TRUE;
97 /***********************************************************************
98 * MSG_AddMsg
100 * Add a message to the queue. Return FALSE if queue is full.
102 static int MSG_AddMsg( HANDLE hQueue, MSG * msg, DWORD extraInfo )
104 int pos;
105 MESSAGEQUEUE *msgQueue;
107 if (!(msgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return FALSE;
108 pos = msgQueue->nextFreeMessage;
110 /* Check if queue is full */
111 if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0)) {
112 fprintf(stderr,"MSG_AddMsg // queue is full !\n");
113 return FALSE;
116 /* Store message */
117 msgQueue->messages[pos].msg = *msg;
118 msgQueue->messages[pos].extraInfo = extraInfo;
119 if (pos < msgQueue->queueSize-1) pos++;
120 else pos = 0;
121 msgQueue->nextFreeMessage = pos;
122 msgQueue->msgCount++;
123 msgQueue->status |= QS_POSTMESSAGE;
124 msgQueue->tempStatus |= QS_POSTMESSAGE;
125 return TRUE;
129 /***********************************************************************
130 * MSG_FindMsg
132 * Find a message matching the given parameters. Return -1 if none available.
134 static int MSG_FindMsg(MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last)
136 int i, pos = msgQueue->nextMessage;
138 if (!msgQueue->msgCount) return -1;
139 if (!hwnd && !first && !last) return pos;
141 for (i = 0; i < msgQueue->msgCount; i++)
143 MSG * msg = &msgQueue->messages[pos].msg;
145 if (!hwnd || (msg->hwnd == hwnd))
147 if (!first && !last) return pos;
148 if ((msg->message >= first) && (msg->message <= last)) return pos;
150 if (pos < msgQueue->queueSize-1) pos++;
151 else pos = 0;
153 return -1;
157 /***********************************************************************
158 * MSG_RemoveMsg
160 * Remove a message from the queue (pos must be a valid position).
162 static void MSG_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
164 if (pos >= msgQueue->nextMessage)
166 for ( ; pos > msgQueue->nextMessage; pos--)
167 msgQueue->messages[pos] = msgQueue->messages[pos-1];
168 msgQueue->nextMessage++;
169 if (msgQueue->nextMessage >= msgQueue->queueSize)
170 msgQueue->nextMessage = 0;
172 else
174 for ( ; pos < msgQueue->nextFreeMessage; pos++)
175 msgQueue->messages[pos] = msgQueue->messages[pos+1];
176 if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
177 else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
179 msgQueue->msgCount--;
180 if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE;
181 msgQueue->tempStatus = 0;
185 /***********************************************************************
186 * MSG_TranslateMouseMsg
188 * Translate an mouse hardware event into a real mouse message.
189 * Return value indicates whether the translated message must be passed
190 * to the user.
191 * Actions performed:
192 * - Find the window for this message.
193 * - Translate button-down messages in double-clicks.
194 * - Send the WM_NCHITTEST message to find where the cursor is.
195 * - Activate the window if needed.
196 * - Translate the message into a non-client message, or translate
197 * the coordinates to client coordinates.
198 * - Send the WM_SETCURSOR message.
200 static BOOL MSG_TranslateMouseMsg( MSG *msg, BOOL remove )
202 BOOL eatMsg = FALSE;
203 INT hittest_result;
204 static DWORD lastClickTime = 0;
205 static WORD lastClickMsg = 0;
206 static POINT lastClickPos = { 0, 0 };
208 BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
209 (msg->message == WM_RBUTTONDOWN) ||
210 (msg->message == WM_MBUTTONDOWN));
212 /* Find the window */
214 if (GetCapture())
216 msg->hwnd = GetCapture();
217 msg->lParam = MAKELONG( msg->pt.x, msg->pt.y );
218 ScreenToClient( msg->hwnd, (LPPOINT)&msg->lParam );
219 return TRUE; /* No need to further process the message */
221 else msg->hwnd = WindowFromPoint( msg->pt );
223 /* Send the WM_NCHITTEST message */
225 hittest_result = (INT)SendMessage( msg->hwnd, WM_NCHITTEST, 0,
226 MAKELONG( msg->pt.x, msg->pt.y ) );
227 while ((hittest_result == HTTRANSPARENT) && (msg->hwnd))
229 msg->hwnd = WINPOS_NextWindowFromPoint( msg->hwnd, msg->pt );
230 if (msg->hwnd)
231 hittest_result = (INT)SendMessage( msg->hwnd, WM_NCHITTEST, 0,
232 MAKELONG( msg->pt.x, msg->pt.y ));
234 if (!msg->hwnd) msg->hwnd = GetDesktopWindow();
236 /* Send the WM_PARENTNOTIFY message */
238 if (mouseClick) WIN_SendParentNotify( msg->hwnd, msg->message,
239 MAKELONG( msg->pt.x, msg->pt.y ) );
241 /* Activate the window if needed */
243 if (mouseClick)
245 HWND parent, hwndTop = msg->hwnd;
246 while ((parent = GetParent(hwndTop)) != 0) hwndTop = parent;
247 if (hwndTop != GetActiveWindow())
249 LONG ret = SendMessage( msg->hwnd, WM_MOUSEACTIVATE, hwndTop,
250 MAKELONG( hittest_result, msg->message ) );
251 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
252 eatMsg = TRUE;
253 if ((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
255 SetWindowPos( hwndTop, HWND_TOP, 0, 0, 0, 0,
256 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
257 WINPOS_ChangeActiveWindow( hwndTop, TRUE );
262 /* Send the WM_SETCURSOR message */
264 SendMessage( msg->hwnd, WM_SETCURSOR, msg->hwnd,
265 MAKELONG( hittest_result, msg->message ));
266 if (eatMsg) return FALSE;
268 /* Check for double-click */
270 if (mouseClick)
272 BOOL dbl_click = FALSE;
274 if ((msg->message == lastClickMsg) &&
275 (msg->time - lastClickTime < doubleClickSpeed) &&
276 (abs(msg->pt.x - lastClickPos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
277 (abs(msg->pt.y - lastClickPos.y) < SYSMETRICS_CYDOUBLECLK/2))
278 dbl_click = TRUE;
280 if (dbl_click && (hittest_result == HTCLIENT))
282 /* Check whether window wants the double click message. */
283 WND * wndPtr = WIN_FindWndPtr( msg->hwnd );
284 if (!wndPtr || !(WIN_CLASS_STYLE(wndPtr) & CS_DBLCLKS))
285 dbl_click = FALSE;
288 if (dbl_click) switch(msg->message)
290 case WM_LBUTTONDOWN: msg->message = WM_LBUTTONDBLCLK; break;
291 case WM_RBUTTONDOWN: msg->message = WM_RBUTTONDBLCLK; break;
292 case WM_MBUTTONDOWN: msg->message = WM_MBUTTONDBLCLK; break;
295 if (remove)
297 lastClickTime = msg->time;
298 lastClickMsg = msg->message;
299 lastClickPos = msg->pt;
303 /* Build the translated message */
305 msg->lParam = MAKELONG( msg->pt.x, msg->pt.y );
306 if (hittest_result == HTCLIENT)
308 ScreenToClient( msg->hwnd, (LPPOINT)&msg->lParam );
310 else
312 msg->wParam = hittest_result;
313 msg->message += WM_NCLBUTTONDOWN - WM_LBUTTONDOWN;
316 return TRUE;
320 /***********************************************************************
321 * MSG_TranslateKeyboardMsg
323 * Translate an keyboard hardware event into a real message.
324 * Return value indicates whether the translated message must be passed
325 * to the user.
327 static BOOL MSG_TranslateKeyboardMsg( MSG *msg )
329 /* Should check Ctrl-Esc and PrintScreen here */
331 msg->hwnd = GetFocus();
332 if (!msg->hwnd)
334 /* Send the message to the active window instead, */
335 /* translating messages to their WM_SYS equivalent */
336 msg->hwnd = GetActiveWindow();
337 msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
339 return TRUE;
343 /***********************************************************************
344 * MSG_PeekHardwareMsg
346 * Peek for a hardware message matching the hwnd and message filters.
348 static BOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, WORD first, WORD last,
349 BOOL remove )
351 int i, pos = sysMsgQueue->nextMessage;
353 for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
355 *msg = sysMsgQueue->messages[pos].msg;
357 /* Translate message */
359 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
361 if (!MSG_TranslateMouseMsg( msg, remove )) continue;
363 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
365 if (!MSG_TranslateKeyboardMsg( msg )) continue;
367 else continue; /* Should never happen */
369 /* Check message against filters */
371 if (hwnd && (msg->hwnd != hwnd)) continue;
372 if ((first || last) &&
373 ((msg->message < first) || (msg->message > last))) continue;
374 if (GetWindowTask(msg->hwnd) != GetCurrentTask())
375 continue; /* Not for this task */
376 if (remove) MSG_RemoveMsg( sysMsgQueue, pos );
377 return TRUE;
379 return FALSE;
383 /**********************************************************************
384 * SetDoubleClickTime (USER.20)
386 void SetDoubleClickTime( WORD interval )
388 if (interval == 0)
389 doubleClickSpeed = 500;
390 else
391 doubleClickSpeed = interval;
395 /**********************************************************************
396 * GetDoubleClickTime (USER.21)
398 WORD GetDoubleClickTime()
400 return (WORD)doubleClickSpeed;
404 /***********************************************************************
405 * MSG_IncPaintCount
407 void MSG_IncPaintCount( HANDLE hQueue )
409 MESSAGEQUEUE *queue;
411 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
412 queue->wPaintCount++;
413 queue->status |= QS_PAINT;
414 queue->tempStatus |= QS_PAINT;
418 /***********************************************************************
419 * MSG_DecPaintCount
421 void MSG_DecPaintCount( HANDLE hQueue )
423 MESSAGEQUEUE *queue;
425 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
426 queue->wPaintCount--;
427 if (!queue->wPaintCount) queue->status &= ~QS_PAINT;
431 /***********************************************************************
432 * MSG_IncTimerCount
434 void MSG_IncTimerCount( HANDLE hQueue )
436 MESSAGEQUEUE *queue;
438 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
439 queue->wTimerCount++;
440 queue->status |= QS_TIMER;
441 queue->tempStatus |= QS_TIMER;
445 /***********************************************************************
446 * MSG_DecTimerCount
448 void MSG_DecTimerCount( HANDLE hQueue )
450 MESSAGEQUEUE *queue;
452 if (!(queue = (MESSAGEQUEUE *)GlobalLock( hQueue ))) return;
453 queue->wTimerCount--;
454 if (!queue->wTimerCount) queue->status &= ~QS_TIMER;
458 /***********************************************************************
459 * hardware_event
461 * Add an event to the system message queue.
462 * Note: the position is relative to the desktop window.
464 void hardware_event( WORD message, WORD wParam, LONG lParam,
465 int xPos, int yPos, DWORD time, DWORD extraInfo )
467 MSG *msg;
468 int pos;
470 if (!sysMsgQueue) return;
471 pos = sysMsgQueue->nextFreeMessage;
473 /* Merge with previous event if possible */
475 if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
477 if (pos > 0) pos--;
478 else pos = sysMsgQueue->queueSize - 1;
479 msg = &sysMsgQueue->messages[pos].msg;
480 if ((msg->message == message) && (msg->wParam == wParam))
481 sysMsgQueue->msgCount--; /* Merge events */
482 else
483 pos = sysMsgQueue->nextFreeMessage; /* Don't merge */
486 /* Check if queue is full */
488 if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
490 /* Queue is full, beep (but not on every mouse motion...) */
491 if (message != WM_MOUSEMOVE) MessageBeep(0);
492 return;
495 /* Store message */
497 msg = &sysMsgQueue->messages[pos].msg;
498 msg->hwnd = 0;
499 msg->message = message;
500 msg->wParam = wParam;
501 msg->lParam = lParam;
502 msg->time = time;
503 msg->pt.x = xPos & 0xffff;
504 msg->pt.y = yPos & 0xffff;
505 sysMsgQueue->messages[pos].extraInfo = extraInfo;
506 if (pos < sysMsgQueue->queueSize - 1) pos++;
507 else pos = 0;
508 sysMsgQueue->nextFreeMessage = pos;
509 sysMsgQueue->msgCount++;
513 /***********************************************************************
514 * MSG_GetHardwareMessage
516 * Like GetMessage(), but only return mouse and keyboard events.
517 * Used internally for window moving and resizing. Mouse messages
518 * are not translated.
519 * Warning: msg->hwnd is always 0.
521 BOOL MSG_GetHardwareMessage( LPMSG msg )
523 int pos;
524 XEvent event;
526 while(1)
528 if ((pos = MSG_FindMsg( sysMsgQueue, 0, 0, 0 )) != -1)
530 *msg = sysMsgQueue->messages[pos].msg;
531 MSG_RemoveMsg( sysMsgQueue, pos );
532 break;
534 XNextEvent( display, &event );
535 EVENT_ProcessEvent( &event );
537 return TRUE;
541 /***********************************************************************
542 * SetMessageQueue (USER.266)
544 BOOL SetMessageQueue( int size )
546 HGLOBAL hQueue;
547 MESSAGEQUEUE *queuePtr;
549 if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
551 /* Free the old message queue */
552 if ((hQueue = GetTaskQueue(0)) != 0)
554 GlobalUnlock( hQueue );
555 GlobalFree( hQueue );
558 if (!(hQueue = MSG_CreateMsgQueue( size ))) return FALSE;
559 queuePtr = (MESSAGEQUEUE *)GlobalLock( hQueue );
560 queuePtr->hTask = GetCurrentTask();
561 SetTaskQueue( 0, hQueue );
562 return TRUE;
566 /***********************************************************************
567 * GetWindowTask (USER.224)
569 HTASK GetWindowTask( HWND hwnd )
571 WND *wndPtr = WIN_FindWndPtr( hwnd );
572 MESSAGEQUEUE *queuePtr;
574 if (!wndPtr) return 0;
575 queuePtr = (MESSAGEQUEUE *)GlobalLock( wndPtr->hmemTaskQ );
576 if (!queuePtr) return 0;
577 return queuePtr->hTask;
581 /***********************************************************************
582 * PostQuitMessage (USER.6)
584 void PostQuitMessage( int exitCode )
586 MESSAGEQUEUE *queue;
588 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return;
589 queue->wPostQMsg = TRUE;
590 queue->wExitCode = exitCode;
594 /***********************************************************************
595 * GetQueueStatus (USER.334)
597 DWORD GetQueueStatus( int flags )
599 MESSAGEQUEUE *queue;
600 DWORD ret;
602 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
603 ret = MAKELONG( queue->tempStatus, queue->status );
604 queue->tempStatus = 0;
605 return ret & MAKELONG( flags, flags );
609 /***********************************************************************
610 * GetInputState (USER.335)
612 BOOL GetInputState()
614 MESSAGEQUEUE *queue;
616 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return FALSE;
617 return queue->status & (QS_KEY | QS_MOUSEBUTTON);
621 /***********************************************************************
622 * MSG_Synchronize
624 * Synchronize with the X server. Should not be used too often.
626 void MSG_Synchronize()
628 XEvent event;
630 XSync( display, False );
631 while (XPending( display ))
633 XNextEvent( display, &event );
634 EVENT_ProcessEvent( &event );
639 /***********************************************************************
640 * MSG_WaitXEvent
642 * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
643 * Return TRUE if an event is pending, FALSE on timeout or error
644 * (for instance lost connection with the server).
646 BOOL MSG_WaitXEvent( LONG maxWait )
648 fd_set read_set;
649 struct timeval timeout;
650 XEvent event;
651 int fd = ConnectionNumber(display);
653 if (!XPending(display) && (maxWait != -1))
655 FD_ZERO( &read_set );
656 FD_SET( fd, &read_set );
657 timeout.tv_sec = maxWait / 1000;
658 timeout.tv_usec = (maxWait % 1000) * 1000;
659 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
660 return FALSE; /* Timeout or error */
663 /* Process the event (and possibly others that occurred in the meantime) */
666 XNextEvent( display, &event );
667 EVENT_ProcessEvent( &event );
669 while (XPending( display ));
670 return TRUE;
674 /***********************************************************************
675 * MSG_PeekMessage
677 static BOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last,
678 WORD flags, BOOL peek )
680 int pos, mask;
681 MESSAGEQUEUE *msgQueue;
682 LONG nextExp; /* Next timer expiration time */
684 if (first || last)
686 mask = QS_POSTMESSAGE; /* Always selectioned */
687 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
688 if ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) mask |= QS_MOUSE;
689 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
690 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
691 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
693 else mask = QS_MOUSE | QS_KEY | QS_POSTMESSAGE | QS_TIMER | QS_PAINT;
695 while(1)
697 msgQueue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) );
698 if (!msgQueue) return FALSE;
700 /* First handle a message put by SendMessage() */
701 if (msgQueue->status & QS_SENDMESSAGE)
703 if (!hwnd || (msgQueue->hWnd == hwnd))
705 if ((!first && !last) ||
706 ((msgQueue->msg >= first) && (msgQueue->msg <= last)))
708 msg->hwnd = msgQueue->hWnd;
709 msg->message = msgQueue->msg;
710 msg->wParam = msgQueue->wParam;
711 msg->lParam = msgQueue->lParam;
712 if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE;
713 break;
718 /* Now find a normal message */
719 pos = MSG_FindMsg( msgQueue, hwnd, first, last );
720 if (pos != -1)
722 QMSG *qmsg = &msgQueue->messages[pos];
723 *msg = qmsg->msg;
724 msgQueue->GetMessageTimeVal = msg->time;
725 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
726 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
728 if (flags & PM_REMOVE) MSG_RemoveMsg( msgQueue, pos );
729 break;
732 /* Now find a hardware event */
733 if (MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
735 /* Got one */
736 msgQueue->GetMessageTimeVal = msg->time;
737 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
738 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
739 break;
742 /* Now handle a WM_QUIT message */
743 if (msgQueue->wPostQMsg)
745 msg->hwnd = hwnd;
746 msg->message = WM_QUIT;
747 msg->wParam = msgQueue->wExitCode;
748 msg->lParam = 0;
749 break;
752 /* Now find a WM_PAINT message */
753 if ((msgQueue->status & QS_PAINT) && (mask & QS_PAINT))
755 msg->hwnd = WIN_FindWinToRepaint( hwnd );
756 msg->message = WM_PAINT;
757 msg->wParam = 0;
758 msg->lParam = 0;
759 if (msg->hwnd != 0) break;
762 /* Finally handle WM_TIMER messages */
763 if ((msgQueue->status & QS_TIMER) && (mask & QS_TIMER))
765 if (TIMER_CheckTimer( &nextExp, msg, hwnd, flags & PM_REMOVE ))
766 break; /* Got a timer msg */
768 else nextExp = -1; /* No timeout needed */
770 Yield();
772 /* Wait until something happens */
773 if (peek)
775 if (!MSG_WaitXEvent( 0 )) return FALSE; /* No pending event */
777 else /* Wait for an event, then restart the loop */
778 MSG_WaitXEvent( nextExp );
781 /* We got a message */
782 if (peek) return TRUE;
783 else return (msg->message != WM_QUIT);
787 /***********************************************************************
788 * MSG_InternalGetMessage
790 * GetMessage() function for internal use. Behave like GetMessage(),
791 * but also call message filters and optionally send WM_ENTERIDLE messages.
792 * 'hwnd' must be the handle of the dialog or menu window.
793 * 'code' is the message filter value (MSGF_??? codes).
795 BOOL MSG_InternalGetMessage( SEGPTR msg, HWND hwnd, HWND hwndOwner, short code,
796 WORD flags, BOOL sendIdle )
798 for (;;)
800 if (sendIdle)
802 if (!MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
803 0, 0, 0, flags, TRUE ))
805 /* No message present -> send ENTERIDLE and wait */
806 SendMessage( hwndOwner, WM_ENTERIDLE, code, (LPARAM)hwnd );
807 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
808 0, 0, 0, flags, FALSE );
811 else /* Always wait for a message */
812 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
813 0, 0, 0, flags, FALSE );
815 if (!CallMsgFilter( msg, code ))
816 return (((MSG *)PTR_SEG_TO_LIN(msg))->message != WM_QUIT);
818 /* Message filtered -> remove it from the queue */
819 /* if it's still there. */
820 if (!(flags & PM_REMOVE))
821 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
822 0, 0, 0, PM_REMOVE, TRUE );
827 /***********************************************************************
828 * PeekMessage (USER.109)
830 BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags )
832 return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
836 /***********************************************************************
837 * GetMessage (USER.108)
839 BOOL GetMessage( SEGPTR msg, HWND hwnd, WORD first, WORD last )
841 MSG_PeekMessage( (MSG *)PTR_SEG_TO_LIN(msg),
842 hwnd, first, last, PM_REMOVE, FALSE );
843 CALL_SYSTEM_HOOK( WH_GETMESSAGE, 0, 0, (LPARAM)msg );
844 CALL_TASK_HOOK( WH_GETMESSAGE, 0, 0, (LPARAM)msg );
845 return (((MSG *)PTR_SEG_TO_LIN(msg))->message != WM_QUIT);
850 /***********************************************************************
851 * PostMessage (USER.110)
853 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
855 MSG msg;
856 WND *wndPtr;
858 if (hwnd == HWND_BROADCAST) {
859 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
860 hwnd = GetTopWindow(GetDesktopWindow());
861 while (hwnd) {
862 if (!(wndPtr = WIN_FindWndPtr(hwnd))) break;
863 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION) {
864 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04X m=%04X w=%04X l=%08lX !\n",
865 hwnd, message, wParam, lParam);
866 PostMessage(hwnd, message, wParam, lParam);
869 char str[128];
870 GetWindowText(hwnd, str, sizeof(str));
871 dprintf_msg(stddeb, "BROADCAST GetWindowText()='%s' !\n", str);
873 hwnd = wndPtr->hwndNext;
875 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
876 return TRUE;
879 wndPtr = WIN_FindWndPtr( hwnd );
880 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
881 msg.hwnd = hwnd;
882 msg.message = message;
883 msg.wParam = wParam;
884 msg.lParam = lParam;
885 msg.time = GetTickCount();
886 msg.pt.x = 0;
887 msg.pt.y = 0;
889 return MSG_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
892 /***********************************************************************
893 * PostAppMessage (USER.116)
895 BOOL PostAppMessage( HTASK hTask, WORD message, WORD wParam, LONG lParam )
897 MSG msg;
899 if (GetTaskQueue(hTask) == 0) return FALSE;
900 msg.hwnd = 0;
901 msg.message = message;
902 msg.wParam = wParam;
903 msg.lParam = lParam;
904 msg.time = GetTickCount();
905 msg.pt.x = 0;
906 msg.pt.y = 0;
908 return MSG_AddMsg( GetTaskQueue(hTask), &msg, 0 );
912 /***********************************************************************
913 * SendMessage (USER.111)
915 LONG SendMessage( HWND hwnd, WORD msg, WORD wParam, LONG lParam )
917 WND * wndPtr;
918 LONG ret;
920 wndPtr = WIN_FindWndPtr( hwnd );
921 if (!wndPtr) return 0;
922 else {
923 /* Argh. This is inefficient. */
924 typedef struct {
925 LONG lParam;
926 WORD wParam;
927 WORD wMsg;
928 WORD hWnd;
929 } msgstruct;
930 HANDLE msgh = GlobalAlloc(0,sizeof(msgstruct));
931 SEGPTR segmsg = WIN16_GlobalLock(msgh);
932 msgstruct *Msg = PTR_SEG_TO_LIN(segmsg);
934 Msg->hWnd = hwnd;
935 Msg->wMsg = msg;
936 Msg->wParam = wParam;
937 Msg->lParam = lParam;
938 CALL_SYSTEM_HOOK( WH_CALLWNDPROC, 0, 0, (LPARAM)segmsg );
939 CALL_TASK_HOOK( WH_CALLWNDPROC, 0, 0, (LPARAM)segmsg );
940 ret = CallWindowProc( wndPtr->lpfnWndProc, Msg->hWnd, Msg->wMsg, Msg->wParam,
941 Msg->lParam );
942 GlobalUnlock(msgh);
943 GlobalFree(msgh);
944 dprintf_msg( stddeb,"SendMessage(%4.4x,%x,%x,%lx) -> %lx\n",
945 hwnd, msg, wParam, lParam, ret );
946 return ret;
951 /***********************************************************************
952 * WaitMessage (USER.112)
954 void WaitMessage( void )
956 MSG msg;
957 MESSAGEQUEUE *queue;
958 LONG nextExp = -1; /* Next timer expiration time */
960 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return;
961 if ((queue->wPostQMsg) ||
962 (queue->status & (QS_SENDMESSAGE | QS_PAINT)) ||
963 (queue->msgCount) || (sysMsgQueue->msgCount) )
964 return;
965 if ((queue->status & QS_TIMER) &&
966 TIMER_CheckTimer( &nextExp, &msg, 0, FALSE))
967 return;
968 MSG_WaitXEvent( nextExp );
972 /***********************************************************************
973 * TranslateMessage (USER.113)
975 BOOL TranslateMessage( LPMSG msg )
977 int message = msg->message;
979 if ((message == WM_KEYDOWN) || (message == WM_KEYUP) ||
980 (message == WM_SYSKEYDOWN) || (message == WM_SYSKEYUP))
982 dprintf_msg(stddeb, "Translating key message\n" );
983 return TRUE;
985 return FALSE;
989 /***********************************************************************
990 * DispatchMessage (USER.114)
992 LONG DispatchMessage( LPMSG msg )
994 WND * wndPtr;
995 LONG retval;
996 int painting;
998 dprintf_msg(stddeb, "Dispatch message hwnd=%04x msg=0x%x w=%d l=%ld time=%lu pt=%d,%d\n",
999 msg->hwnd, msg->message, msg->wParam, msg->lParam,
1000 msg->time, msg->pt.x, msg->pt.y );
1002 /* Process timer messages */
1003 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1005 if (msg->lParam)
1006 return CallWindowProc( (WNDPROC)msg->lParam, msg->hwnd,
1007 msg->message, msg->wParam, GetTickCount() );
1010 if (!msg->hwnd) return 0;
1011 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1012 if (!wndPtr->lpfnWndProc) return 0;
1013 painting = (msg->message == WM_PAINT);
1014 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1015 retval = CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message,
1016 msg->wParam, msg->lParam );
1017 if (painting && IsWindow(msg->hwnd) &&
1018 (wndPtr->flags & WIN_NEEDS_BEGINPAINT))
1020 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %d!\n",
1021 msg->hwnd);
1022 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1024 return retval;
1028 /***********************************************************************
1029 * GetMessagePos (USER.119)
1031 DWORD GetMessagePos(void)
1033 MESSAGEQUEUE *queue;
1035 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1036 return queue->GetMessagePosVal;
1040 /***********************************************************************
1041 * GetMessageTime (USER.120)
1043 LONG GetMessageTime(void)
1045 MESSAGEQUEUE *queue;
1047 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1048 return queue->GetMessageTimeVal;
1052 /***********************************************************************
1053 * GetMessageExtraInfo (USER.288)
1055 LONG GetMessageExtraInfo(void)
1057 MESSAGEQUEUE *queue;
1059 if (!(queue = (MESSAGEQUEUE *)GlobalLock( GetTaskQueue(0) ))) return 0;
1060 return queue->GetMessageExtraInfoVal;
1064 /***********************************************************************
1065 * RegisterWindowMessage (USER.118)
1067 WORD RegisterWindowMessage( LPCSTR str )
1069 WORD wRet;
1070 dprintf_msg(stddeb, "RegisterWindowMessage: '%s'\n", str );
1071 wRet = GlobalAddAtom( str );
1072 return wRet;
1076 /***********************************************************************
1077 * GetTickCount (USER.13)
1079 DWORD GetTickCount(void)
1081 struct timeval t;
1082 gettimeofday( &t, NULL );
1083 return (t.tv_sec * 1000) + (t.tv_usec / 1000);
1086 /***********************************************************************
1087 * InSendMessage (USER.192
1089 * According to the book, this should return true iff the current message
1090 * was send from another application. In that case, the application should
1091 * invoke ReplyMessage before calling message relevant API.
1092 * Currently, Wine will always return FALSE, as there is no other app.
1094 BOOL InSendMessage()
1096 return FALSE;