2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
11 #include <sys/types.h>
16 #include "sysmetrics.h"
26 /* #define DEBUG_MSG */
29 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
30 #define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK
32 #define HWND_BROADCAST16 ((HWND16)0xffff)
33 #define HWND_BROADCAST32 ((HWND32)0xffffffff)
35 #define ASCII_CHAR_HACK 0x0800
37 typedef enum { SYSQ_MSG_ABANDON
, SYSQ_MSG_SKIP
, SYSQ_MSG_ACCEPT
} SYSQ_STATUS
;
39 extern WPARAM lastEventChar
; /* event.c */
40 extern BOOL MouseButtonsStates
[3];
41 extern BOOL AsyncMouseButtonsStates
[3];
42 extern BYTE KeyStateTable
[256];
43 extern BYTE AsyncKeyStateTable
[256];
45 extern MESSAGEQUEUE
*pCursorQueue
; /* queue.c */
46 extern MESSAGEQUEUE
*pActiveQueue
;
48 DWORD MSG_WineStartTicks
; /* Ticks at Wine startup */
50 static WORD doubleClickSpeed
= 452;
51 static INT32 debugSMRL
= 0; /* intertask SendMessage() recursion level */
53 /***********************************************************************
54 * MSG_TranslateMouseMsg
56 * Translate an mouse hardware event into a real mouse message.
57 * Return value indicates whether the translated message must be passed
60 * - Find the window for this message.
61 * - Translate button-down messages in double-clicks.
62 * - Send the WM_NCHITTEST message to find where the cursor is.
63 * - Activate the window if needed.
64 * - Translate the message into a non-client message, or translate
65 * the coordinates to client coordinates.
66 * - Send the WM_SETCURSOR message.
68 static SYSQ_STATUS
MSG_TranslateMouseMsg( MSG16
*msg
, BOOL remove
)
73 MOUSEHOOKSTRUCT16
*hook
;
75 static DWORD lastClickTime
= 0;
76 static WORD lastClickMsg
= 0;
77 static POINT16 lastClickPos
= { 0, 0 };
79 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16(GetTaskQueue(0));
81 BOOL mouseClick
= ((msg
->message
== WM_LBUTTONDOWN
) ||
82 (msg
->message
== WM_RBUTTONDOWN
) ||
83 (msg
->message
== WM_MBUTTONDOWN
));
87 if ((msg
->hwnd
= GetCapture16()) != 0)
91 ScreenToClient16( msg
->hwnd
, &pt
);
92 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
93 /* No need to further process the message */
95 if (!HOOK_GetHook( WH_MOUSE
, GetTaskQueue(0)) ||
96 !(hook
= SEGPTR_NEW(MOUSEHOOKSTRUCT16
)))
97 return SYSQ_MSG_ACCEPT
;
99 hook
->hwnd
= msg
->hwnd
;
100 hook
->wHitTestCode
= HTCLIENT
;
101 hook
->dwExtraInfo
= 0;
102 ret
= !HOOK_CallHooks( WH_MOUSE
, remove
? HC_ACTION
: HC_NOREMOVE
,
103 msg
->message
, (LPARAM
)SEGPTR_GET(hook
));
105 return ret
? SYSQ_MSG_ACCEPT
: SYSQ_MSG_SKIP
;
108 hittest
= WINPOS_WindowFromPoint( msg
->pt
, &pWnd
);
109 if (pWnd
->hmemTaskQ
!= GetTaskQueue(0))
111 /* Not for the current task */
112 if (queue
) QUEUE_ClearWakeBit( queue
, QS_MOUSE
);
113 /* Wake up the other task */
114 queue
= (MESSAGEQUEUE
*)GlobalLock16( pWnd
->hmemTaskQ
);
115 if (queue
) QUEUE_SetWakeBit( queue
, QS_MOUSE
);
116 return SYSQ_MSG_ABANDON
;
118 pCursorQueue
= queue
;
119 msg
->hwnd
= pWnd
->hwndSelf
;
121 if ((hittest
!= HTERROR
) && mouseClick
)
123 HWND hwndTop
= WIN_GetTopParent( msg
->hwnd
);
125 /* Send the WM_PARENTNOTIFY message */
127 WIN_SendParentNotify( msg
->hwnd
, msg
->message
, 0,
128 MAKELPARAM( msg
->pt
.x
, msg
->pt
.y
) );
130 /* Activate the window if needed */
132 if (msg
->hwnd
!= GetActiveWindow() &&
133 msg
->hwnd
!= GetDesktopWindow16())
135 LONG ret
= SendMessage16( msg
->hwnd
, WM_MOUSEACTIVATE
, hwndTop
,
136 MAKELONG( hittest
, msg
->message
) );
138 if ((ret
== MA_ACTIVATEANDEAT
) || (ret
== MA_NOACTIVATEANDEAT
))
141 if (((ret
== MA_ACTIVATE
) || (ret
== MA_ACTIVATEANDEAT
))
142 && hwndTop
!= GetActiveWindow() )
143 WINPOS_SetActiveWindow( hwndTop
, TRUE
, TRUE
);
147 /* Send the WM_SETCURSOR message */
149 SendMessage16( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
150 MAKELONG( hittest
, msg
->message
));
151 if (eatMsg
) return SYSQ_MSG_SKIP
;
153 /* Check for double-click */
157 BOOL dbl_click
= FALSE
;
159 if ((msg
->message
== lastClickMsg
) &&
160 (msg
->time
- lastClickTime
< doubleClickSpeed
) &&
161 (abs(msg
->pt
.x
- lastClickPos
.x
) < SYSMETRICS_CXDOUBLECLK
/2) &&
162 (abs(msg
->pt
.y
- lastClickPos
.y
) < SYSMETRICS_CYDOUBLECLK
/2))
165 if (dbl_click
&& (hittest
== HTCLIENT
))
167 /* Check whether window wants the double click message. */
168 dbl_click
= (pWnd
->class->style
& CS_DBLCLKS
) != 0;
171 if (dbl_click
) switch(msg
->message
)
173 case WM_LBUTTONDOWN
: msg
->message
= WM_LBUTTONDBLCLK
; break;
174 case WM_RBUTTONDOWN
: msg
->message
= WM_RBUTTONDBLCLK
; break;
175 case WM_MBUTTONDOWN
: msg
->message
= WM_MBUTTONDBLCLK
; break;
180 lastClickTime
= msg
->time
;
181 lastClickMsg
= msg
->message
;
182 lastClickPos
= msg
->pt
;
186 /* Build the translated message */
188 if (hittest
== HTCLIENT
)
189 ScreenToClient16( msg
->hwnd
, &pt
);
192 msg
->wParam
= hittest
;
193 msg
->message
+= WM_NCLBUTTONDOWN
- WM_LBUTTONDOWN
;
195 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
197 /* Call the WH_MOUSE hook */
199 if (!HOOK_GetHook( WH_MOUSE
, GetTaskQueue(0)) ||
200 !(hook
= SEGPTR_NEW(MOUSEHOOKSTRUCT16
)))
201 return SYSQ_MSG_ACCEPT
;
204 hook
->hwnd
= msg
->hwnd
;
205 hook
->wHitTestCode
= hittest
;
206 hook
->dwExtraInfo
= 0;
207 ret
= !HOOK_CallHooks( WH_MOUSE
, remove
? HC_ACTION
: HC_NOREMOVE
,
208 msg
->message
, (LPARAM
)SEGPTR_GET(hook
) );
210 return ret
? SYSQ_MSG_ACCEPT
: SYSQ_MSG_SKIP
;
214 /***********************************************************************
215 * MSG_TranslateKeyboardMsg
217 * Translate an keyboard hardware event into a real message.
218 * Return value indicates whether the translated message must be passed
221 static SYSQ_STATUS
MSG_TranslateKeyboardMsg( MSG16
*msg
, BOOL remove
)
225 /* Should check Ctrl-Esc and PrintScreen here */
227 msg
->hwnd
= GetFocus16();
230 /* Send the message to the active window instead, */
231 /* translating messages to their WM_SYS equivalent */
233 msg
->hwnd
= GetActiveWindow();
235 if( msg
->message
< WM_SYSKEYDOWN
)
236 msg
->message
+= WM_SYSKEYDOWN
- WM_KEYDOWN
;
238 pWnd
= WIN_FindWndPtr( msg
->hwnd
);
239 if (pWnd
&& (pWnd
->hmemTaskQ
!= GetTaskQueue(0)))
241 /* Not for the current task */
242 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) );
243 if (queue
) QUEUE_ClearWakeBit( queue
, QS_KEY
);
244 /* Wake up the other task */
245 queue
= (MESSAGEQUEUE
*)GlobalLock16( pWnd
->hmemTaskQ
);
246 if (queue
) QUEUE_SetWakeBit( queue
, QS_KEY
);
247 return SYSQ_MSG_ABANDON
;
249 return (HOOK_CallHooks( WH_KEYBOARD
, remove
? HC_ACTION
: HC_NOREMOVE
,
250 msg
->wParam
, msg
->lParam
))
251 ? SYSQ_MSG_SKIP
: SYSQ_MSG_ACCEPT
;
255 /***********************************************************************
256 * MSG_JournalRecordMsg
258 * Build an EVENTMSG structure and call JOURNALRECORD hook
260 static void MSG_JournalRecordMsg( MSG16
*msg
)
262 EVENTMSG16
*event
= SEGPTR_NEW(EVENTMSG16
);
264 event
->message
= msg
->message
;
265 event
->time
= msg
->time
;
266 if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
268 event
->paramL
= (msg
->wParam
& 0xFF) | (HIWORD(msg
->lParam
) << 8);
269 event
->paramH
= msg
->lParam
& 0x7FFF;
270 if (HIWORD(msg
->lParam
) & 0x0100)
271 event
->paramH
|= 0x8000; /* special_key - bit */
272 HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0,
273 (LPARAM
)SEGPTR_GET(event
) );
275 else if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
277 event
->paramL
= LOWORD(msg
->lParam
); /* X pos */
278 event
->paramH
= HIWORD(msg
->lParam
); /* Y pos */
279 ClientToScreen16( msg
->hwnd
, (LPPOINT16
)&event
->paramL
);
280 HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0,
281 (LPARAM
)SEGPTR_GET(event
) );
283 else if ((msg
->message
>= WM_NCMOUSEFIRST
) &&
284 (msg
->message
<= WM_NCMOUSELAST
))
286 event
->paramL
= LOWORD(msg
->lParam
); /* X pos */
287 event
->paramH
= HIWORD(msg
->lParam
); /* Y pos */
288 event
->message
+= WM_MOUSEMOVE
-WM_NCMOUSEMOVE
;/* give no info about NC area */
289 HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0,
290 (LPARAM
)SEGPTR_GET(event
) );
295 /*****************************************************************
296 * MSG_JournalPlayBackIsAscii
298 static BOOL
MSG_JournalPlayBackIsAscii(WPARAM wParam
)
300 return ((wParam
>VK_HELP
&& wParam
<VK_F1
) ||
301 wParam
== VK_SPACE
||
302 wParam
== VK_ESCAPE
||
303 wParam
== VK_RETURN
||
309 /***********************************************************************
310 * MSG_JournalPlayBackMsg
312 * Get an EVENTMSG struct via call JOURNALPAYBACK hook function
314 static int MSG_JournalPlayBackMsg(void)
318 WORD keyDown
,i
,wParam
,result
=0;
320 if ( HOOK_GetHook(WH_JOURNALPLAYBACK
, 0) )
322 tmpMsg
= SEGPTR_NEW(EVENTMSG16
);
323 wtime
=HOOK_CallHooks( WH_JOURNALPLAYBACK
, HC_GETNEXT
, 0, (LPARAM
)SEGPTR_GET(tmpMsg
));
324 /* dprintf_msg(stddeb,"Playback wait time =%ld\n",wtime); */
328 if ((tmpMsg
->message
>= WM_KEYFIRST
) && (tmpMsg
->message
<= WM_KEYLAST
))
330 wParam
=tmpMsg
->paramL
& 0xFF;
331 lParam
=MAKELONG(tmpMsg
->paramH
&0x7ffff,tmpMsg
->paramL
>>8);
332 if (tmpMsg
->message
== WM_KEYDOWN
|| tmpMsg
->message
== WM_SYSKEYDOWN
)
334 for (keyDown
=i
=0; i
<256 && !keyDown
; i
++)
335 if (KeyStateTable
[i
] & 0x80)
338 lParam
|= 0x40000000;
339 AsyncKeyStateTable
[wParam
]=KeyStateTable
[wParam
] |= 0x80;
340 if (MSG_JournalPlayBackIsAscii(wParam
))
342 lastEventChar
= wParam
; /* control TranslateMessage() */
343 lParam
|= (LONG
)((LONG
)ASCII_CHAR_HACK
*0x10000L
);
345 if (!(KeyStateTable
[VK_SHIFT
] & 0x80) &&
346 !(KeyStateTable
[VK_CAPITAL
] & 0x80))
347 lastEventChar
= tolower(lastEventChar
);
348 if (KeyStateTable
[VK_CONTROL
] & 0x80)
352 else /* WM_KEYUP, WM_SYSKEYUP */
354 lParam
|= 0xC0000000;
355 AsyncKeyStateTable
[wParam
]=KeyStateTable
[wParam
] &= ~0x80;
357 if (KeyStateTable
[VK_MENU
] & 0x80)
358 lParam
|= 0x20000000;
359 if (tmpMsg
->paramH
& 0x8000) /*special_key bit*/
360 lParam
|= 0x01000000;
361 hardware_event( tmpMsg
->message
, wParam
, lParam
,0, 0, tmpMsg
->time
, 0 );
365 if ((tmpMsg
->message
>= WM_MOUSEFIRST
) && (tmpMsg
->message
<= WM_MOUSELAST
))
367 switch (tmpMsg
->message
)
369 case WM_LBUTTONDOWN
:MouseButtonsStates
[0]=AsyncMouseButtonsStates
[0]=1;break;
370 case WM_LBUTTONUP
: MouseButtonsStates
[0]=AsyncMouseButtonsStates
[0]=0;break;
371 case WM_MBUTTONDOWN
:MouseButtonsStates
[1]=AsyncMouseButtonsStates
[1]=1;break;
372 case WM_MBUTTONUP
: MouseButtonsStates
[1]=AsyncMouseButtonsStates
[1]=0;break;
373 case WM_RBUTTONDOWN
:MouseButtonsStates
[2]=AsyncMouseButtonsStates
[2]=1;break;
374 case WM_RBUTTONUP
: MouseButtonsStates
[2]=AsyncMouseButtonsStates
[2]=0;break;
376 AsyncKeyStateTable
[VK_LBUTTON
]= KeyStateTable
[VK_LBUTTON
] = MouseButtonsStates
[0] << 8;
377 AsyncKeyStateTable
[VK_MBUTTON
]= KeyStateTable
[VK_MBUTTON
] = MouseButtonsStates
[1] << 8;
378 AsyncKeyStateTable
[VK_RBUTTON
]= KeyStateTable
[VK_RBUTTON
] = MouseButtonsStates
[2] << 8;
379 SetCursorPos(tmpMsg
->paramL
,tmpMsg
->paramH
);
380 lParam
=MAKELONG(tmpMsg
->paramL
,tmpMsg
->paramH
);
382 if (MouseButtonsStates
[0]) wParam
|= MK_LBUTTON
;
383 if (MouseButtonsStates
[1]) wParam
|= MK_MBUTTON
;
384 if (MouseButtonsStates
[2]) wParam
|= MK_RBUTTON
;
385 hardware_event( tmpMsg
->message
, wParam
, lParam
,
386 tmpMsg
->paramL
, tmpMsg
->paramH
, tmpMsg
->time
, 0 );
389 HOOK_CallHooks( WH_JOURNALPLAYBACK
, HC_SKIP
, 0, (LPARAM
)SEGPTR_GET(tmpMsg
));
392 result
= QS_MOUSE
| QS_KEY
;
398 /***********************************************************************
399 * MSG_PeekHardwareMsg
401 * Peek for a hardware message matching the hwnd and message filters.
403 static BOOL
MSG_PeekHardwareMsg( MSG16
*msg
, HWND hwnd
, WORD first
, WORD last
,
407 MESSAGEQUEUE
*sysMsgQueue
= QUEUE_GetSysQueue();
408 int i
, pos
= sysMsgQueue
->nextMessage
;
410 /* If the queue is empty, attempt to fill it */
411 if (!sysMsgQueue
->msgCount
&& XPending(display
))
412 EVENT_WaitXEvent( FALSE
, FALSE
);
414 for (i
= 0; i
< sysMsgQueue
->msgCount
; i
++, pos
++)
416 if (pos
>= sysMsgQueue
->queueSize
) pos
= 0;
417 *msg
= sysMsgQueue
->messages
[pos
].msg
;
419 /* Translate message; return FALSE immediately on SYSQ_MSG_ABANDON */
421 if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
423 if ((status
= MSG_TranslateMouseMsg(msg
,remove
)) == SYSQ_MSG_ABANDON
)
426 else if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
428 if ((status
= MSG_TranslateKeyboardMsg(msg
,remove
)) == SYSQ_MSG_ABANDON
)
431 else /* Non-standard hardware event */
433 HARDWAREHOOKSTRUCT16
*hook
;
434 if ((hook
= SEGPTR_NEW(HARDWAREHOOKSTRUCT16
)))
437 hook
->hWnd
= msg
->hwnd
;
438 hook
->wMessage
= msg
->message
;
439 hook
->wParam
= msg
->wParam
;
440 hook
->lParam
= msg
->lParam
;
441 ret
= HOOK_CallHooks( WH_HARDWARE
,
442 remove
? HC_ACTION
: HC_NOREMOVE
,
443 0, (LPARAM
)SEGPTR_GET(hook
) );
445 status
= ret
? SYSQ_MSG_SKIP
: SYSQ_MSG_ACCEPT
;
449 if (status
== SYSQ_MSG_SKIP
)
451 if (remove
) QUEUE_RemoveMsg( sysMsgQueue
, pos
);
452 /* FIXME: call CBT_CLICKSKIPPED from here */
456 /* Check message against filters */
458 if (hwnd
&& (msg
->hwnd
!= hwnd
)) continue;
459 if ((first
|| last
) &&
460 ((msg
->message
< first
) || (msg
->message
> last
))) continue;
463 if (HOOK_GetHook( WH_JOURNALRECORD
, GetTaskQueue(0) ))
464 MSG_JournalRecordMsg( msg
);
465 QUEUE_RemoveMsg( sysMsgQueue
, pos
);
473 /**********************************************************************
474 * SetDoubleClickTime (USER.20)
476 void SetDoubleClickTime( WORD interval
)
478 doubleClickSpeed
= interval
? interval
: 500;
482 /**********************************************************************
483 * GetDoubleClickTime (USER.21)
485 WORD
GetDoubleClickTime()
487 return doubleClickSpeed
;
491 /***********************************************************************
494 * Implementation of an inter-task SendMessage.
496 static LRESULT
MSG_SendMessage( HQUEUE16 hDestQueue
, HWND hwnd
, UINT msg
,
497 WPARAM wParam
, LPARAM lParam
)
499 INT32 prevSMRL
= debugSMRL
;
500 QSMCTRL qCtrl
= { 0, 1};
501 MESSAGEQUEUE
*queue
, *destQ
;
503 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
504 if (!(destQ
= (MESSAGEQUEUE
*)GlobalLock16( hDestQueue
))) return 0;
506 if (IsTaskLocked() || !IsWindow(hwnd
)) return 0;
509 dprintf_sendmsg(stddeb
,"%*sSM: %s [%04x] (%04x -> %04x)\n",
510 prevSMRL
, "", SPY_GetMsgName(msg
), msg
, queue
->self
, hDestQueue
);
512 if( !(queue
->wakeBits
& QS_SMPARAMSFREE
) )
514 dprintf_sendmsg(stddeb
,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
515 queue
->changeBits
&= ~QS_SMPARAMSFREE
;
516 QUEUE_WaitBits( QS_SMPARAMSFREE
);
523 queue
->wParam
= wParam
;
524 queue
->lParam
= lParam
;
525 queue
->hPrevSendingTask
= destQ
->hSendingTask
;
526 destQ
->hSendingTask
= GetTaskQueue(0);
528 queue
->wakeBits
&= ~QS_SMPARAMSFREE
;
530 dprintf_sendmsg(stddeb
,"%*ssm: smResultInit = %08x\n", prevSMRL
, "", (unsigned)&qCtrl
);
532 queue
->smResultInit
= &qCtrl
;
534 QUEUE_SetWakeBit( destQ
, QS_SENDMESSAGE
);
536 /* perform task switch and wait for the result */
538 while( qCtrl
.bPending
)
540 if (!(queue
->wakeBits
& QS_SMRESULT
))
542 queue
->changeBits
&= ~QS_SMRESULT
;
543 DirectedYield( destQ
->hTask
);
544 QUEUE_WaitBits( QS_SMRESULT
);
545 dprintf_sendmsg(stddeb
,"\tsm: have result!\n");
549 dprintf_sendmsg(stddeb
,"%*ssm: smResult = %08x\n", prevSMRL
, "", (unsigned)queue
->smResult
);
551 queue
->smResult
->lResult
= queue
->SendMessageReturn
;
552 queue
->smResult
->bPending
= FALSE
;
553 queue
->wakeBits
&= ~QS_SMRESULT
;
555 if( queue
->smResult
!= &qCtrl
)
556 dprintf_msg(stddeb
,"%*ssm: weird scenes inside the goldmine!\n", prevSMRL
, "");
558 queue
->smResultInit
= NULL
;
560 dprintf_sendmsg(stddeb
,"%*sSM: [%04x] returning %08lx\n", prevSMRL
, "", msg
, qCtrl
.lResult
);
563 return qCtrl
.lResult
;
567 /***********************************************************************
568 * ReplyMessage (USER.115)
570 void ReplyMessage( LRESULT result
)
572 MESSAGEQUEUE
*senderQ
;
575 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return;
577 dprintf_msg(stddeb
,"ReplyMessage, queue %04x\n", queue
->self
);
579 while( (senderQ
= (MESSAGEQUEUE
*)GlobalLock16( queue
->InSendMessageHandle
)))
581 dprintf_msg(stddeb
,"\trpm: replying to %04x (%04x -> %04x)\n",
582 queue
->msg
, queue
->self
, senderQ
->self
);
584 if( queue
->wakeBits
& QS_SENDMESSAGE
)
586 QUEUE_ReceiveMessage( queue
);
587 continue; /* ReceiveMessage() already called us */
590 if(!(senderQ
->wakeBits
& QS_SMRESULT
) ) break;
593 if( !senderQ
) { dprintf_msg(stddeb
,"\trpm: done\n"); return; }
595 senderQ
->SendMessageReturn
= result
;
596 dprintf_msg(stddeb
,"\trpm: smResult = %08x, result = %08lx\n",
597 (unsigned)queue
->smResultCurrent
, result
);
599 senderQ
->smResult
= queue
->smResultCurrent
;
600 queue
->InSendMessageHandle
= 0;
602 QUEUE_SetWakeBit( senderQ
, QS_SMRESULT
);
603 DirectedYield( queue
->hSendingTask
);
607 /***********************************************************************
610 static BOOL
MSG_PeekMessage( LPMSG16 msg
, HWND hwnd
, WORD first
, WORD last
,
611 WORD flags
, BOOL peek
)
614 MESSAGEQUEUE
*msgQueue
;
618 DDE_TestDDE(hwnd
); /* do we have dde handling in the window ?*/
619 DDE_GetRemoteMessage();
620 #endif /* CONFIG_IPC */
622 mask
= QS_POSTMESSAGE
| QS_SENDMESSAGE
; /* Always selected */
625 /* MSWord gets stuck if we do not check for nonclient mouse messages */
627 if ((first
<= WM_KEYLAST
) && (last
>= WM_KEYFIRST
)) mask
|= QS_KEY
;
628 if ( ((first
<= WM_MOUSELAST
) && (last
>= WM_MOUSEFIRST
)) ||
629 ((first
<= WM_NCMOUSELAST
) && (last
>= WM_NCMOUSEFIRST
)) ) mask
|= QS_MOUSE
;
630 if ((first
<= WM_TIMER
) && (last
>= WM_TIMER
)) mask
|= QS_TIMER
;
631 if ((first
<= WM_SYSTIMER
) && (last
>= WM_SYSTIMER
)) mask
|= QS_TIMER
;
632 if ((first
<= WM_PAINT
) && (last
>= WM_PAINT
)) mask
|= QS_PAINT
;
634 else mask
|= QS_MOUSE
| QS_KEY
| QS_TIMER
| QS_PAINT
;
636 if (IsTaskLocked()) flags
|= PM_NOYIELD
;
640 hQueue
= GetTaskQueue(0);
641 msgQueue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
642 if (!msgQueue
) return FALSE
;
643 msgQueue
->changeBits
= 0;
645 /* First handle a message put by SendMessage() */
647 if (msgQueue
->wakeBits
& QS_SENDMESSAGE
)
648 QUEUE_ReceiveMessage( msgQueue
);
650 /* Now handle a WM_QUIT message
652 * FIXME: PostQuitMessage() should post WM_QUIT and
653 * set QS_POSTMESSAGE wakebit instead of this.
656 if (msgQueue
->wPostQMsg
&&
657 (!first
|| WM_QUIT
>= first
) &&
658 (!last
|| WM_QUIT
<= last
) )
661 msg
->message
= WM_QUIT
;
662 msg
->wParam
= msgQueue
->wExitCode
;
667 /* Now find a normal message */
669 if (((msgQueue
->wakeBits
& mask
) & QS_POSTMESSAGE
) &&
670 ((pos
= QUEUE_FindMsg( msgQueue
, hwnd
, first
, last
)) != -1))
672 QMSG
*qmsg
= &msgQueue
->messages
[pos
];
674 msgQueue
->GetMessageTimeVal
= msg
->time
;
675 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
676 msgQueue
->GetMessageExtraInfoVal
= qmsg
->extraInfo
;
678 if (flags
& PM_REMOVE
) QUEUE_RemoveMsg( msgQueue
, pos
);
682 msgQueue
->changeBits
|= MSG_JournalPlayBackMsg();
684 /* Now find a hardware event */
686 if (((msgQueue
->wakeBits
& mask
) & (QS_MOUSE
| QS_KEY
)) &&
687 MSG_PeekHardwareMsg( msg
, hwnd
, first
, last
, flags
& PM_REMOVE
))
690 msgQueue
->GetMessageTimeVal
= msg
->time
;
691 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
692 msgQueue
->GetMessageExtraInfoVal
= 0; /* Always 0 for now */
696 /* Check again for SendMessage */
698 if (msgQueue
->wakeBits
& QS_SENDMESSAGE
)
699 QUEUE_ReceiveMessage( msgQueue
);
701 /* Now find a WM_PAINT message */
703 if ((msgQueue
->wakeBits
& mask
) & QS_PAINT
)
706 msg
->hwnd
= WIN_FindWinToRepaint( hwnd
, hQueue
);
707 msg
->message
= WM_PAINT
;
711 if ((wndPtr
= WIN_FindWndPtr(msg
->hwnd
)))
713 if( wndPtr
->dwStyle
& WS_MINIMIZE
&&
714 wndPtr
->class->hIcon
)
716 msg
->message
= WM_PAINTICON
;
720 if( !hwnd
|| msg
->hwnd
== hwnd
|| IsChild(hwnd
,msg
->hwnd
) )
722 if( wndPtr
->flags
& WIN_INTERNAL_PAINT
&& !wndPtr
->hrgnUpdate
)
724 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
725 QUEUE_DecPaintCount( hQueue
);
732 /* Check for timer messages, but yield first */
734 if (!(flags
& PM_NOYIELD
))
737 if (msgQueue
->wakeBits
& QS_SENDMESSAGE
)
738 QUEUE_ReceiveMessage( msgQueue
);
740 if ((msgQueue
->wakeBits
& mask
) & QS_TIMER
)
742 if (TIMER_GetTimerMsg(msg
, hwnd
, hQueue
, flags
& PM_REMOVE
)) break;
747 if (!(flags
& PM_NOYIELD
)) UserYield();
750 msgQueue
->wakeMask
= mask
;
751 QUEUE_WaitBits( mask
);
754 /* We got a message */
755 if (peek
) return TRUE
;
756 else return (msg
->message
!= WM_QUIT
);
760 /***********************************************************************
761 * MSG_InternalGetMessage
763 * GetMessage() function for internal use. Behave like GetMessage(),
764 * but also call message filters and optionally send WM_ENTERIDLE messages.
765 * 'hwnd' must be the handle of the dialog or menu window.
766 * 'code' is the message filter value (MSGF_??? codes).
768 BOOL32
MSG_InternalGetMessage( MSG16
*msg
, HWND32 hwnd
, HWND32 hwndOwner
,
769 WPARAM32 code
, WORD flags
, BOOL32 sendIdle
)
775 if (!MSG_PeekMessage( msg
, 0, 0, 0, flags
, TRUE
))
777 /* No message present -> send ENTERIDLE and wait */
778 if (IsWindow(hwndOwner
))
779 SendMessage16( hwndOwner
, WM_ENTERIDLE
,
780 code
, (LPARAM
)hwnd
);
781 MSG_PeekMessage( msg
, 0, 0, 0, flags
, FALSE
);
784 else /* Always wait for a message */
785 MSG_PeekMessage( msg
, 0, 0, 0, flags
, FALSE
);
787 /* Call message filters */
789 if (HOOK_GetHook( WH_SYSMSGFILTER
, GetTaskQueue(0) ) ||
790 HOOK_GetHook( WH_MSGFILTER
, GetTaskQueue(0) ))
792 MSG16
*pmsg
= SEGPTR_NEW(MSG16
);
797 ret
= ((BOOL16
)HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0,
798 (LPARAM
)SEGPTR_GET(pmsg
) ) ||
799 (BOOL16
)HOOK_CallHooks( WH_MSGFILTER
, code
, 0,
800 (LPARAM
)SEGPTR_GET(pmsg
) ));
804 /* Message filtered -> remove it from the queue */
805 /* if it's still there. */
806 if (!(flags
& PM_REMOVE
))
807 MSG_PeekMessage( msg
, 0, 0, 0, PM_REMOVE
, TRUE
);
813 return (msg
->message
!= WM_QUIT
);
818 /***********************************************************************
819 * PeekMessage16 (USER.109)
821 BOOL16
PeekMessage16( LPMSG16 msg
, HWND16 hwnd
, UINT16 first
,
822 UINT16 last
, UINT16 flags
)
824 return MSG_PeekMessage( msg
, hwnd
, first
, last
, flags
, TRUE
);
828 /***********************************************************************
829 * GetMessage (USER.108)
831 BOOL
GetMessage( SEGPTR msg
, HWND hwnd
, UINT first
, UINT last
)
833 MSG16
*lpmsg
= (MSG16
*)PTR_SEG_TO_LIN(msg
);
834 MSG_PeekMessage( lpmsg
,
835 hwnd
, first
, last
, PM_REMOVE
, FALSE
);
837 dprintf_msg(stddeb
,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg
->message
,
839 HOOK_CallHooks( WH_GETMESSAGE
, HC_ACTION
, 0, (LPARAM
)msg
);
840 return (lpmsg
->message
!= WM_QUIT
);
844 /***********************************************************************
845 * PostMessage (USER.110)
847 BOOL
PostMessage( HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
853 msg
.message
= message
;
856 msg
.time
= GetTickCount();
861 if (DDE_PostMessage(&msg
))
863 #endif /* CONFIG_IPC */
865 if (hwnd
== HWND_BROADCAST16
)
867 dprintf_msg(stddeb
,"PostMessage // HWND_BROADCAST !\n");
868 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
870 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
872 dprintf_msg(stddeb
,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
873 wndPtr
->hwndSelf
, message
, wParam
, lParam
);
874 PostMessage( wndPtr
->hwndSelf
, message
, wParam
, lParam
);
877 dprintf_msg(stddeb
,"PostMessage // End of HWND_BROADCAST !\n");
881 wndPtr
= WIN_FindWndPtr( hwnd
);
882 if (!wndPtr
|| !wndPtr
->hmemTaskQ
) return FALSE
;
884 return QUEUE_AddMsg( wndPtr
->hmemTaskQ
, &msg
, 0 );
887 /***********************************************************************
888 * PostAppMessage (USER.116)
890 BOOL
PostAppMessage( HTASK hTask
, WORD message
, WORD wParam
, LONG lParam
)
894 if (GetTaskQueue(hTask
) == 0) return FALSE
;
896 msg
.message
= message
;
899 msg
.time
= GetTickCount();
903 return QUEUE_AddMsg( GetTaskQueue(hTask
), &msg
, 0 );
907 /***********************************************************************
908 * SendMessage16 (USER.111)
910 LRESULT
SendMessage16( HWND16 hwnd
, UINT16 msg
, WPARAM16 wParam
, LPARAM lParam
)
916 MSG16 DDE_msg
= { hwnd
, msg
, wParam
, lParam
};
917 if (DDE_SendMessage(&DDE_msg
)) return TRUE
;
918 #endif /* CONFIG_IPC */
920 if (hwnd
== HWND_BROADCAST16
)
922 dprintf_msg(stddeb
,"SendMessage // HWND_BROADCAST !\n");
923 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
925 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
927 dprintf_msg(stddeb
,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
928 wndPtr
->hwndSelf
, msg
, (DWORD
)wParam
, lParam
);
929 SendMessage16( wndPtr
->hwndSelf
, msg
, wParam
, lParam
);
932 dprintf_msg(stddeb
,"SendMessage // End of HWND_BROADCAST !\n");
936 if (HOOK_GetHook( WH_CALLWNDPROC
, GetTaskQueue(0) ))
946 if ((pmsg
= SEGPTR_NEW(struct msgstruct
)))
950 pmsg
->wParam
= wParam
;
951 pmsg
->lParam
= lParam
;
952 HOOK_CallHooks( WH_CALLWNDPROC
, HC_ACTION
, 1,
953 (LPARAM
)SEGPTR_GET(pmsg
) );
956 wParam
= pmsg
->wParam
;
957 lParam
= pmsg
->lParam
;
961 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
963 fprintf( stderr
, "SendMessage16: invalid hwnd %04x\n", hwnd
);
966 if (QUEUE_IsDoomedQueue(wndPtr
->hmemTaskQ
))
967 return 0; /* Don't send anything if the task is dying */
968 if (wndPtr
->hmemTaskQ
!= GetTaskQueue(0))
969 return MSG_SendMessage( wndPtr
->hmemTaskQ
, hwnd
, msg
, wParam
, lParam
);
971 SPY_EnterMessage( SPY_SENDMESSAGE16
, hwnd
, msg
, wParam
, lParam
);
972 ret
= CallWindowProc16( (WNDPROC16
)wndPtr
->winproc
,
973 hwnd
, msg
, wParam
, lParam
);
974 SPY_ExitMessage( SPY_RESULT_OK16
, hwnd
, msg
, ret
);
979 /***********************************************************************
980 * SendMessage32A (USER32.453)
982 LRESULT
SendMessage32A(HWND32 hwnd
, UINT32 msg
, WPARAM32 wParam
, LPARAM lParam
)
987 if (hwnd
== HWND_BROADCAST32
)
989 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
991 /* FIXME: should use something like EnumWindows here */
992 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
993 SendMessage32A( wndPtr
->hwndSelf
, msg
, wParam
, lParam
);
998 /* FIXME: call hooks */
1000 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
1002 fprintf( stderr
, "SendMessage32A: invalid hwnd %08x\n", hwnd
);
1006 if (WINPROC_GetProcType( wndPtr
->winproc
) == WIN_PROC_16
)
1008 /* Use SendMessage16 for now to get hooks right */
1011 if (WINPROC_MapMsg32ATo16( msg
, wParam
, &msg16
, &wParam16
, &lParam
) == -1)
1013 ret
= SendMessage16( hwnd
, msg16
, wParam16
, lParam
);
1014 WINPROC_UnmapMsg32ATo16( msg16
, wParam16
, lParam
);
1018 if (QUEUE_IsDoomedQueue(wndPtr
->hmemTaskQ
))
1019 return 0; /* Don't send anything if the task is dying */
1021 if (wndPtr
->hmemTaskQ
!= GetTaskQueue(0))
1023 fprintf( stderr
, "SendMessage32A: intertask message not supported\n" );
1027 SPY_EnterMessage( SPY_SENDMESSAGE32
, hwnd
, msg
, wParam
, lParam
);
1028 ret
= CallWindowProc32A( (WNDPROC32
)wndPtr
->winproc
,
1029 hwnd
, msg
, wParam
, lParam
);
1030 SPY_ExitMessage( SPY_RESULT_OK32
, hwnd
, msg
, ret
);
1035 /***********************************************************************
1036 * SendMessage32W (USER32.458)
1038 LRESULT
SendMessage32W(HWND32 hwnd
, UINT32 msg
, WPARAM32 wParam
, LPARAM lParam
)
1043 if (hwnd
== HWND_BROADCAST32
)
1045 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
1047 /* FIXME: should use something like EnumWindows here */
1048 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
1049 SendMessage32W( wndPtr
->hwndSelf
, msg
, wParam
, lParam
);
1054 /* FIXME: call hooks */
1056 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
1058 fprintf( stderr
, "SendMessage32W: invalid hwnd %08x\n", hwnd
);
1061 if (QUEUE_IsDoomedQueue(wndPtr
->hmemTaskQ
))
1062 return 0; /* Don't send anything if the task is dying */
1063 if (wndPtr
->hmemTaskQ
!= GetTaskQueue(0))
1065 fprintf( stderr
, "SendMessage32W: intertask message not supported\n" );
1069 SPY_EnterMessage( SPY_SENDMESSAGE32
, hwnd
, msg
, wParam
, lParam
);
1070 ret
= CallWindowProc32W( (WNDPROC32
)wndPtr
->winproc
,
1071 hwnd
, msg
, wParam
, lParam
);
1072 SPY_ExitMessage( SPY_RESULT_OK32
, hwnd
, msg
, ret
);
1077 /***********************************************************************
1078 * WaitMessage (USER.112)
1080 void WaitMessage( void )
1082 QUEUE_WaitBits( QS_ALLINPUT
);
1086 /***********************************************************************
1087 * TranslateMessage (USER.113)
1089 * This should call ToAscii but it is currently broken
1093 BOOL
TranslateMessage( LPMSG16 msg
)
1095 UINT message
= msg
->message
;
1096 /* BYTE wparam[2]; */
1098 if ((message
== WM_KEYDOWN
) || (message
== WM_KEYUP
) ||
1099 (message
== WM_SYSKEYDOWN
) || (message
== WM_SYSKEYUP
))
1101 dprintf_msg(stddeb
, "Translating key %04x, scancode %04x\n", msg
->wParam
,
1102 HIWORD(msg
->lParam
) );
1104 if( HIWORD(msg
->lParam
) & ASCII_CHAR_HACK
)
1106 /* if( ToAscii( msg->wParam, HIWORD(msg->lParam), (LPSTR)&KeyStateTable,
1110 message
+= 2 - (message
& 0x0001);
1112 PostMessage( msg
->hwnd
, message
, lastEventChar
, msg
->lParam
);
1121 /***********************************************************************
1122 * DispatchMessage (USER.114)
1124 LONG
DispatchMessage( const MSG16
* msg
)
1130 /* Process timer messages */
1131 if ((msg
->message
== WM_TIMER
) || (msg
->message
== WM_SYSTIMER
))
1135 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1136 return CallWindowProc16( (WNDPROC16
)msg
->lParam
, msg
->hwnd
,
1137 msg
->message
, msg
->wParam
, GetTickCount() );
1141 if (!msg
->hwnd
) return 0;
1142 if (!(wndPtr
= WIN_FindWndPtr( msg
->hwnd
))) return 0;
1143 if (!wndPtr
->winproc
) return 0;
1144 painting
= (msg
->message
== WM_PAINT
);
1145 if (painting
) wndPtr
->flags
|= WIN_NEEDS_BEGINPAINT
;
1146 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1148 SPY_EnterMessage( SPY_DISPATCHMESSAGE16
, msg
->hwnd
, msg
->message
,
1149 msg
->wParam
, msg
->lParam
);
1150 retval
= CallWindowProc16( (WNDPROC16
)wndPtr
->winproc
,
1151 msg
->hwnd
, msg
->message
,
1152 msg
->wParam
, msg
->lParam
);
1153 SPY_ExitMessage( SPY_RESULT_OK16
, msg
->hwnd
, msg
->message
, retval
);
1155 if (painting
&& (wndPtr
= WIN_FindWndPtr( msg
->hwnd
)) &&
1156 (wndPtr
->flags
& WIN_NEEDS_BEGINPAINT
) && wndPtr
->hrgnUpdate
)
1158 fprintf(stderr
, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1160 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
1161 /* Validate the update region to avoid infinite WM_PAINT loop */
1162 ValidateRect32( msg
->hwnd
, NULL
);
1168 /***********************************************************************
1169 * RegisterWindowMessage16 (USER.118)
1171 WORD
RegisterWindowMessage16( SEGPTR str
)
1173 dprintf_msg(stddeb
, "RegisterWindowMessage16: %08lx\n", (DWORD
)str
);
1174 return GlobalAddAtom16( str
);
1178 /***********************************************************************
1179 * RegisterWindowMessage32A (USER32.436)
1181 WORD
RegisterWindowMessage32A( LPCSTR str
)
1183 dprintf_msg(stddeb
, "RegisterWindowMessage32A: %s\n", str
);
1184 return GlobalAddAtom32A( str
);
1188 /***********************************************************************
1189 * RegisterWindowMessage32W (USER32.437)
1191 WORD
RegisterWindowMessage32W( LPCWSTR str
)
1193 dprintf_msg(stddeb
, "RegisterWindowMessage32W: %p\n", str
);
1194 return GlobalAddAtom32W( str
);
1198 /***********************************************************************
1199 * GetTickCount (USER.13) (KERNEL32.299)
1201 DWORD
GetTickCount(void)
1204 gettimeofday( &t
, NULL
);
1205 return ((t
.tv_sec
* 1000) + (t
.tv_usec
/ 1000)) - MSG_WineStartTicks
;
1209 /***********************************************************************
1210 * GetCurrentTime (USER.15)
1212 * (effectively identical to GetTickCount)
1214 DWORD
GetCurrentTime(void)
1216 return GetTickCount();
1220 /***********************************************************************
1221 * InSendMessage (USER.192)
1223 BOOL
InSendMessage()
1225 MESSAGEQUEUE
*queue
;
1227 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) )))
1229 return (BOOL
)queue
->InSendMessageHandle
;