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 extern WPARAM lastEventChar
; /* event.c */
38 extern BOOL MouseButtonsStates
[3];
39 extern BOOL AsyncMouseButtonsStates
[3];
40 extern BYTE KeyStateTable
[256];
41 extern BYTE AsyncKeyStateTable
[256];
43 DWORD MSG_WineStartTicks
; /* Ticks at Wine startup */
45 static WORD doubleClickSpeed
= 452;
47 /***********************************************************************
48 * MSG_TranslateMouseMsg
50 * Translate an mouse hardware event into a real mouse message.
51 * Return value indicates whether the translated message must be passed
54 * - Find the window for this message.
55 * - Translate button-down messages in double-clicks.
56 * - Send the WM_NCHITTEST message to find where the cursor is.
57 * - Activate the window if needed.
58 * - Translate the message into a non-client message, or translate
59 * the coordinates to client coordinates.
60 * - Send the WM_SETCURSOR message.
62 static BOOL
MSG_TranslateMouseMsg( MSG16
*msg
, BOOL remove
)
67 MOUSEHOOKSTRUCT16
*hook
;
69 static DWORD lastClickTime
= 0;
70 static WORD lastClickMsg
= 0;
71 static POINT16 lastClickPos
= { 0, 0 };
74 BOOL mouseClick
= ((msg
->message
== WM_LBUTTONDOWN
) ||
75 (msg
->message
== WM_RBUTTONDOWN
) ||
76 (msg
->message
== WM_MBUTTONDOWN
));
80 if ((msg
->hwnd
= GetCapture()) != 0)
84 ScreenToClient16( msg
->hwnd
, &pt
);
85 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
86 /* No need to further process the message */
88 if (!HOOK_GetHook( WH_MOUSE
, GetTaskQueue(0)) ||
89 !(hook
= SEGPTR_NEW(MOUSEHOOKSTRUCT16
)))
92 hook
->hwnd
= msg
->hwnd
;
93 hook
->wHitTestCode
= HTCLIENT
;
94 hook
->dwExtraInfo
= 0;
95 ret
= !HOOK_CallHooks( WH_MOUSE
, remove
? HC_ACTION
: HC_NOREMOVE
,
96 msg
->message
, (LPARAM
)SEGPTR_GET(hook
));
101 hittest
= WINPOS_WindowFromPoint( msg
->pt
, &pWnd
);
102 if (pWnd
->hmemTaskQ
!= GetTaskQueue(0))
104 /* Not for the current task */
105 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) );
106 if (queue
) QUEUE_ClearWakeBit( queue
, QS_MOUSE
);
107 /* Wake up the other task */
108 queue
= (MESSAGEQUEUE
*)GlobalLock16( pWnd
->hmemTaskQ
);
109 if (queue
) QUEUE_SetWakeBit( queue
, QS_MOUSE
);
112 msg
->hwnd
= pWnd
->hwndSelf
;
113 if ((hittest
!= HTERROR
) && mouseClick
)
115 HWND hwndTop
= WIN_GetTopParent( msg
->hwnd
);
117 /* Send the WM_PARENTNOTIFY message */
119 WIN_SendParentNotify( msg
->hwnd
, msg
->message
, 0,
120 MAKELPARAM( msg
->pt
.x
, msg
->pt
.y
) );
122 /* Activate the window if needed */
124 if (msg
->hwnd
!= GetActiveWindow() && msg
->hwnd
!= GetDesktopWindow())
126 LONG ret
= SendMessage16( msg
->hwnd
, WM_MOUSEACTIVATE
, hwndTop
,
127 MAKELONG( hittest
, msg
->message
) );
129 if ((ret
== MA_ACTIVATEANDEAT
) || (ret
== MA_NOACTIVATEANDEAT
))
132 if (((ret
== MA_ACTIVATE
) || (ret
== MA_ACTIVATEANDEAT
))
133 && hwndTop
!= GetActiveWindow() )
134 WINPOS_SetActiveWindow( hwndTop
, TRUE
, TRUE
);
138 /* Send the WM_SETCURSOR message */
140 SendMessage16( msg
->hwnd
, WM_SETCURSOR
, (WPARAM
)msg
->hwnd
,
141 MAKELONG( hittest
, msg
->message
));
142 if (eatMsg
) return FALSE
;
144 /* Check for double-click */
148 BOOL dbl_click
= FALSE
;
150 if ((msg
->message
== lastClickMsg
) &&
151 (msg
->time
- lastClickTime
< doubleClickSpeed
) &&
152 (abs(msg
->pt
.x
- lastClickPos
.x
) < SYSMETRICS_CXDOUBLECLK
/2) &&
153 (abs(msg
->pt
.y
- lastClickPos
.y
) < SYSMETRICS_CYDOUBLECLK
/2))
156 if (dbl_click
&& (hittest
== HTCLIENT
))
158 /* Check whether window wants the double click message. */
159 dbl_click
= (pWnd
->class->style
& CS_DBLCLKS
) != 0;
162 if (dbl_click
) switch(msg
->message
)
164 case WM_LBUTTONDOWN
: msg
->message
= WM_LBUTTONDBLCLK
; break;
165 case WM_RBUTTONDOWN
: msg
->message
= WM_RBUTTONDBLCLK
; break;
166 case WM_MBUTTONDOWN
: msg
->message
= WM_MBUTTONDBLCLK
; break;
171 lastClickTime
= msg
->time
;
172 lastClickMsg
= msg
->message
;
173 lastClickPos
= msg
->pt
;
177 /* Build the translated message */
179 if (hittest
== HTCLIENT
)
180 ScreenToClient16( msg
->hwnd
, &pt
);
183 msg
->wParam
= hittest
;
184 msg
->message
+= WM_NCLBUTTONDOWN
- WM_LBUTTONDOWN
;
186 msg
->lParam
= MAKELONG( pt
.x
, pt
.y
);
188 /* Call the WH_MOUSE hook */
190 if (!HOOK_GetHook( WH_MOUSE
, GetTaskQueue(0)) ||
191 !(hook
= SEGPTR_NEW(MOUSEHOOKSTRUCT16
)))
195 hook
->hwnd
= msg
->hwnd
;
196 hook
->wHitTestCode
= hittest
;
197 hook
->dwExtraInfo
= 0;
198 ret
= !HOOK_CallHooks( WH_MOUSE
, remove
? HC_ACTION
: HC_NOREMOVE
,
199 msg
->message
, (LPARAM
)SEGPTR_GET(hook
) );
205 /***********************************************************************
206 * MSG_TranslateKeyboardMsg
208 * Translate an keyboard hardware event into a real message.
209 * Return value indicates whether the translated message must be passed
212 static BOOL
MSG_TranslateKeyboardMsg( MSG16
*msg
, BOOL remove
)
216 /* Should check Ctrl-Esc and PrintScreen here */
218 msg
->hwnd
= GetFocus();
221 /* Send the message to the active window instead, */
222 /* translating messages to their WM_SYS equivalent */
224 msg
->hwnd
= GetActiveWindow();
226 if( msg
->message
< WM_SYSKEYDOWN
)
227 msg
->message
+= WM_SYSKEYDOWN
- WM_KEYDOWN
;
229 pWnd
= WIN_FindWndPtr( msg
->hwnd
);
230 if (pWnd
&& (pWnd
->hmemTaskQ
!= GetTaskQueue(0)))
232 /* Not for the current task */
233 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) );
234 if (queue
) QUEUE_ClearWakeBit( queue
, QS_KEY
);
235 /* Wake up the other task */
236 queue
= (MESSAGEQUEUE
*)GlobalLock16( pWnd
->hmemTaskQ
);
237 if (queue
) QUEUE_SetWakeBit( queue
, QS_KEY
);
240 return !HOOK_CallHooks( WH_KEYBOARD
, remove
? HC_ACTION
: HC_NOREMOVE
,
241 msg
->wParam
, msg
->lParam
);
244 /***********************************************************************
245 * MSG_JournalRecordMsg
247 * Build an EVENTMSG structure and call JOURNALRECORD hook
249 static void MSG_JournalRecordMsg( MSG16
*msg
)
251 EVENTMSG16
*event
= SEGPTR_NEW(EVENTMSG16
);
253 event
->message
= msg
->message
;
254 event
->time
= msg
->time
;
255 if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
257 event
->paramL
= (msg
->wParam
& 0xFF) | (HIWORD(msg
->lParam
) << 8);
258 event
->paramH
= msg
->lParam
& 0x7FFF;
259 if (HIWORD(msg
->lParam
) & 0x0100)
260 event
->paramH
|= 0x8000; /* special_key - bit */
261 HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0,
262 (LPARAM
)SEGPTR_GET(event
) );
264 else if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
266 event
->paramL
= LOWORD(msg
->lParam
); /* X pos */
267 event
->paramH
= HIWORD(msg
->lParam
); /* Y pos */
268 ClientToScreen16( msg
->hwnd
, (LPPOINT16
)&event
->paramL
);
269 HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0,
270 (LPARAM
)SEGPTR_GET(event
) );
272 else if ((msg
->message
>= WM_NCMOUSEFIRST
) &&
273 (msg
->message
<= WM_NCMOUSELAST
))
275 event
->paramL
= LOWORD(msg
->lParam
); /* X pos */
276 event
->paramH
= HIWORD(msg
->lParam
); /* Y pos */
277 event
->message
+= WM_MOUSEMOVE
-WM_NCMOUSEMOVE
;/* give no info about NC area */
278 HOOK_CallHooks( WH_JOURNALRECORD
, HC_ACTION
, 0,
279 (LPARAM
)SEGPTR_GET(event
) );
284 /*****************************************************************
285 * MSG_JournalPlayBackIsAscii
287 static BOOL
MSG_JournalPlayBackIsAscii(WPARAM wParam
)
289 return ((wParam
>VK_HELP
&& wParam
<VK_F1
) ||
290 wParam
== VK_SPACE
||
291 wParam
== VK_ESCAPE
||
292 wParam
== VK_RETURN
||
298 /***********************************************************************
299 * MSG_JournalPlayBackMsg
301 * Get an EVENTMSG struct via call JOURNALPAYBACK hook function
303 static int MSG_JournalPlayBackMsg(void)
307 WORD keyDown
,i
,wParam
,result
=0;
309 if ( HOOK_GetHook(WH_JOURNALPLAYBACK
, 0) )
311 tmpMsg
= SEGPTR_NEW(EVENTMSG16
);
312 wtime
=HOOK_CallHooks( WH_JOURNALPLAYBACK
, HC_GETNEXT
, 0, (LPARAM
)SEGPTR_GET(tmpMsg
));
313 /* dprintf_msg(stddeb,"Playback wait time =%ld\n",wtime); */
317 if ((tmpMsg
->message
>= WM_KEYFIRST
) && (tmpMsg
->message
<= WM_KEYLAST
))
319 wParam
=tmpMsg
->paramL
& 0xFF;
320 lParam
=MAKELONG(tmpMsg
->paramH
&0x7ffff,tmpMsg
->paramL
>>8);
321 if (tmpMsg
->message
== WM_KEYDOWN
|| tmpMsg
->message
== WM_SYSKEYDOWN
)
323 for (keyDown
=i
=0; i
<256 && !keyDown
; i
++)
324 if (KeyStateTable
[i
] & 0x80)
327 lParam
|= 0x40000000;
328 AsyncKeyStateTable
[wParam
]=KeyStateTable
[wParam
] |= 0x80;
329 if (MSG_JournalPlayBackIsAscii(wParam
))
331 lastEventChar
= wParam
; /* control TranslateMessage() */
332 lParam
|= (LONG
)((LONG
)ASCII_CHAR_HACK
*0x10000L
);
334 if (!(KeyStateTable
[VK_SHIFT
] & 0x80) &&
335 !(KeyStateTable
[VK_CAPITAL
] & 0x80))
336 lastEventChar
= tolower(lastEventChar
);
337 if (KeyStateTable
[VK_CONTROL
] & 0x80)
341 else /* WM_KEYUP, WM_SYSKEYUP */
343 lParam
|= 0xC0000000;
344 AsyncKeyStateTable
[wParam
]=KeyStateTable
[wParam
] &= ~0x80;
346 if (KeyStateTable
[VK_MENU
] & 0x80)
347 lParam
|= 0x20000000;
348 if (tmpMsg
->paramH
& 0x8000) /*special_key bit*/
349 lParam
|= 0x01000000;
350 hardware_event( tmpMsg
->message
, wParam
, lParam
,0, 0, tmpMsg
->time
, 0 );
354 if ((tmpMsg
->message
>= WM_MOUSEFIRST
) && (tmpMsg
->message
<= WM_MOUSELAST
))
356 switch (tmpMsg
->message
)
358 case WM_LBUTTONDOWN
:MouseButtonsStates
[0]=AsyncMouseButtonsStates
[0]=1;break;
359 case WM_LBUTTONUP
: MouseButtonsStates
[0]=AsyncMouseButtonsStates
[0]=0;break;
360 case WM_MBUTTONDOWN
:MouseButtonsStates
[1]=AsyncMouseButtonsStates
[1]=1;break;
361 case WM_MBUTTONUP
: MouseButtonsStates
[1]=AsyncMouseButtonsStates
[1]=0;break;
362 case WM_RBUTTONDOWN
:MouseButtonsStates
[2]=AsyncMouseButtonsStates
[2]=1;break;
363 case WM_RBUTTONUP
: MouseButtonsStates
[2]=AsyncMouseButtonsStates
[2]=0;break;
365 AsyncKeyStateTable
[VK_LBUTTON
]= KeyStateTable
[VK_LBUTTON
] = MouseButtonsStates
[0] << 8;
366 AsyncKeyStateTable
[VK_MBUTTON
]= KeyStateTable
[VK_MBUTTON
] = MouseButtonsStates
[1] << 8;
367 AsyncKeyStateTable
[VK_RBUTTON
]= KeyStateTable
[VK_RBUTTON
] = MouseButtonsStates
[2] << 8;
368 SetCursorPos(tmpMsg
->paramL
,tmpMsg
->paramH
);
369 lParam
=MAKELONG(tmpMsg
->paramL
,tmpMsg
->paramH
);
371 if (MouseButtonsStates
[0]) wParam
|= MK_LBUTTON
;
372 if (MouseButtonsStates
[1]) wParam
|= MK_MBUTTON
;
373 if (MouseButtonsStates
[2]) wParam
|= MK_RBUTTON
;
374 hardware_event( tmpMsg
->message
, wParam
, lParam
,
375 tmpMsg
->paramL
, tmpMsg
->paramH
, tmpMsg
->time
, 0 );
378 HOOK_CallHooks( WH_JOURNALPLAYBACK
, HC_SKIP
, 0, (LPARAM
)SEGPTR_GET(tmpMsg
));
381 result
= QS_MOUSE
| QS_KEY
;
387 /***********************************************************************
388 * MSG_PeekHardwareMsg
390 * Peek for a hardware message matching the hwnd and message filters.
392 static BOOL
MSG_PeekHardwareMsg( MSG16
*msg
, HWND hwnd
, WORD first
, WORD last
,
395 MESSAGEQUEUE
*sysMsgQueue
= QUEUE_GetSysQueue();
396 int i
, pos
= sysMsgQueue
->nextMessage
;
398 /* If the queue is empty, attempt to fill it */
399 if (!sysMsgQueue
->msgCount
&& XPending(display
)) EVENT_WaitXEvent( FALSE
);
401 for (i
= 0; i
< sysMsgQueue
->msgCount
; i
++, pos
++)
403 if (pos
>= sysMsgQueue
->queueSize
) pos
= 0;
404 *msg
= sysMsgQueue
->messages
[pos
].msg
;
406 /* Translate message */
408 if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
410 if (!MSG_TranslateMouseMsg( msg
, remove
)) continue;
412 else if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
414 if (!MSG_TranslateKeyboardMsg( msg
, remove
)) continue;
416 else /* Non-standard hardware event */
418 HARDWAREHOOKSTRUCT16
*hook
;
419 if ((hook
= SEGPTR_NEW(HARDWAREHOOKSTRUCT16
)))
422 hook
->hWnd
= msg
->hwnd
;
423 hook
->wMessage
= msg
->message
;
424 hook
->wParam
= msg
->wParam
;
425 hook
->lParam
= msg
->lParam
;
426 ret
= HOOK_CallHooks( WH_HARDWARE
,
427 remove
? HC_ACTION
: HC_NOREMOVE
,
428 0, (LPARAM
)SEGPTR_GET(hook
) );
434 /* Check message against filters */
436 if (hwnd
&& (msg
->hwnd
!= hwnd
)) continue;
437 if ((first
|| last
) &&
438 ((msg
->message
< first
) || (msg
->message
> last
))) continue;
439 if ((msg
->hwnd
!= GetDesktopWindow()) &&
440 (GetWindowTask16(msg
->hwnd
) != GetCurrentTask()))
441 continue; /* Not for this task */
442 if (remove
&& HOOK_GetHook( WH_JOURNALRECORD
, GetTaskQueue(0) ))
443 MSG_JournalRecordMsg( msg
);
444 if (remove
) QUEUE_RemoveMsg( sysMsgQueue
, pos
);
451 /**********************************************************************
452 * SetDoubleClickTime (USER.20)
454 void SetDoubleClickTime( WORD interval
)
456 doubleClickSpeed
= interval
? interval
: 500;
460 /**********************************************************************
461 * GetDoubleClickTime (USER.21)
463 WORD
GetDoubleClickTime()
465 return doubleClickSpeed
;
469 /***********************************************************************
472 * Implementation of an inter-task SendMessage.
474 static LRESULT
MSG_SendMessage( HQUEUE16 hDestQueue
, HWND hwnd
, UINT msg
,
475 WPARAM wParam
, LPARAM lParam
)
477 MESSAGEQUEUE
*queue
, *destQ
;
479 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
480 if (!(destQ
= (MESSAGEQUEUE
*)GlobalLock16( hDestQueue
))) return 0;
484 fprintf( stderr
, "SendMessage: task is locked\n" );
490 fprintf( stderr
, "Nested SendMessage(), msg %04x skipped\n", msg
);
495 queue
->wParam
= wParam
;
496 queue
->lParam
= lParam
;
497 queue
->hPrevSendingTask
= destQ
->hSendingTask
;
498 destQ
->hSendingTask
= GetTaskQueue(0);
499 QUEUE_SetWakeBit( destQ
, QS_SENDMESSAGE
);
501 /* Wait for the result */
503 printf( "SendMessage %04x to %04x\n", msg
, hDestQueue
);
505 if (!(queue
->wakeBits
& QS_SMRESULT
))
507 DirectedYield( destQ
->hTask
);
508 QUEUE_WaitBits( QS_SMRESULT
);
510 printf( "SendMessage %04x to %04x: got %08lx\n",
511 msg
, hDestQueue
, queue
->SendMessageReturn
);
512 queue
->wakeBits
&= ~QS_SMRESULT
;
513 return queue
->SendMessageReturn
;
517 /***********************************************************************
518 * ReplyMessage (USER.115)
520 void ReplyMessage( LRESULT result
)
522 MESSAGEQUEUE
*senderQ
;
525 printf( "ReplyMessage\n " );
526 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return;
527 if (!(senderQ
= (MESSAGEQUEUE
*)GlobalLock16( queue
->InSendMessageHandle
)))
531 if (queue
->wakeBits
& QS_SENDMESSAGE
) QUEUE_ReceiveMessage( queue
);
532 else if (senderQ
->wakeBits
& QS_SMRESULT
) Yield();
535 printf( "ReplyMessage: res = %08lx\n", result
);
536 senderQ
->SendMessageReturn
= result
;
537 queue
->InSendMessageHandle
= 0;
538 QUEUE_SetWakeBit( senderQ
, QS_SMRESULT
);
539 DirectedYield( queue
->hSendingTask
);
543 /***********************************************************************
546 static BOOL
MSG_PeekMessage( LPMSG16 msg
, HWND hwnd
, WORD first
, WORD last
,
547 WORD flags
, BOOL peek
)
550 MESSAGEQUEUE
*msgQueue
;
554 DDE_TestDDE(hwnd
); /* do we have dde handling in the window ?*/
555 DDE_GetRemoteMessage();
556 #endif /* CONFIG_IPC */
558 mask
= QS_POSTMESSAGE
| QS_SENDMESSAGE
; /* Always selected */
561 /* MSWord gets stuck if we do not check for nonclient mouse messages */
563 if ((first
<= WM_KEYLAST
) && (last
>= WM_KEYFIRST
)) mask
|= QS_KEY
;
564 if ( ((first
<= WM_MOUSELAST
) && (last
>= WM_MOUSEFIRST
)) ||
565 ((first
<= WM_NCMOUSELAST
) && (last
>= WM_NCMOUSEFIRST
)) ) mask
|= QS_MOUSE
;
566 if ((first
<= WM_TIMER
) && (last
>= WM_TIMER
)) mask
|= QS_TIMER
;
567 if ((first
<= WM_SYSTIMER
) && (last
>= WM_SYSTIMER
)) mask
|= QS_TIMER
;
568 if ((first
<= WM_PAINT
) && (last
>= WM_PAINT
)) mask
|= QS_PAINT
;
570 else mask
|= QS_MOUSE
| QS_KEY
| QS_TIMER
| QS_PAINT
;
572 if (IsTaskLocked()) flags
|= PM_NOYIELD
;
576 hQueue
= GetTaskQueue(0);
577 msgQueue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
578 if (!msgQueue
) return FALSE
;
579 msgQueue
->changeBits
= 0;
581 /* First handle a message put by SendMessage() */
583 if (msgQueue
->wakeBits
& QS_SENDMESSAGE
)
584 QUEUE_ReceiveMessage( msgQueue
);
586 /* Now find a normal message */
588 if (((msgQueue
->wakeBits
& mask
) & QS_POSTMESSAGE
) &&
589 ((pos
= QUEUE_FindMsg( msgQueue
, hwnd
, first
, last
)) != -1))
591 QMSG
*qmsg
= &msgQueue
->messages
[pos
];
593 msgQueue
->GetMessageTimeVal
= msg
->time
;
594 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
595 msgQueue
->GetMessageExtraInfoVal
= qmsg
->extraInfo
;
597 if (flags
& PM_REMOVE
) QUEUE_RemoveMsg( msgQueue
, pos
);
601 msgQueue
->changeBits
|= MSG_JournalPlayBackMsg();
603 /* Now find a hardware event */
605 if (((msgQueue
->wakeBits
& mask
) & (QS_MOUSE
| QS_KEY
)) &&
606 MSG_PeekHardwareMsg( msg
, hwnd
, first
, last
, flags
& PM_REMOVE
))
609 msgQueue
->GetMessageTimeVal
= msg
->time
;
610 msgQueue
->GetMessagePosVal
= *(DWORD
*)&msg
->pt
;
611 msgQueue
->GetMessageExtraInfoVal
= 0; /* Always 0 for now */
615 /* Now handle a WM_QUIT message */
617 if (msgQueue
->wPostQMsg
)
620 msg
->message
= WM_QUIT
;
621 msg
->wParam
= msgQueue
->wExitCode
;
626 /* Check again for SendMessage */
628 if (msgQueue
->wakeBits
& QS_SENDMESSAGE
)
629 QUEUE_ReceiveMessage( msgQueue
);
631 /* Now find a WM_PAINT message */
633 if ((msgQueue
->wakeBits
& mask
) & QS_PAINT
)
636 msg
->hwnd
= WIN_FindWinToRepaint( hwnd
, hQueue
);
637 msg
->message
= WM_PAINT
;
641 if ((wndPtr
= WIN_FindWndPtr(msg
->hwnd
)))
643 if( wndPtr
->dwStyle
& WS_MINIMIZE
&&
644 wndPtr
->class->hIcon
)
646 msg
->message
= WM_PAINTICON
;
650 if( !hwnd
|| msg
->hwnd
== hwnd
|| IsChild(hwnd
,msg
->hwnd
) )
652 if( wndPtr
->flags
& WIN_INTERNAL_PAINT
&& !wndPtr
->hrgnUpdate
)
654 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
655 QUEUE_DecPaintCount( hQueue
);
662 /* Check for timer messages, but yield first */
664 if (!(flags
& PM_NOYIELD
))
667 if (msgQueue
->wakeBits
& QS_SENDMESSAGE
)
668 QUEUE_ReceiveMessage( msgQueue
);
670 if ((msgQueue
->wakeBits
& mask
) & QS_TIMER
)
672 if (TIMER_GetTimerMsg(msg
, hwnd
, hQueue
, flags
& PM_REMOVE
)) break;
677 if (!(flags
& PM_NOYIELD
)) UserYield();
680 msgQueue
->wakeMask
= mask
;
681 QUEUE_WaitBits( mask
);
684 /* We got a message */
685 if (peek
) return TRUE
;
686 else return (msg
->message
!= WM_QUIT
);
690 /***********************************************************************
691 * MSG_InternalGetMessage
693 * GetMessage() function for internal use. Behave like GetMessage(),
694 * but also call message filters and optionally send WM_ENTERIDLE messages.
695 * 'hwnd' must be the handle of the dialog or menu window.
696 * 'code' is the message filter value (MSGF_??? codes).
698 BOOL
MSG_InternalGetMessage( MSG16
*msg
, HWND hwnd
, HWND hwndOwner
, short code
,
699 WORD flags
, BOOL sendIdle
)
705 if (!MSG_PeekMessage( msg
, 0, 0, 0, flags
, TRUE
))
707 /* No message present -> send ENTERIDLE and wait */
708 if (IsWindow(hwndOwner
))
709 SendMessage16( hwndOwner
, WM_ENTERIDLE
,
710 code
, (LPARAM
)hwnd
);
711 MSG_PeekMessage( msg
, 0, 0, 0, flags
, FALSE
);
714 else /* Always wait for a message */
715 MSG_PeekMessage( msg
, 0, 0, 0, flags
, FALSE
);
717 /* Call message filters */
719 if (HOOK_GetHook( WH_SYSMSGFILTER
, GetTaskQueue(0) ) ||
720 HOOK_GetHook( WH_MSGFILTER
, GetTaskQueue(0) ))
722 MSG16
*pmsg
= SEGPTR_NEW(MSG16
);
727 ret
= ((BOOL16
)HOOK_CallHooks( WH_SYSMSGFILTER
, code
, 0,
728 (LPARAM
)SEGPTR_GET(pmsg
) ) ||
729 (BOOL16
)HOOK_CallHooks( WH_MSGFILTER
, code
, 0,
730 (LPARAM
)SEGPTR_GET(pmsg
) ));
734 /* Message filtered -> remove it from the queue */
735 /* if it's still there. */
736 if (!(flags
& PM_REMOVE
))
737 MSG_PeekMessage( msg
, 0, 0, 0, PM_REMOVE
, TRUE
);
743 return (msg
->message
!= WM_QUIT
);
748 /***********************************************************************
749 * PeekMessage16 (USER.109)
751 BOOL16
PeekMessage16( LPMSG16 msg
, HWND16 hwnd
, UINT16 first
,
752 UINT16 last
, UINT16 flags
)
754 return MSG_PeekMessage( msg
, hwnd
, first
, last
, flags
, TRUE
);
758 /***********************************************************************
759 * GetMessage (USER.108)
761 BOOL
GetMessage( SEGPTR msg
, HWND hwnd
, UINT first
, UINT last
)
763 MSG16
*lpmsg
= (MSG16
*)PTR_SEG_TO_LIN(msg
);
764 MSG_PeekMessage( lpmsg
,
765 hwnd
, first
, last
, PM_REMOVE
, FALSE
);
767 dprintf_msg(stddeb
,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg
->message
,
769 HOOK_CallHooks( WH_GETMESSAGE
, HC_ACTION
, 0, (LPARAM
)msg
);
770 return (lpmsg
->message
!= WM_QUIT
);
774 /***********************************************************************
775 * PostMessage (USER.110)
777 BOOL
PostMessage( HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
783 msg
.message
= message
;
786 msg
.time
= GetTickCount();
791 if (DDE_PostMessage(&msg
))
793 #endif /* CONFIG_IPC */
795 if (hwnd
== HWND_BROADCAST16
)
797 dprintf_msg(stddeb
,"PostMessage // HWND_BROADCAST !\n");
798 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
800 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
802 dprintf_msg(stddeb
,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
803 wndPtr
->hwndSelf
, message
, wParam
, lParam
);
804 PostMessage( wndPtr
->hwndSelf
, message
, wParam
, lParam
);
807 dprintf_msg(stddeb
,"PostMessage // End of HWND_BROADCAST !\n");
811 wndPtr
= WIN_FindWndPtr( hwnd
);
812 if (!wndPtr
|| !wndPtr
->hmemTaskQ
) return FALSE
;
814 return QUEUE_AddMsg( wndPtr
->hmemTaskQ
, &msg
, 0 );
817 /***********************************************************************
818 * PostAppMessage (USER.116)
820 BOOL
PostAppMessage( HTASK hTask
, WORD message
, WORD wParam
, LONG lParam
)
824 if (GetTaskQueue(hTask
) == 0) return FALSE
;
826 msg
.message
= message
;
829 msg
.time
= GetTickCount();
833 return QUEUE_AddMsg( GetTaskQueue(hTask
), &msg
, 0 );
837 /***********************************************************************
838 * SendMessage16 (USER.111)
840 LRESULT
SendMessage16( HWND16 hwnd
, UINT16 msg
, WPARAM16 wParam
, LPARAM lParam
)
846 MSG16 DDE_msg
= { hwnd
, msg
, wParam
, lParam
};
847 if (DDE_SendMessage(&DDE_msg
)) return TRUE
;
848 #endif /* CONFIG_IPC */
850 if (hwnd
== HWND_BROADCAST16
)
852 dprintf_msg(stddeb
,"SendMessage // HWND_BROADCAST !\n");
853 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
855 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
857 dprintf_msg(stddeb
,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
858 wndPtr
->hwndSelf
, msg
, (DWORD
)wParam
, lParam
);
859 SendMessage16( wndPtr
->hwndSelf
, msg
, wParam
, lParam
);
862 dprintf_msg(stddeb
,"SendMessage // End of HWND_BROADCAST !\n");
866 if (HOOK_GetHook( WH_CALLWNDPROC
, GetTaskQueue(0) ))
876 if ((pmsg
= SEGPTR_NEW(struct msgstruct
)))
880 pmsg
->wParam
= wParam
;
881 pmsg
->lParam
= lParam
;
882 HOOK_CallHooks( WH_CALLWNDPROC
, HC_ACTION
, 1,
883 (LPARAM
)SEGPTR_GET(pmsg
) );
886 wParam
= pmsg
->wParam
;
887 lParam
= pmsg
->lParam
;
891 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
893 fprintf( stderr
, "SendMessage16: invalid hwnd %04x\n", hwnd
);
896 if (QUEUE_IsDoomedQueue(wndPtr
->hmemTaskQ
))
897 return 0; /* Don't send anything if the task is dying */
898 if (wndPtr
->hmemTaskQ
!= GetTaskQueue(0))
899 return MSG_SendMessage( wndPtr
->hmemTaskQ
, hwnd
, msg
, wParam
, lParam
);
901 SPY_EnterMessage( SPY_SENDMESSAGE16
, hwnd
, msg
, wParam
, lParam
);
902 ret
= CallWindowProc16( (WNDPROC16
)wndPtr
->winproc
,
903 hwnd
, msg
, wParam
, lParam
);
904 SPY_ExitMessage( SPY_RESULT_OK16
, hwnd
, msg
, ret
);
909 /***********************************************************************
910 * SendMessage32A (USER32.453)
912 LRESULT
SendMessage32A(HWND32 hwnd
, UINT32 msg
, WPARAM32 wParam
, LPARAM lParam
)
917 if (hwnd
== HWND_BROADCAST32
)
919 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
921 /* FIXME: should use something like EnumWindows here */
922 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
923 SendMessage32A( wndPtr
->hwndSelf
, msg
, wParam
, lParam
);
928 /* FIXME: call hooks */
930 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
932 fprintf( stderr
, "SendMessage32A: invalid hwnd %08x\n", hwnd
);
936 if (WINPROC_GetProcType( wndPtr
->winproc
) == WIN_PROC_16
)
938 /* Use SendMessage16 for now to get hooks right */
941 if (WINPROC_MapMsg32ATo16( msg
, wParam
, &msg16
, &wParam16
, &lParam
) == -1)
943 ret
= SendMessage16( hwnd
, msg16
, wParam16
, lParam
);
944 WINPROC_UnmapMsg32ATo16( msg16
, wParam16
, lParam
);
948 if (QUEUE_IsDoomedQueue(wndPtr
->hmemTaskQ
))
949 return 0; /* Don't send anything if the task is dying */
951 if (wndPtr
->hmemTaskQ
!= GetTaskQueue(0))
953 fprintf( stderr
, "SendMessage32A: intertask message not supported\n" );
957 SPY_EnterMessage( SPY_SENDMESSAGE32
, hwnd
, msg
, wParam
, lParam
);
958 ret
= CallWindowProc32A( (WNDPROC32
)wndPtr
->winproc
,
959 hwnd
, msg
, wParam
, lParam
);
960 SPY_ExitMessage( SPY_RESULT_OK32
, hwnd
, msg
, ret
);
965 /***********************************************************************
966 * SendMessage32W (USER32.458)
968 LRESULT
SendMessage32W(HWND32 hwnd
, UINT32 msg
, WPARAM32 wParam
, LPARAM lParam
)
973 if (hwnd
== HWND_BROADCAST32
)
975 for (wndPtr
= WIN_GetDesktop()->child
; wndPtr
; wndPtr
= wndPtr
->next
)
977 /* FIXME: should use something like EnumWindows here */
978 if (wndPtr
->dwStyle
& WS_POPUP
|| wndPtr
->dwStyle
& WS_CAPTION
)
979 SendMessage32W( wndPtr
->hwndSelf
, msg
, wParam
, lParam
);
984 /* FIXME: call hooks */
986 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)))
988 fprintf( stderr
, "SendMessage32W: invalid hwnd %08x\n", hwnd
);
991 if (QUEUE_IsDoomedQueue(wndPtr
->hmemTaskQ
))
992 return 0; /* Don't send anything if the task is dying */
993 if (wndPtr
->hmemTaskQ
!= GetTaskQueue(0))
995 fprintf( stderr
, "SendMessage32W: intertask message not supported\n" );
999 SPY_EnterMessage( SPY_SENDMESSAGE32
, hwnd
, msg
, wParam
, lParam
);
1000 ret
= CallWindowProc32W( (WNDPROC32
)wndPtr
->winproc
,
1001 hwnd
, msg
, wParam
, lParam
);
1002 SPY_ExitMessage( SPY_RESULT_OK32
, hwnd
, msg
, ret
);
1007 /***********************************************************************
1008 * WaitMessage (USER.112)
1010 void WaitMessage( void )
1012 QUEUE_WaitBits( QS_ALLINPUT
);
1016 /***********************************************************************
1017 * TranslateMessage (USER.113)
1019 * This should call ToAscii but it is currently broken
1023 BOOL
TranslateMessage( LPMSG16 msg
)
1025 UINT message
= msg
->message
;
1026 /* BYTE wparam[2]; */
1028 if ((message
== WM_KEYDOWN
) || (message
== WM_KEYUP
) ||
1029 (message
== WM_SYSKEYDOWN
) || (message
== WM_SYSKEYUP
))
1031 dprintf_msg(stddeb
, "Translating key %04x, scancode %04x\n", msg
->wParam
,
1032 HIWORD(msg
->lParam
) );
1034 if( HIWORD(msg
->lParam
) & ASCII_CHAR_HACK
)
1036 /* if( ToAscii( msg->wParam, HIWORD(msg->lParam), (LPSTR)&KeyStateTable,
1040 message
+= 2 - (message
& 0x0001);
1042 PostMessage( msg
->hwnd
, message
, lastEventChar
, msg
->lParam
);
1051 /***********************************************************************
1052 * DispatchMessage (USER.114)
1054 LONG
DispatchMessage( const MSG16
* msg
)
1060 /* Process timer messages */
1061 if ((msg
->message
== WM_TIMER
) || (msg
->message
== WM_SYSTIMER
))
1065 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1066 return CallWindowProc16( (WNDPROC16
)msg
->lParam
, msg
->hwnd
,
1067 msg
->message
, msg
->wParam
, GetTickCount() );
1071 if (!msg
->hwnd
) return 0;
1072 if (!(wndPtr
= WIN_FindWndPtr( msg
->hwnd
))) return 0;
1073 if (!wndPtr
->winproc
) return 0;
1074 painting
= (msg
->message
== WM_PAINT
);
1075 if (painting
) wndPtr
->flags
|= WIN_NEEDS_BEGINPAINT
;
1076 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1078 SPY_EnterMessage( SPY_DISPATCHMESSAGE16
, msg
->hwnd
, msg
->message
,
1079 msg
->wParam
, msg
->lParam
);
1080 retval
= CallWindowProc16( (WNDPROC16
)wndPtr
->winproc
,
1081 msg
->hwnd
, msg
->message
,
1082 msg
->wParam
, msg
->lParam
);
1083 SPY_ExitMessage( SPY_RESULT_OK16
, msg
->hwnd
, msg
->message
, retval
);
1085 if (painting
&& (wndPtr
= WIN_FindWndPtr( msg
->hwnd
)) &&
1086 (wndPtr
->flags
& WIN_NEEDS_BEGINPAINT
) && wndPtr
->hrgnUpdate
)
1088 fprintf(stderr
, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
1090 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
1091 /* Validate the update region to avoid infinite WM_PAINT loop */
1092 ValidateRect32( msg
->hwnd
, NULL
);
1098 /***********************************************************************
1099 * RegisterWindowMessage16 (USER.118)
1101 WORD
RegisterWindowMessage16( SEGPTR str
)
1103 dprintf_msg(stddeb
, "RegisterWindowMessage16: %08lx\n", (DWORD
)str
);
1104 return GlobalAddAtom16( str
);
1108 /***********************************************************************
1109 * RegisterWindowMessage32A (USER32.436)
1111 WORD
RegisterWindowMessage32A( LPCSTR str
)
1113 dprintf_msg(stddeb
, "RegisterWindowMessage32A: %s\n", str
);
1114 return GlobalAddAtom32A( str
);
1118 /***********************************************************************
1119 * RegisterWindowMessage32W (USER32.437)
1121 WORD
RegisterWindowMessage32W( LPCWSTR str
)
1123 dprintf_msg(stddeb
, "RegisterWindowMessage32W: %p\n", str
);
1124 return GlobalAddAtom32W( str
);
1128 /***********************************************************************
1129 * GetTickCount (USER.13) (KERNEL32.299)
1131 DWORD
GetTickCount(void)
1134 gettimeofday( &t
, NULL
);
1135 return ((t
.tv_sec
* 1000) + (t
.tv_usec
/ 1000)) - MSG_WineStartTicks
;
1139 /***********************************************************************
1140 * GetCurrentTime (USER.15)
1142 * (effectively identical to GetTickCount)
1144 DWORD
GetCurrentTime(void)
1146 return GetTickCount();
1150 /***********************************************************************
1151 * InSendMessage (USER.192)
1153 BOOL
InSendMessage()
1155 MESSAGEQUEUE
*queue
;
1157 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) )))
1159 return (BOOL
)queue
->InSendMessageHandle
;