2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
15 #include "sysmetrics.h"
20 /* #define DEBUG_MSG */
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 /***********************************************************************
43 * Create a message queue.
45 static HANDLE
MSG_CreateMsgQueue( int size
)
48 MESSAGEQUEUE
* msgQueue
;
51 queueSize
= sizeof(MESSAGEQUEUE
) + size
* sizeof(QMSG
);
52 if (!(hQueue
= GlobalAlloc( GMEM_FIXED
, queueSize
))) return 0;
53 msgQueue
= (MESSAGEQUEUE
*) GlobalLock( hQueue
);
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;
68 msgQueue
->wPostQMsg
= 0;
69 msgQueue
->wExitCode
= 0;
70 msgQueue
->InSendMessageHandle
= 0;
71 msgQueue
->wPaintCount
= 0;
72 msgQueue
->wTimerCount
= 0;
73 msgQueue
->tempStatus
= 0;
75 GlobalUnlock( 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 );
97 /***********************************************************************
100 * Add a message to the queue. Return FALSE if queue is full.
102 static int MSG_AddMsg( HANDLE hQueue
, MSG
* msg
, DWORD extraInfo
)
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");
117 msgQueue
->messages
[pos
].msg
= *msg
;
118 msgQueue
->messages
[pos
].extraInfo
= extraInfo
;
119 if (pos
< msgQueue
->queueSize
-1) pos
++;
121 msgQueue
->nextFreeMessage
= pos
;
122 msgQueue
->msgCount
++;
123 msgQueue
->status
|= QS_POSTMESSAGE
;
124 msgQueue
->tempStatus
|= QS_POSTMESSAGE
;
129 /***********************************************************************
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
++;
157 /***********************************************************************
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;
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
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
)
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 */
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
);
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 */
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
))
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 */
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))
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
))
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;
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
);
312 msg
->wParam
= hittest_result
;
313 msg
->message
+= WM_NCLBUTTONDOWN
- WM_LBUTTONDOWN
;
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
327 static BOOL
MSG_TranslateKeyboardMsg( MSG
*msg
)
329 /* Should check Ctrl-Esc and PrintScreen here */
331 msg
->hwnd
= GetFocus();
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
;
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
,
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
);
383 /**********************************************************************
384 * SetDoubleClickTime (USER.20)
386 void SetDoubleClickTime( WORD interval
)
389 doubleClickSpeed
= 500;
391 doubleClickSpeed
= interval
;
395 /**********************************************************************
396 * GetDoubleClickTime (USER.21)
398 WORD
GetDoubleClickTime()
400 return (WORD
)doubleClickSpeed
;
404 /***********************************************************************
407 void MSG_IncPaintCount( HANDLE hQueue
)
411 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
412 queue
->wPaintCount
++;
413 queue
->status
|= QS_PAINT
;
414 queue
->tempStatus
|= QS_PAINT
;
418 /***********************************************************************
421 void MSG_DecPaintCount( HANDLE hQueue
)
425 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
426 queue
->wPaintCount
--;
427 if (!queue
->wPaintCount
) queue
->status
&= ~QS_PAINT
;
431 /***********************************************************************
434 void MSG_IncTimerCount( HANDLE hQueue
)
438 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
439 queue
->wTimerCount
++;
440 queue
->status
|= QS_TIMER
;
441 queue
->tempStatus
|= QS_TIMER
;
445 /***********************************************************************
448 void MSG_DecTimerCount( HANDLE hQueue
)
452 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( hQueue
))) return;
453 queue
->wTimerCount
--;
454 if (!queue
->wTimerCount
) queue
->status
&= ~QS_TIMER
;
458 /***********************************************************************
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
)
470 if (!sysMsgQueue
) return;
471 pos
= sysMsgQueue
->nextFreeMessage
;
473 /* Merge with previous event if possible */
475 if ((message
== WM_MOUSEMOVE
) && sysMsgQueue
->msgCount
)
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 */
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);
497 msg
= &sysMsgQueue
->messages
[pos
].msg
;
499 msg
->message
= message
;
500 msg
->wParam
= wParam
;
501 msg
->lParam
= lParam
;
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
++;
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
)
528 if ((pos
= MSG_FindMsg( sysMsgQueue
, 0, 0, 0 )) != -1)
530 *msg
= sysMsgQueue
->messages
[pos
].msg
;
531 MSG_RemoveMsg( sysMsgQueue
, pos
);
534 XNextEvent( display
, &event
);
535 EVENT_ProcessEvent( &event
);
541 /***********************************************************************
542 * SetMessageQueue (USER.266)
544 BOOL
SetMessageQueue( int size
)
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
);
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
)
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
)
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)
616 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock( GetTaskQueue(0) ))) return FALSE
;
617 return queue
->status
& (QS_KEY
| QS_MOUSEBUTTON
);
621 /***********************************************************************
624 * Synchronize with the X server. Should not be used too often.
626 void MSG_Synchronize()
630 XSync( display
, False
);
631 while (XPending( display
))
633 XNextEvent( display
, &event
);
634 EVENT_ProcessEvent( &event
);
639 /***********************************************************************
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
)
649 struct timeval timeout
;
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
));
674 /***********************************************************************
677 static BOOL
MSG_PeekMessage( LPMSG msg
, HWND hwnd
, WORD first
, WORD last
,
678 WORD flags
, BOOL peek
)
681 MESSAGEQUEUE
*msgQueue
;
682 LONG nextExp
; /* Next timer expiration time */
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
;
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
;
718 /* Now find a normal message */
719 pos
= MSG_FindMsg( msgQueue
, hwnd
, first
, last
);
722 QMSG
*qmsg
= &msgQueue
->messages
[pos
];
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
);
732 /* Now find a hardware event */
733 if (MSG_PeekHardwareMsg( msg
, hwnd
, first
, last
, flags
& PM_REMOVE
))
736 msgQueue
->GetMessageTimeVal
= msg
->time
;
737 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
738 msgQueue
->GetMessageExtraInfoVal
= 0; /* Always 0 for now */
742 /* Now handle a WM_QUIT message */
743 if (msgQueue
->wPostQMsg
)
746 msg
->message
= WM_QUIT
;
747 msg
->wParam
= msgQueue
->wExitCode
;
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
;
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 */
772 /* Wait until something happens */
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
)
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
)
858 if (hwnd
== HWND_BROADCAST
) {
859 dprintf_msg(stddeb
,"PostMessage // HWND_BROADCAST !\n");
860 hwnd
= GetTopWindow(GetDesktopWindow());
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
);
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");
879 wndPtr
= WIN_FindWndPtr( hwnd
);
880 if (!wndPtr
|| !wndPtr
->hmemTaskQ
) return FALSE
;
882 msg
.message
= message
;
885 msg
.time
= GetTickCount();
889 return MSG_AddMsg( wndPtr
->hmemTaskQ
, &msg
, 0 );
892 /***********************************************************************
893 * PostAppMessage (USER.116)
895 BOOL
PostAppMessage( HTASK hTask
, WORD message
, WORD wParam
, LONG lParam
)
899 if (GetTaskQueue(hTask
) == 0) return FALSE
;
901 msg
.message
= message
;
904 msg
.time
= GetTickCount();
908 return MSG_AddMsg( GetTaskQueue(hTask
), &msg
, 0 );
912 /***********************************************************************
913 * SendMessage (USER.111)
915 LONG
SendMessage( HWND hwnd
, WORD msg
, WORD wParam
, LONG lParam
)
920 wndPtr
= WIN_FindWndPtr( hwnd
);
921 if (!wndPtr
) return 0;
923 /* Argh. This is inefficient. */
930 HANDLE msgh
= GlobalAlloc(0,sizeof(msgstruct
));
931 SEGPTR segmsg
= WIN16_GlobalLock(msgh
);
932 msgstruct
*Msg
= PTR_SEG_TO_LIN(segmsg
);
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
,
944 dprintf_msg( stddeb
,"SendMessage(%4.4x,%x,%x,%lx) -> %lx\n",
945 hwnd
, msg
, wParam
, lParam
, ret
);
951 /***********************************************************************
952 * WaitMessage (USER.112)
954 void WaitMessage( void )
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
) )
965 if ((queue
->status
& QS_TIMER
) &&
966 TIMER_CheckTimer( &nextExp
, &msg
, 0, FALSE
))
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" );
989 /***********************************************************************
990 * DispatchMessage (USER.114)
992 LONG
DispatchMessage( LPMSG msg
)
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
))
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",
1022 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
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
)
1070 dprintf_msg(stddeb
, "RegisterWindowMessage: '%s'\n", str
);
1071 wRet
= GlobalAddAtom( str
);
1076 /***********************************************************************
1077 * GetTickCount (USER.13)
1079 DWORD
GetTickCount(void)
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()