2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
15 #include "sysmetrics.h"
23 /* #define DEBUG_MSG */
26 #define HWND_BROADCAST ((HWND)0xffff)
27 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
30 extern BOOL
TIMER_CheckTimer( LONG
*next
, MSG
*msg
,
31 HWND hwnd
, BOOL remove
); /* timer.c */
33 /* ------- Internal Queues ------ */
35 static HANDLE hmemSysMsgQueue
= 0;
36 static MESSAGEQUEUE
*sysMsgQueue
= NULL
;
38 HANDLE hActiveQ_G
= 0;
39 static HANDLE hFirstQueue
= 0;
41 /* ------- Miscellaneous ------ */
42 static int doubleClickSpeed
= 452;
45 /***********************************************************************
48 * Create a message queue.
50 static HANDLE
MSG_CreateMsgQueue( int size
)
53 MESSAGEQUEUE
* msgQueue
;
56 queueSize
= sizeof(MESSAGEQUEUE
) + size
* sizeof(QMSG
);
57 if (!(hQueue
= GlobalAlloc( GMEM_FIXED
| GMEM_ZEROINIT
, queueSize
)))
59 msgQueue
= (MESSAGEQUEUE
*) GlobalLock( hQueue
);
60 msgQueue
->msgSize
= sizeof(QMSG
);
61 msgQueue
->queueSize
= size
;
62 msgQueue
->wWinVersion
= 0; /* FIXME? */
63 GlobalUnlock( hQueue
);
67 /***********************************************************************
70 BOOL
MSG_DeleteMsgQueue( HANDLE hQueue
)
72 MESSAGEQUEUE
* msgQueue
= (MESSAGEQUEUE
*)GlobalLock(hQueue
);
76 dprintf_msg(stddeb
,"DeleteMsgQueue: invalid argument.\n");
80 if( !msgQueue
) return 0;
82 if( hQueue
== hFirstQueue
)
83 hFirstQueue
= msgQueue
->next
;
84 else if( hFirstQueue
)
86 MESSAGEQUEUE
*msgQ
= (MESSAGEQUEUE
*)GlobalLock(hFirstQueue
);
88 /* walk up queue list and relink if needed */
91 if( msgQ
->next
== hQueue
)
92 msgQ
->next
= msgQueue
->next
;
94 /* should check for intertask sendmessages here */
97 msgQ
= (MESSAGEQUEUE
*)GlobalLock(msgQ
->next
);
101 GlobalFree( hQueue
);
105 /***********************************************************************
106 * MSG_CreateSysMsgQueue
108 * Create the system message queue, and set the double-click speed.
109 * Must be called only once.
111 BOOL
MSG_CreateSysMsgQueue( int size
)
113 if (size
> MAX_QUEUE_SIZE
) size
= MAX_QUEUE_SIZE
;
114 else if (size
<= 0) size
= 1;
115 if (!(hmemSysMsgQueue
= MSG_CreateMsgQueue( size
))) return FALSE
;
116 sysMsgQueue
= (MESSAGEQUEUE
*) GlobalLock( hmemSysMsgQueue
);
117 doubleClickSpeed
= GetProfileInt( "windows", "DoubleClickSpeed", 452 );
122 /***********************************************************************
125 * Add a message to the queue. Return FALSE if queue is full.
127 static int MSG_AddMsg( HANDLE hQueue
, MSG
* msg
, DWORD extraInfo
)
130 MESSAGEQUEUE
*msgQueue
;
132 if (!(msgQueue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return FALSE
;
133 pos
= msgQueue
->nextFreeMessage
;
135 /* Check if queue is full */
136 if ((pos
== msgQueue
->nextMessage
) && (msgQueue
->msgCount
> 0)) {
137 fprintf(stderr
,"MSG_AddMsg // queue is full !\n");
142 msgQueue
->messages
[pos
].msg
= *msg
;
143 msgQueue
->messages
[pos
].extraInfo
= extraInfo
;
144 if (pos
< msgQueue
->queueSize
-1) pos
++;
146 msgQueue
->nextFreeMessage
= pos
;
147 msgQueue
->msgCount
++;
148 msgQueue
->status
|= QS_POSTMESSAGE
;
149 msgQueue
->tempStatus
|= QS_POSTMESSAGE
;
154 /***********************************************************************
157 * Find a message matching the given parameters. Return -1 if none available.
159 static int MSG_FindMsg(MESSAGEQUEUE
* msgQueue
, HWND hwnd
, int first
, int last
)
161 int i
, pos
= msgQueue
->nextMessage
;
163 dprintf_msg(stddeb
,"MSG_FindMsg: hwnd=0x"NPFMT
"\n\n", hwnd
);
165 if (!msgQueue
->msgCount
) return -1;
166 if (!hwnd
&& !first
&& !last
) return pos
;
168 for (i
= 0; i
< msgQueue
->msgCount
; i
++)
170 MSG
* msg
= &msgQueue
->messages
[pos
].msg
;
172 if (!hwnd
|| (msg
->hwnd
== hwnd
))
174 if (!first
&& !last
) return pos
;
175 if ((msg
->message
>= first
) && (msg
->message
<= last
)) return pos
;
177 if (pos
< msgQueue
->queueSize
-1) pos
++;
184 /***********************************************************************
187 * Remove a message from the queue (pos must be a valid position).
189 static void MSG_RemoveMsg( MESSAGEQUEUE
* msgQueue
, int pos
)
191 if (pos
>= msgQueue
->nextMessage
)
193 for ( ; pos
> msgQueue
->nextMessage
; pos
--)
194 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
-1];
195 msgQueue
->nextMessage
++;
196 if (msgQueue
->nextMessage
>= msgQueue
->queueSize
)
197 msgQueue
->nextMessage
= 0;
201 for ( ; pos
< msgQueue
->nextFreeMessage
; pos
++)
202 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
+1];
203 if (msgQueue
->nextFreeMessage
) msgQueue
->nextFreeMessage
--;
204 else msgQueue
->nextFreeMessage
= msgQueue
->queueSize
-1;
206 msgQueue
->msgCount
--;
207 if (!msgQueue
->msgCount
) msgQueue
->status
&= ~QS_POSTMESSAGE
;
208 msgQueue
->tempStatus
= 0;
211 /***********************************************************************
214 HTASK
MSG_GetQueueTask( HANDLE hQueue
)
216 MESSAGEQUEUE
*msgQ
= GlobalLock( hQueue
);
218 return (msgQ
) ? msgQ
->hTask
: 0 ;
221 /***********************************************************************
222 * MSG_GetWindowForEvent
224 * Find the window and hittest for a mouse event.
226 static INT
MSG_GetWindowForEvent( POINT pt
, HWND
*phwnd
)
230 INT hittest
= HTERROR
;
233 *phwnd
= hwnd
= GetDesktopWindow();
238 /* If point is in window, and window is visible, and it */
239 /* is enabled (or it's a top-level window), then explore */
240 /* its children. Otherwise, go to the next window. */
242 wndPtr
= WIN_FindWndPtr( hwnd
);
243 if ((wndPtr
->dwStyle
& WS_VISIBLE
) &&
244 (!(wndPtr
->dwStyle
& WS_DISABLED
) ||
245 !(wndPtr
->dwStyle
& WS_CHILD
)) &&
246 (x
>= wndPtr
->rectWindow
.left
) &&
247 (x
< wndPtr
->rectWindow
.right
) &&
248 (y
>= wndPtr
->rectWindow
.top
) &&
249 (y
< wndPtr
->rectWindow
.bottom
))
252 x
-= wndPtr
->rectClient
.left
;
253 y
-= wndPtr
->rectClient
.top
;
254 /* If window is minimized or disabled, ignore its children */
255 if ((wndPtr
->dwStyle
& WS_MINIMIZE
) ||
256 (wndPtr
->dwStyle
& WS_DISABLED
)) break;
257 hwnd
= wndPtr
->hwndChild
;
259 else hwnd
= wndPtr
->hwndNext
;
262 /* Make point relative to parent again */
264 wndPtr
= WIN_FindWndPtr( *phwnd
);
265 x
+= wndPtr
->rectClient
.left
;
266 y
+= wndPtr
->rectClient
.top
;
268 /* Send the WM_NCHITTEST message */
272 wndPtr
= WIN_FindWndPtr( *phwnd
);
273 if (wndPtr
->dwStyle
& WS_DISABLED
) hittest
= HTERROR
;
274 else hittest
= (INT
)SendMessage( *phwnd
, WM_NCHITTEST
, 0,
275 MAKELONG( pt
.x
, pt
.y
) );
276 if (hittest
!= HTTRANSPARENT
) break; /* Found the window */
277 hwnd
= wndPtr
->hwndNext
;
280 WND
*nextPtr
= WIN_FindWndPtr( hwnd
);
281 if ((nextPtr
->dwStyle
& WS_VISIBLE
) &&
282 (x
>= nextPtr
->rectWindow
.left
) &&
283 (x
< nextPtr
->rectWindow
.right
) &&
284 (y
>= nextPtr
->rectWindow
.top
) &&
285 (y
< nextPtr
->rectWindow
.bottom
)) break;
286 hwnd
= nextPtr
->hwndNext
;
288 if (hwnd
) *phwnd
= hwnd
; /* Found a suitable sibling */
289 else /* Go back to the parent */
291 if (!(*phwnd
= wndPtr
->hwndParent
)) break;
292 wndPtr
= WIN_FindWndPtr( *phwnd
);
293 x
+= wndPtr
->rectClient
.left
;
294 y
+= wndPtr
->rectClient
.top
;
298 if (!*phwnd
) *phwnd
= GetDesktopWindow();
303 /***********************************************************************
304 * MSG_TranslateMouseMsg
306 * Translate an mouse hardware event into a real mouse message.
307 * Return value indicates whether the translated message must be passed
310 * - Find the window for this message.
311 * - Translate button-down messages in double-clicks.
312 * - Send the WM_NCHITTEST message to find where the cursor is.
313 * - Activate the window if needed.
314 * - Translate the message into a non-client message, or translate
315 * the coordinates to client coordinates.
316 * - Send the WM_SETCURSOR message.
318 static BOOL
MSG_TranslateMouseMsg( MSG
*msg
, BOOL remove
)
322 static DWORD lastClickTime
= 0;
323 static WORD lastClickMsg
= 0;
324 static POINT lastClickPos
= { 0, 0 };
326 MOUSEHOOKSTRUCT hook
= { msg
->pt
, 0, HTCLIENT
, 0 };
328 BOOL mouseClick
= ((msg
->message
== WM_LBUTTONDOWN
) ||
329 (msg
->message
== WM_RBUTTONDOWN
) ||
330 (msg
->message
== WM_MBUTTONDOWN
));
332 /* Find the window */
336 msg
->hwnd
= GetCapture();
337 ScreenToClient( msg
->hwnd
, &pt
);
338 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
339 /* No need to further process the message */
340 hook
.hwnd
= msg
->hwnd
;
341 return !HOOK_CallHooks( WH_MOUSE
, remove
? HC_ACTION
: HC_NOREMOVE
,
342 msg
->message
, (LPARAM
)MAKE_SEGPTR(&hook
));
345 if ((hittest
= MSG_GetWindowForEvent( msg
->pt
, &msg
->hwnd
)) != HTERROR
)
348 /* Send the WM_PARENTNOTIFY message */
350 if (mouseClick
) WIN_SendParentNotify( msg
->hwnd
, msg
->message
, 0,
351 MAKELONG( msg
->pt
.x
, msg
->pt
.y
) );
353 /* Activate the window if needed */
357 HWND hwndTop
= WIN_GetTopParent( msg
->hwnd
);
358 if (hwndTop
!= GetActiveWindow())
360 LONG ret
= SendMessage( msg
->hwnd
, WM_MOUSEACTIVATE
,
362 MAKELONG( hittest
, msg
->message
) );
363 if ((ret
== MA_ACTIVATEANDEAT
) || (ret
== MA_NOACTIVATEANDEAT
))
365 if ((ret
== MA_ACTIVATE
) || (ret
== MA_ACTIVATEANDEAT
))
367 SetWindowPos( hwndTop
, HWND_TOP
, 0, 0, 0, 0,
368 SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
369 WINPOS_ChangeActiveWindow( hwndTop
, TRUE
);
375 /* Send the WM_SETCURSOR message */
377 SendMessage( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
378 MAKELONG( hittest
, msg
->message
));
379 if (eatMsg
) return FALSE
;
381 /* Check for double-click */
385 BOOL dbl_click
= FALSE
;
387 if ((msg
->message
== lastClickMsg
) &&
388 (msg
->time
- lastClickTime
< doubleClickSpeed
) &&
389 (abs(msg
->pt
.x
- lastClickPos
.x
) < SYSMETRICS_CXDOUBLECLK
/2) &&
390 (abs(msg
->pt
.y
- lastClickPos
.y
) < SYSMETRICS_CYDOUBLECLK
/2))
393 if (dbl_click
&& (hittest
== HTCLIENT
))
395 /* Check whether window wants the double click message. */
396 WND
* wndPtr
= WIN_FindWndPtr( msg
->hwnd
);
397 if (!wndPtr
|| !(WIN_CLASS_STYLE(wndPtr
) & CS_DBLCLKS
))
401 if (dbl_click
) switch(msg
->message
)
403 case WM_LBUTTONDOWN
: msg
->message
= WM_LBUTTONDBLCLK
; break;
404 case WM_RBUTTONDOWN
: msg
->message
= WM_RBUTTONDBLCLK
; break;
405 case WM_MBUTTONDOWN
: msg
->message
= WM_MBUTTONDBLCLK
; break;
410 lastClickTime
= msg
->time
;
411 lastClickMsg
= msg
->message
;
412 lastClickPos
= msg
->pt
;
416 /* Build the translated message */
418 if (hittest
== HTCLIENT
)
419 ScreenToClient( msg
->hwnd
, &pt
);
422 msg
->wParam
= hittest
;
423 msg
->message
+= WM_NCLBUTTONDOWN
- WM_LBUTTONDOWN
;
425 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
427 hook
.hwnd
= msg
->hwnd
;
428 hook
.wHitTestCode
= hittest
;
429 return !HOOK_CallHooks( WH_MOUSE
, remove
? HC_ACTION
: HC_NOREMOVE
,
430 msg
->message
, (LPARAM
)MAKE_SEGPTR(&hook
));
434 /***********************************************************************
435 * MSG_TranslateKeyboardMsg
437 * Translate an keyboard hardware event into a real message.
438 * Return value indicates whether the translated message must be passed
441 static BOOL
MSG_TranslateKeyboardMsg( MSG
*msg
, BOOL remove
)
443 /* Should check Ctrl-Esc and PrintScreen here */
445 msg
->hwnd
= GetFocus();
448 /* Send the message to the active window instead, */
449 /* translating messages to their WM_SYS equivalent */
450 msg
->hwnd
= GetActiveWindow();
451 msg
->message
+= WM_SYSKEYDOWN
- WM_KEYDOWN
;
453 return !HOOK_CallHooks( WH_KEYBOARD
, remove
? HC_ACTION
: HC_NOREMOVE
,
454 msg
->wParam
, msg
->lParam
);
458 /***********************************************************************
459 * MSG_PeekHardwareMsg
461 * Peek for a hardware message matching the hwnd and message filters.
463 static BOOL
MSG_PeekHardwareMsg( MSG
*msg
, HWND hwnd
, WORD first
, WORD last
,
466 int i
, pos
= sysMsgQueue
->nextMessage
;
468 for (i
= 0; i
< sysMsgQueue
->msgCount
; i
++, pos
++)
470 if (pos
>= sysMsgQueue
->queueSize
) pos
= 0;
471 *msg
= sysMsgQueue
->messages
[pos
].msg
;
473 /* Translate message */
475 if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
477 if (!MSG_TranslateMouseMsg( msg
, remove
)) continue;
479 else if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
481 if (!MSG_TranslateKeyboardMsg( msg
, remove
)) continue;
483 else /* Non-standard hardware event */
485 HARDWAREHOOKSTRUCT hook
= { msg
->hwnd
, msg
->message
,
486 msg
->wParam
, msg
->lParam
};
487 if (HOOK_CallHooks( WH_HARDWARE
, remove
? HC_ACTION
: HC_NOREMOVE
,
488 0, (LPARAM
)MAKE_SEGPTR(&hook
) )) continue;
491 /* Check message against filters */
493 if (hwnd
&& (msg
->hwnd
!= hwnd
)) continue;
494 if ((first
|| last
) &&
495 ((msg
->message
< first
) || (msg
->message
> last
))) continue;
496 if ((msg
->hwnd
!= GetDesktopWindow()) &&
497 (GetWindowTask(msg
->hwnd
) != GetCurrentTask()))
498 continue; /* Not for this task */
501 MSG tmpMsg
= *msg
; /* FIXME */
502 HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
,
503 0, (LPARAM
)MAKE_SEGPTR(&tmpMsg
) );
504 MSG_RemoveMsg( sysMsgQueue
, pos
);
512 /**********************************************************************
513 * SetDoubleClickTime (USER.20)
515 void SetDoubleClickTime( WORD interval
)
518 doubleClickSpeed
= 500;
520 doubleClickSpeed
= interval
;
524 /**********************************************************************
525 * GetDoubleClickTime (USER.21)
527 WORD
GetDoubleClickTime()
529 return (WORD
)doubleClickSpeed
;
533 /***********************************************************************
536 void MSG_IncPaintCount( HANDLE hQueue
)
540 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
541 queue
->wPaintCount
++;
542 queue
->status
|= QS_PAINT
;
543 queue
->tempStatus
|= QS_PAINT
;
547 /***********************************************************************
550 void MSG_DecPaintCount( HANDLE hQueue
)
554 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
555 queue
->wPaintCount
--;
556 if (!queue
->wPaintCount
) queue
->status
&= ~QS_PAINT
;
560 /***********************************************************************
563 void MSG_IncTimerCount( HANDLE hQueue
)
567 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
568 queue
->wTimerCount
++;
569 queue
->status
|= QS_TIMER
;
570 queue
->tempStatus
|= QS_TIMER
;
574 /***********************************************************************
577 void MSG_DecTimerCount( HANDLE hQueue
)
581 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
582 queue
->wTimerCount
--;
583 if (!queue
->wTimerCount
) queue
->status
&= ~QS_TIMER
;
587 /***********************************************************************
590 * Add an event to the system message queue.
591 * Note: the position is relative to the desktop window.
593 void hardware_event( WORD message
, WORD wParam
, LONG lParam
,
594 int xPos
, int yPos
, DWORD time
, DWORD extraInfo
)
599 if (!sysMsgQueue
) return;
600 pos
= sysMsgQueue
->nextFreeMessage
;
602 /* Merge with previous event if possible */
604 if ((message
== WM_MOUSEMOVE
) && sysMsgQueue
->msgCount
)
607 else pos
= sysMsgQueue
->queueSize
- 1;
608 msg
= &sysMsgQueue
->messages
[pos
].msg
;
609 if ((msg
->message
== message
) && (msg
->wParam
== wParam
))
610 sysMsgQueue
->msgCount
--; /* Merge events */
612 pos
= sysMsgQueue
->nextFreeMessage
; /* Don't merge */
615 /* Check if queue is full */
617 if ((pos
== sysMsgQueue
->nextMessage
) && sysMsgQueue
->msgCount
)
619 /* Queue is full, beep (but not on every mouse motion...) */
620 if (message
!= WM_MOUSEMOVE
) MessageBeep(0);
626 msg
= &sysMsgQueue
->messages
[pos
].msg
;
628 msg
->message
= message
;
629 msg
->wParam
= wParam
;
630 msg
->lParam
= lParam
;
632 msg
->pt
.x
= xPos
& 0xffff;
633 msg
->pt
.y
= yPos
& 0xffff;
634 sysMsgQueue
->messages
[pos
].extraInfo
= extraInfo
;
635 if (pos
< sysMsgQueue
->queueSize
- 1) pos
++;
637 sysMsgQueue
->nextFreeMessage
= pos
;
638 sysMsgQueue
->msgCount
++;
642 /***********************************************************************
643 * MSG_GetHardwareMessage
645 * Like GetMessage(), but only return mouse and keyboard events.
646 * Used internally for window moving and resizing. Mouse messages
647 * are not translated.
648 * Warning: msg->hwnd is always 0.
650 BOOL
MSG_GetHardwareMessage( LPMSG msg
)
657 if ((pos
= MSG_FindMsg( sysMsgQueue
, 0, 0, 0 )) != -1)
659 *msg
= sysMsgQueue
->messages
[pos
].msg
;
660 MSG_RemoveMsg( sysMsgQueue
, pos
);
663 XNextEvent( display
, &event
);
664 EVENT_ProcessEvent( &event
);
670 /***********************************************************************
671 * SetMessageQueue (USER.266)
673 BOOL
SetMessageQueue( int size
)
676 HGLOBAL hNextQueue
= hFirstQueue
;
677 MESSAGEQUEUE
*queuePrev
= NULL
;
678 MESSAGEQUEUE
*queuePtr
;
680 if ((size
> MAX_QUEUE_SIZE
) || (size
<= 0)) return TRUE
;
682 /* Free the old message queue */
683 if ((hQueue
= GetTaskQueue(0)) != 0)
685 MESSAGEQUEUE
*queuePtr
= (MESSAGEQUEUE
*)GlobalLock( hQueue
);
689 MESSAGEQUEUE
*msgQ
= (MESSAGEQUEUE
*)GlobalLock(hFirstQueue
);
691 hNextQueue
= queuePtr
->next
;
694 if( hQueue
!= hFirstQueue
)
697 if( msgQ
->next
== hQueue
)
702 msgQ
= (MESSAGEQUEUE
*)GlobalLock(msgQ
->next
);
704 GlobalUnlock( hQueue
);
705 MSG_DeleteMsgQueue( hQueue
);
709 if( !(hQueue
= MSG_CreateMsgQueue( size
)))
712 /* it did have a queue */
713 queuePrev
->next
= hNextQueue
;
717 queuePtr
= (MESSAGEQUEUE
*)GlobalLock( hQueue
);
718 queuePtr
->hTask
= GetCurrentTask();
719 queuePtr
->next
= hNextQueue
;
722 hFirstQueue
= hQueue
;
724 queuePrev
->next
= hQueue
;
726 SetTaskQueue( 0, hQueue
);
731 /***********************************************************************
732 * GetWindowTask (USER.224)
734 HTASK
GetWindowTask( HWND hwnd
)
736 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
737 MESSAGEQUEUE
*queuePtr
;
739 if (!wndPtr
) return 0;
740 queuePtr
= (MESSAGEQUEUE
*)GlobalLock( wndPtr
->hmemTaskQ
);
741 if (!queuePtr
) return 0;
742 return queuePtr
->hTask
;
746 /***********************************************************************
747 * PostQuitMessage (USER.6)
749 void PostQuitMessage( int exitCode
)
753 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return;
754 queue
->wPostQMsg
= TRUE
;
755 queue
->wExitCode
= exitCode
;
759 /***********************************************************************
760 * GetQueueStatus (USER.334)
762 DWORD
GetQueueStatus( int flags
)
767 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
768 ret
= MAKELONG( queue
->tempStatus
, queue
->status
);
769 queue
->tempStatus
= 0;
770 return ret
& MAKELONG( flags
, flags
);
774 /***********************************************************************
775 * GetInputState (USER.335)
781 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return FALSE
;
782 return queue
->status
& (QS_KEY
| QS_MOUSEBUTTON
);
786 /***********************************************************************
789 * Synchronize with the X server. Should not be used too often.
791 void MSG_Synchronize()
795 XSync( display
, False
);
796 while (XPending( display
))
798 XNextEvent( display
, &event
);
799 EVENT_ProcessEvent( &event
);
804 /***********************************************************************
807 * Wait for an X event, but at most maxWait milliseconds (-1 for no timeout).
808 * Return TRUE if an event is pending, FALSE on timeout or error
809 * (for instance lost connection with the server).
811 BOOL
MSG_WaitXEvent( LONG maxWait
)
814 struct timeval timeout
;
816 int fd
= ConnectionNumber(display
);
818 if (!XPending(display
) && (maxWait
!= -1))
820 FD_ZERO( &read_set
);
821 FD_SET( fd
, &read_set
);
823 timeout
.tv_usec
= (maxWait
% 1000) * 1000;
824 timeout
.tv_sec
= maxWait
/ 1000;
827 sigsetjmp(env_wait_x
, 1);
830 if (DDE_GetRemoteMessage()) {
831 while(DDE_GetRemoteMessage())
835 stop_wait_op
= STOP_WAIT_X
;
836 /* The code up to the next "stop_wait_op= CONT" must be reentrant */
837 if (select( fd
+1, &read_set
, NULL
, NULL
, &timeout
) != 1 &&
838 !XPending(display
)) {
844 #else /* CONFIG_IPC */
845 if (select( fd
+1, &read_set
, NULL
, NULL
, &timeout
) != 1)
846 return FALSE
; /* Timeout or error */
847 #endif /* CONFIG_IPC */
851 /* Process the event (and possibly others that occurred in the meantime) */
856 if (DDE_GetRemoteMessage())
858 while(DDE_GetRemoteMessage()) ;
861 #endif /* CONFIG_IPC */
863 XNextEvent( display
, &event
);
864 EVENT_ProcessEvent( &event
);
866 while (XPending( display
));
871 /***********************************************************************
874 static BOOL
MSG_PeekMessage( LPMSG msg
, HWND hwnd
, WORD first
, WORD last
,
875 WORD flags
, BOOL peek
)
878 MESSAGEQUEUE
*msgQueue
;
879 LONG nextExp
; /* Next timer expiration time */
882 DDE_TestDDE(hwnd
); /* do we have dde handling in the window ?*/
883 DDE_GetRemoteMessage();
884 #endif /* CONFIG_IPC */
888 mask
= QS_POSTMESSAGE
; /* Always selectioned */
889 if ((first
<= WM_KEYLAST
) && (last
>= WM_KEYFIRST
)) mask
|= QS_KEY
;
890 if ((first
<= WM_MOUSELAST
) && (last
>= WM_MOUSEFIRST
)) mask
|= QS_MOUSE
;
891 if ((first
<= WM_TIMER
) && (last
>= WM_TIMER
)) mask
|= QS_TIMER
;
892 if ((first
<= WM_SYSTIMER
) && (last
>= WM_SYSTIMER
)) mask
|= QS_TIMER
;
893 if ((first
<= WM_PAINT
) && (last
>= WM_PAINT
)) mask
|= QS_PAINT
;
895 else mask
= QS_MOUSE
| QS_KEY
| QS_POSTMESSAGE
| QS_TIMER
| QS_PAINT
;
899 msgQueue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) );
900 if (!msgQueue
) return FALSE
;
902 /* First handle a message put by SendMessage() */
903 if (msgQueue
->status
& QS_SENDMESSAGE
)
905 if (!hwnd
|| (msgQueue
->hWnd
== hwnd
))
907 if ((!first
&& !last
) ||
908 ((msgQueue
->msg
>= first
) && (msgQueue
->msg
<= last
)))
910 msg
->hwnd
= msgQueue
->hWnd
;
911 msg
->message
= msgQueue
->msg
;
912 msg
->wParam
= msgQueue
->wParam
;
913 msg
->lParam
= msgQueue
->lParam
;
914 if (flags
& PM_REMOVE
) msgQueue
->status
&= ~QS_SENDMESSAGE
;
920 /* Now find a normal message */
921 pos
= MSG_FindMsg( msgQueue
, hwnd
, first
, last
);
924 QMSG
*qmsg
= &msgQueue
->messages
[pos
];
926 msgQueue
->GetMessageTimeVal
= msg
->time
;
927 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
928 msgQueue
->GetMessageExtraInfoVal
= qmsg
->extraInfo
;
930 if (flags
& PM_REMOVE
) MSG_RemoveMsg( msgQueue
, pos
);
934 /* Now find a hardware event */
935 if (MSG_PeekHardwareMsg( msg
, hwnd
, first
, last
, flags
& PM_REMOVE
))
938 msgQueue
->GetMessageTimeVal
= msg
->time
;
939 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
940 msgQueue
->GetMessageExtraInfoVal
= 0; /* Always 0 for now */
944 /* Now handle a WM_QUIT message */
945 if (msgQueue
->wPostQMsg
)
948 msg
->message
= WM_QUIT
;
949 msg
->wParam
= msgQueue
->wExitCode
;
954 /* Now find a WM_PAINT message */
955 if ((msgQueue
->status
& QS_PAINT
) && (mask
& QS_PAINT
))
957 msg
->hwnd
= WIN_FindWinToRepaint( hwnd
);
958 msg
->message
= WM_PAINT
;
961 if (msg
->hwnd
!= 0) break;
964 /* Finally handle WM_TIMER messages */
965 if ((msgQueue
->status
& QS_TIMER
) && (mask
& QS_TIMER
))
967 if (TIMER_CheckTimer( &nextExp
, msg
, hwnd
, flags
& PM_REMOVE
))
968 break; /* Got a timer msg */
970 else nextExp
= -1; /* No timeout needed */
974 /* Wait until something happens */
977 if (!MSG_WaitXEvent( 0 )) return FALSE
; /* No pending event */
979 else /* Wait for an event, then restart the loop */
980 MSG_WaitXEvent( nextExp
);
983 /* We got a message */
984 if (peek
) return TRUE
;
985 else return (msg
->message
!= WM_QUIT
);
989 /***********************************************************************
990 * MSG_InternalGetMessage
992 * GetMessage() function for internal use. Behave like GetMessage(),
993 * but also call message filters and optionally send WM_ENTERIDLE messages.
994 * 'hwnd' must be the handle of the dialog or menu window.
995 * 'code' is the message filter value (MSGF_??? codes).
997 BOOL
MSG_InternalGetMessage( SEGPTR msg
, HWND hwnd
, HWND hwndOwner
, short code
,
998 WORD flags
, BOOL sendIdle
)
1004 if (!MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
1005 0, 0, 0, flags
, TRUE
))
1007 /* No message present -> send ENTERIDLE and wait */
1008 SendMessage( hwndOwner
, WM_ENTERIDLE
, code
, (LPARAM
)hwnd
);
1009 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
1010 0, 0, 0, flags
, FALSE
);
1013 else /* Always wait for a message */
1014 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
1015 0, 0, 0, flags
, FALSE
);
1017 if (!CallMsgFilter( msg
, code
))
1018 return (((MSG
*)PTR_SEG_TO_LIN(msg
))->message
!= WM_QUIT
);
1020 /* Message filtered -> remove it from the queue */
1021 /* if it's still there. */
1022 if (!(flags
& PM_REMOVE
))
1023 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
1024 0, 0, 0, PM_REMOVE
, TRUE
);
1029 /***********************************************************************
1030 * PeekMessage (USER.109)
1032 BOOL
PeekMessage( LPMSG msg
, HWND hwnd
, WORD first
, WORD last
, WORD flags
)
1034 return MSG_PeekMessage( msg
, hwnd
, first
, last
, flags
, TRUE
);
1038 /***********************************************************************
1039 * GetMessage (USER.108)
1041 BOOL
GetMessage( SEGPTR msg
, HWND hwnd
, UINT first
, UINT last
)
1043 MSG_PeekMessage( (MSG
*)PTR_SEG_TO_LIN(msg
),
1044 hwnd
, first
, last
, PM_REMOVE
, FALSE
);
1045 HOOK_CallHooks( WH_GETMESSAGE
, HC_ACTION
, 0, (LPARAM
)msg
);
1046 return (((MSG
*)PTR_SEG_TO_LIN(msg
))->message
!= WM_QUIT
);
1051 /***********************************************************************
1052 * PostMessage (USER.110)
1054 BOOL
PostMessage( HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
1060 msg
.message
= message
;
1061 msg
.wParam
= wParam
;
1062 msg
.lParam
= lParam
;
1063 msg
.time
= GetTickCount();
1068 if (DDE_PostMessage(&msg
))
1070 #endif /* CONFIG_IPC */
1072 if (hwnd
== HWND_BROADCAST
) {
1073 dprintf_msg(stddeb
,"PostMessage // HWND_BROADCAST !\n");
1074 hwnd
= GetTopWindow(GetDesktopWindow());
1076 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) break;
1077 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
) {
1078 dprintf_msg(stddeb
,"BROADCAST Message to hWnd="NPFMT
" m=%04X w=%04X l=%08lX !\n",
1079 hwnd
, message
, wParam
, lParam
);
1080 PostMessage(hwnd
, message
, wParam
, lParam
);
1082 hwnd
= wndPtr
->hwndNext
;
1084 dprintf_msg(stddeb
,"PostMessage // End of HWND_BROADCAST !\n");
1088 wndPtr
= WIN_FindWndPtr( hwnd
);
1089 if (!wndPtr
|| !wndPtr
->hmemTaskQ
) return FALSE
;
1091 return MSG_AddMsg( wndPtr
->hmemTaskQ
, &msg
, 0 );
1094 /***********************************************************************
1095 * PostAppMessage (USER.116)
1097 BOOL
PostAppMessage( HTASK hTask
, WORD message
, WORD wParam
, LONG lParam
)
1101 if (GetTaskQueue(hTask
) == 0) return FALSE
;
1103 msg
.message
= message
;
1104 msg
.wParam
= wParam
;
1105 msg
.lParam
= lParam
;
1106 msg
.time
= GetTickCount();
1110 return MSG_AddMsg( GetTaskQueue(hTask
), &msg
, 0 );
1114 /***********************************************************************
1115 * SendMessage (USER.111)
1117 LRESULT
SendMessage( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1127 } msgstruct
= { lParam
, wParam
, msg
, hwnd
};
1130 MSG DDE_msg
= { hwnd
, msg
, wParam
, lParam
};
1131 if (DDE_SendMessage(&DDE_msg
)) return TRUE
;
1132 #endif /* CONFIG_IPC */
1134 if (hwnd
== HWND_BROADCAST
)
1136 dprintf_msg(stddeb
,"SendMessage // HWND_BROADCAST !\n");
1137 hwnd
= GetTopWindow(GetDesktopWindow());
1140 if (!(wndPtr
= WIN_FindWndPtr(hwnd
))) break;
1141 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
1143 dprintf_msg(stddeb
,"BROADCAST Message to hWnd="NPFMT
" m=%04X w=%04lX l=%08lX !\n",
1144 hwnd
, msg
, (DWORD
)wParam
, lParam
);
1145 ret
|= SendMessage( hwnd
, msg
, wParam
, lParam
);
1147 hwnd
= wndPtr
->hwndNext
;
1149 dprintf_msg(stddeb
,"SendMessage // End of HWND_BROADCAST !\n");
1153 EnterSpyMessage(SPY_SENDMESSAGE
, hwnd
, msg
, wParam
, lParam
);
1155 HOOK_CallHooks( WH_CALLWNDPROC
, HC_ACTION
, 1, (LPARAM
)MAKE_SEGPTR(&msgstruct
) );
1156 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
1158 ExitSpyMessage(SPY_RESULT_INVALIDHWND
,hwnd
,msg
,0);
1161 ret
= CallWindowProc( wndPtr
->lpfnWndProc
, msgstruct
.hWnd
, msgstruct
.wMsg
,
1162 msgstruct
.wParam
, msgstruct
.lParam
);
1163 ExitSpyMessage(SPY_RESULT_OK
,hwnd
,msg
,ret
);
1168 /***********************************************************************
1169 * WaitMessage (USER.112)
1171 void WaitMessage( void )
1174 MESSAGEQUEUE
*queue
;
1175 LONG nextExp
= -1; /* Next timer expiration time */
1178 DDE_GetRemoteMessage();
1179 #endif /* CONFIG_IPC */
1181 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return;
1182 if ((queue
->wPostQMsg
) ||
1183 (queue
->status
& (QS_SENDMESSAGE
| QS_PAINT
)) ||
1184 (queue
->msgCount
) || (sysMsgQueue
->msgCount
) )
1186 if ((queue
->status
& QS_TIMER
) &&
1187 TIMER_CheckTimer( &nextExp
, &msg
, 0, FALSE
))
1189 /* FIXME: (dde) must check DDE & X-events simultaneously */
1190 MSG_WaitXEvent( nextExp
);
1194 /***********************************************************************
1195 * TranslateMessage (USER.113)
1197 BOOL
TranslateMessage( LPMSG msg
)
1199 int message
= msg
->message
;
1201 if ((message
== WM_KEYDOWN
) || (message
== WM_KEYUP
) ||
1202 (message
== WM_SYSKEYDOWN
) || (message
== WM_SYSKEYUP
))
1204 dprintf_msg(stddeb
, "Translating key message\n" );
1211 /***********************************************************************
1212 * DispatchMessage (USER.114)
1214 LONG
DispatchMessage( LPMSG msg
)
1220 EnterSpyMessage( SPY_DISPATCHMESSAGE
, msg
->hwnd
, msg
->message
,
1221 msg
->wParam
, msg
->lParam
);
1223 /* Process timer messages */
1224 if ((msg
->message
== WM_TIMER
) || (msg
->message
== WM_SYSTIMER
))
1229 HINSTANCE ds
= msg
->hwnd
? WIN_GetWindowInstance( msg
->hwnd
)
1230 : (HINSTANCE
)CURRENT_DS
;
1232 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1233 return CallWndProc( (WNDPROC
)msg
->lParam
, ds
, msg
->hwnd
,
1234 msg
->message
, msg
->wParam
, GetTickCount() );
1238 if (!msg
->hwnd
) return 0;
1239 if (!(wndPtr
= WIN_FindWndPtr( msg
->hwnd
))) return 0;
1240 if (!wndPtr
->lpfnWndProc
) return 0;
1241 painting
= (msg
->message
== WM_PAINT
);
1242 if (painting
) wndPtr
->flags
|= WIN_NEEDS_BEGINPAINT
;
1243 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1244 retval
= CallWindowProc( wndPtr
->lpfnWndProc
, msg
->hwnd
, msg
->message
,
1245 msg
->wParam
, msg
->lParam
);
1246 if (painting
&& IsWindow(msg
->hwnd
) &&
1247 (wndPtr
->flags
& WIN_NEEDS_BEGINPAINT
))
1249 fprintf(stderr
, "BeginPaint not called on WM_PAINT for hwnd "NPFMT
"!\n",
1251 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
1257 /***********************************************************************
1258 * GetMessagePos (USER.119)
1260 DWORD
GetMessagePos(void)
1262 MESSAGEQUEUE
*queue
;
1264 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
1265 return queue
->GetMessagePosVal
;
1269 /***********************************************************************
1270 * GetMessageTime (USER.120)
1272 LONG
GetMessageTime(void)
1274 MESSAGEQUEUE
*queue
;
1276 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
1277 return queue
->GetMessageTimeVal
;
1281 /***********************************************************************
1282 * GetMessageExtraInfo (USER.288)
1284 LONG
GetMessageExtraInfo(void)
1286 MESSAGEQUEUE
*queue
;
1288 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return 0;
1289 return queue
->GetMessageExtraInfoVal
;
1293 /***********************************************************************
1294 * RegisterWindowMessage (USER.118)
1296 WORD
RegisterWindowMessage( SEGPTR str
)
1298 dprintf_msg(stddeb
, "RegisterWindowMessage: '"SPFMT
"'\n", str
);
1299 return GlobalAddAtom( str
);
1303 /***********************************************************************
1304 * GetTickCount (USER.13) (KERNEL32.299)
1306 DWORD
GetTickCount(void)
1309 gettimeofday( &t
, NULL
);
1310 return (t
.tv_sec
* 1000) + (t
.tv_usec
/ 1000);
1313 /***********************************************************************
1314 * GetCurrentTime (effectively identical to GetTickCount)
1316 DWORD
GetCurrentTime(void)
1318 return GetTickCount();
1321 /***********************************************************************
1322 * InSendMessage (USER.192
1324 * According to the book, this should return true iff the current message
1325 * was send from another application. In that case, the application should
1326 * invoke ReplyMessage before calling message relevant API.
1327 * Currently, Wine will always return FALSE, as there is no other app.
1329 BOOL
InSendMessage()