Release 960902
[wine/multimedia.git] / windows / message.c
blobb61ecb392d9a33de4a9c305b5814ab1c37f0caf1
1 /*
2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include <sys/time.h>
11 #include <sys/types.h>
13 #include "message.h"
14 #include "win.h"
15 #include "gdi.h"
16 #include "sysmetrics.h"
17 #include "heap.h"
18 #include "hook.h"
19 #include "spy.h"
20 #include "winpos.h"
21 #include "atom.h"
22 #include "dde.h"
23 #include "queue.h"
24 #include "winproc.h"
25 #include "stddebug.h"
26 /* #define DEBUG_MSG */
27 #include "debug.h"
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
52 * to the user.
53 * Actions performed:
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 )
64 WND *pWnd;
65 BOOL eatMsg = FALSE;
66 INT16 hittest;
67 MOUSEHOOKSTRUCT16 *hook;
68 BOOL32 ret;
69 static DWORD lastClickTime = 0;
70 static WORD lastClickMsg = 0;
71 static POINT16 lastClickPos = { 0, 0 };
72 POINT16 pt = msg->pt;
74 BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
75 (msg->message == WM_RBUTTONDOWN) ||
76 (msg->message == WM_MBUTTONDOWN));
78 /* Find the window */
80 if ((msg->hwnd = GetCapture()) != 0)
82 BOOL32 ret;
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)))
90 return TRUE;
91 hook->pt = msg->pt;
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));
97 SEGPTR_FREE(hook);
98 return ret;
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 );
110 return FALSE;
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))
130 eatMsg = TRUE;
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 */
146 if (mouseClick)
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))
154 dbl_click = TRUE;
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;
169 if (remove)
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 );
181 else
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)))
192 return TRUE;
194 hook->pt = msg->pt;
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) );
200 SEGPTR_FREE(hook);
201 return ret;
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
210 * to the user.
212 static BOOL MSG_TranslateKeyboardMsg( MSG16 *msg, BOOL remove )
214 WND *pWnd;
216 /* Should check Ctrl-Esc and PrintScreen here */
218 msg->hwnd = GetFocus();
219 if (!msg->hwnd)
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 );
238 return FALSE;
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);
252 if (!event) return;
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) );
281 SEGPTR_FREE(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 ||
293 wParam == VK_TAB ||
294 wParam == VK_BACK);
298 /***********************************************************************
299 * MSG_JournalPlayBackMsg
301 * Get an EVENTMSG struct via call JOURNALPAYBACK hook function
303 static int MSG_JournalPlayBackMsg(void)
305 EVENTMSG16 *tmpMsg;
306 long wtime,lParam;
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); */
314 if (wtime<=0)
316 wtime=0;
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)
325 keyDown++;
326 if (!keyDown)
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)
338 lastEventChar&=0x1f;
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 );
352 else
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);
370 wParam=0;
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));
380 else
381 result= QS_MOUSE | QS_KEY;
382 SEGPTR_FREE(tmpMsg);
384 return result;
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,
393 BOOL remove )
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)))
421 BOOL32 ret;
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) );
429 SEGPTR_FREE(hook);
430 if (ret) continue;
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 );
445 return TRUE;
447 return FALSE;
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 /***********************************************************************
470 * MSG_SendMessage
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;
482 if (IsTaskLocked())
484 fprintf( stderr, "SendMessage: task is locked\n" );
485 return 0;
488 if (queue->hWnd)
490 fprintf( stderr, "Nested SendMessage(), msg %04x skipped\n", msg );
491 return 0;
493 queue->hWnd = hwnd;
494 queue->msg = 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;
523 MESSAGEQUEUE *queue;
525 printf( "ReplyMessage\n " );
526 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
527 if (!(senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
528 return;
529 for (;;)
531 if (queue->wakeBits & QS_SENDMESSAGE) QUEUE_ReceiveMessage( queue );
532 else if (senderQ->wakeBits & QS_SMRESULT) Yield();
533 else break;
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 /***********************************************************************
544 * MSG_PeekMessage
546 static BOOL MSG_PeekMessage( LPMSG16 msg, HWND hwnd, WORD first, WORD last,
547 WORD flags, BOOL peek )
549 int pos, mask;
550 MESSAGEQUEUE *msgQueue;
551 HQUEUE16 hQueue;
553 #ifdef CONFIG_IPC
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 */
559 if (first || last)
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;
574 while(1)
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];
592 *msg = qmsg->msg;
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 );
598 break;
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 ))
608 /* Got one */
609 msgQueue->GetMessageTimeVal = msg->time;
610 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
611 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
612 break;
615 /* Now handle a WM_QUIT message */
617 if (msgQueue->wPostQMsg)
619 msg->hwnd = hwnd;
620 msg->message = WM_QUIT;
621 msg->wParam = msgQueue->wExitCode;
622 msg->lParam = 0;
623 break;
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)
635 WND* wndPtr;
636 msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
637 msg->message = WM_PAINT;
638 msg->wParam = 0;
639 msg->lParam = 0;
641 if ((wndPtr = WIN_FindWndPtr(msg->hwnd)))
643 if( wndPtr->dwStyle & WS_MINIMIZE &&
644 wndPtr->class->hIcon )
646 msg->message = WM_PAINTICON;
647 msg->wParam = 1;
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 );
657 break;
662 /* Check for timer messages, but yield first */
664 if (!(flags & PM_NOYIELD))
666 UserYield();
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;
675 if (peek)
677 if (!(flags & PM_NOYIELD)) UserYield();
678 return FALSE;
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 )
701 for (;;)
703 if (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);
723 if (pmsg)
725 BOOL32 ret;
726 *pmsg = *msg;
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) ));
731 SEGPTR_FREE(pmsg);
732 if (ret)
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 );
738 continue;
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,
768 hwnd, first, last );
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 )
779 MSG16 msg;
780 WND *wndPtr;
782 msg.hwnd = hwnd;
783 msg.message = message;
784 msg.wParam = wParam;
785 msg.lParam = lParam;
786 msg.time = GetTickCount();
787 msg.pt.x = 0;
788 msg.pt.y = 0;
790 #ifdef CONFIG_IPC
791 if (DDE_PostMessage(&msg))
792 return TRUE;
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");
808 return TRUE;
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 )
822 MSG16 msg;
824 if (GetTaskQueue(hTask) == 0) return FALSE;
825 msg.hwnd = 0;
826 msg.message = message;
827 msg.wParam = wParam;
828 msg.lParam = lParam;
829 msg.time = GetTickCount();
830 msg.pt.x = 0;
831 msg.pt.y = 0;
833 return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
837 /***********************************************************************
838 * SendMessage16 (USER.111)
840 LRESULT SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam)
842 WND * wndPtr;
843 LRESULT ret;
845 #ifdef CONFIG_IPC
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");
863 return TRUE;
866 if (HOOK_GetHook( WH_CALLWNDPROC, GetTaskQueue(0) ))
868 struct msgstruct
870 LPARAM lParam;
871 WPARAM16 wParam;
872 UINT16 wMsg;
873 HWND16 hWnd;
874 } *pmsg;
876 if ((pmsg = SEGPTR_NEW(struct msgstruct)))
878 pmsg->hWnd = hwnd;
879 pmsg->wMsg = msg;
880 pmsg->wParam = wParam;
881 pmsg->lParam = lParam;
882 HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 1,
883 (LPARAM)SEGPTR_GET(pmsg) );
884 hwnd = pmsg->hWnd;
885 msg = pmsg->wMsg;
886 wParam = pmsg->wParam;
887 lParam = pmsg->lParam;
891 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
893 fprintf( stderr, "SendMessage16: invalid hwnd %04x\n", hwnd );
894 return 0;
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 );
905 return ret;
909 /***********************************************************************
910 * SendMessage32A (USER32.453)
912 LRESULT SendMessage32A(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
914 WND * wndPtr;
915 LRESULT ret;
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 );
925 return TRUE;
928 /* FIXME: call hooks */
930 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
932 fprintf( stderr, "SendMessage32A: invalid hwnd %08x\n", hwnd );
933 return 0;
936 if (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_16)
938 /* Use SendMessage16 for now to get hooks right */
939 UINT16 msg16;
940 WPARAM16 wParam16;
941 if (WINPROC_MapMsg32ATo16( msg, wParam, &msg16, &wParam16, &lParam ) == -1)
942 return 0;
943 ret = SendMessage16( hwnd, msg16, wParam16, lParam );
944 WINPROC_UnmapMsg32ATo16( msg16, wParam16, lParam );
945 return ret;
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" );
954 return 0;
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 );
961 return ret;
965 /***********************************************************************
966 * SendMessage32W (USER32.458)
968 LRESULT SendMessage32W(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
970 WND * wndPtr;
971 LRESULT ret;
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 );
981 return TRUE;
984 /* FIXME: call hooks */
986 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
988 fprintf( stderr, "SendMessage32W: invalid hwnd %08x\n", hwnd );
989 return 0;
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" );
996 return 0;
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 );
1003 return 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,
1037 wparam, 0 ) )
1040 message += 2 - (message & 0x0001);
1042 PostMessage( msg->hwnd, message, lastEventChar, msg->lParam );
1044 return TRUE;
1047 return FALSE;
1051 /***********************************************************************
1052 * DispatchMessage (USER.114)
1054 LONG DispatchMessage( const MSG16* msg )
1056 WND * wndPtr;
1057 LONG retval;
1058 int painting;
1060 /* Process timer messages */
1061 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1063 if (msg->lParam)
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",
1089 msg->hwnd);
1090 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1091 /* Validate the update region to avoid infinite WM_PAINT loop */
1092 ValidateRect32( msg->hwnd, NULL );
1094 return retval;
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)
1133 struct timeval t;
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) )))
1158 return 0;
1159 return (BOOL)queue->InSendMessageHandle;