Release 960818
[wine/hacks.git] / windows / message.c
blob4d5b5587f9a8f46d6022aab8b10029d653f580d6
1 /*
2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/time.h>
10 #include <sys/types.h>
12 #include "message.h"
13 #include "win.h"
14 #include "gdi.h"
15 #include "sysmetrics.h"
16 #include "heap.h"
17 #include "hook.h"
18 #include "spy.h"
19 #include "winpos.h"
20 #include "atom.h"
21 #include "dde.h"
22 #include "queue.h"
23 #include "winproc.h"
24 #include "stddebug.h"
25 /* #define DEBUG_MSG */
26 #include "debug.h"
28 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
29 #define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK
31 #define HWND_BROADCAST16 ((HWND16)0xffff)
32 #define HWND_BROADCAST32 ((HWND32)0xffffffff)
34 extern BYTE* KeyStateTable; /* event.c */
35 extern WPARAM lastEventChar; /* event.c */
37 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
39 static WORD doubleClickSpeed = 452;
41 /***********************************************************************
42 * MSG_TranslateMouseMsg
44 * Translate an mouse hardware event into a real mouse message.
45 * Return value indicates whether the translated message must be passed
46 * to the user.
47 * Actions performed:
48 * - Find the window for this message.
49 * - Translate button-down messages in double-clicks.
50 * - Send the WM_NCHITTEST message to find where the cursor is.
51 * - Activate the window if needed.
52 * - Translate the message into a non-client message, or translate
53 * the coordinates to client coordinates.
54 * - Send the WM_SETCURSOR message.
56 static BOOL MSG_TranslateMouseMsg( MSG16 *msg, BOOL remove )
58 WND *pWnd;
59 BOOL eatMsg = FALSE;
60 INT16 hittest;
61 MOUSEHOOKSTRUCT16 *hook;
62 BOOL32 ret;
63 static DWORD lastClickTime = 0;
64 static WORD lastClickMsg = 0;
65 static POINT16 lastClickPos = { 0, 0 };
66 POINT16 pt = msg->pt;
68 BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
69 (msg->message == WM_RBUTTONDOWN) ||
70 (msg->message == WM_MBUTTONDOWN));
72 /* Find the window */
74 if ((msg->hwnd = GetCapture()) != 0)
76 BOOL32 ret;
78 ScreenToClient16( msg->hwnd, &pt );
79 msg->lParam = MAKELONG( pt.x, pt.y );
80 /* No need to further process the message */
82 if (!HOOK_GetHook( WH_MOUSE, GetTaskQueue(0)) ||
83 !(hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16)))
84 return TRUE;
85 hook->pt = msg->pt;
86 hook->hwnd = msg->hwnd;
87 hook->wHitTestCode = HTCLIENT;
88 hook->dwExtraInfo = 0;
89 ret = !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
90 msg->message, (LPARAM)SEGPTR_GET(hook));
91 SEGPTR_FREE(hook);
92 return ret;
95 hittest = WINPOS_WindowFromPoint( msg->pt, &pWnd );
96 if (pWnd->hmemTaskQ != GetTaskQueue(0))
98 /* Not for the current task */
99 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
100 if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
101 /* Wake up the other task */
102 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
103 if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
104 return FALSE;
106 msg->hwnd = pWnd->hwndSelf;
107 if ((hittest != HTERROR) && mouseClick)
109 HWND hwndTop = WIN_GetTopParent( msg->hwnd );
111 /* Send the WM_PARENTNOTIFY message */
113 WIN_SendParentNotify( msg->hwnd, msg->message, 0,
114 MAKELPARAM( msg->pt.x, msg->pt.y ) );
116 /* Activate the window if needed */
118 if (msg->hwnd != GetActiveWindow() && msg->hwnd != GetDesktopWindow())
120 LONG ret = SendMessage16( msg->hwnd, WM_MOUSEACTIVATE, hwndTop,
121 MAKELONG( hittest, msg->message ) );
123 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
124 eatMsg = TRUE;
126 if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
127 && hwndTop != GetActiveWindow() )
128 WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE );
132 /* Send the WM_SETCURSOR message */
134 SendMessage16( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
135 MAKELONG( hittest, msg->message ));
136 if (eatMsg) return FALSE;
138 /* Check for double-click */
140 if (mouseClick)
142 BOOL dbl_click = FALSE;
144 if ((msg->message == lastClickMsg) &&
145 (msg->time - lastClickTime < doubleClickSpeed) &&
146 (abs(msg->pt.x - lastClickPos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
147 (abs(msg->pt.y - lastClickPos.y) < SYSMETRICS_CYDOUBLECLK/2))
148 dbl_click = TRUE;
150 if (dbl_click && (hittest == HTCLIENT))
152 /* Check whether window wants the double click message. */
153 dbl_click = (pWnd->class->style & CS_DBLCLKS) != 0;
156 if (dbl_click) switch(msg->message)
158 case WM_LBUTTONDOWN: msg->message = WM_LBUTTONDBLCLK; break;
159 case WM_RBUTTONDOWN: msg->message = WM_RBUTTONDBLCLK; break;
160 case WM_MBUTTONDOWN: msg->message = WM_MBUTTONDBLCLK; break;
163 if (remove)
165 lastClickTime = msg->time;
166 lastClickMsg = msg->message;
167 lastClickPos = msg->pt;
171 /* Build the translated message */
173 if (hittest == HTCLIENT)
174 ScreenToClient16( msg->hwnd, &pt );
175 else
177 msg->wParam = hittest;
178 msg->message += WM_NCLBUTTONDOWN - WM_LBUTTONDOWN;
180 msg->lParam = MAKELONG( pt.x, pt.y );
182 /* Call the WH_MOUSE hook */
184 if (!HOOK_GetHook( WH_MOUSE, GetTaskQueue(0)) ||
185 !(hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16)))
186 return TRUE;
188 hook->pt = msg->pt;
189 hook->hwnd = msg->hwnd;
190 hook->wHitTestCode = hittest;
191 hook->dwExtraInfo = 0;
192 ret = !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
193 msg->message, (LPARAM)SEGPTR_GET(hook) );
194 SEGPTR_FREE(hook);
195 return ret;
199 /***********************************************************************
200 * MSG_TranslateKeyboardMsg
202 * Translate an keyboard hardware event into a real message.
203 * Return value indicates whether the translated message must be passed
204 * to the user.
206 static BOOL MSG_TranslateKeyboardMsg( MSG16 *msg, BOOL remove )
208 WND *pWnd;
210 /* Should check Ctrl-Esc and PrintScreen here */
212 msg->hwnd = GetFocus();
213 if (!msg->hwnd)
215 /* Send the message to the active window instead, */
216 /* translating messages to their WM_SYS equivalent */
218 msg->hwnd = GetActiveWindow();
220 if( msg->message < WM_SYSKEYDOWN )
221 msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
223 pWnd = WIN_FindWndPtr( msg->hwnd );
224 if (pWnd && (pWnd->hmemTaskQ != GetTaskQueue(0)))
226 /* Not for the current task */
227 MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
228 if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
229 /* Wake up the other task */
230 queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
231 if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
232 return FALSE;
234 return !HOOK_CallHooks( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
235 msg->wParam, msg->lParam );
238 /***********************************************************************
239 * MSG_JournalRecordMsg
241 * Build an EVENTMSG structure and call JOURNALRECORD hook
243 static void MSG_JournalRecordMsg( MSG16 *msg )
245 EVENTMSG16 *event = SEGPTR_NEW(EVENTMSG16);
246 if (!event) return;
247 event->message = msg->message;
248 event->time = msg->time;
249 if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
251 event->paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
252 event->paramH = msg->lParam & 0x7FFF;
253 if (HIWORD(msg->lParam) & 0x0100)
254 event->paramH |= 0x8000; /* special_key - bit */
255 HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0,
256 (LPARAM)SEGPTR_GET(event) );
258 else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
260 event->paramL = LOWORD(msg->lParam); /* X pos */
261 event->paramH = HIWORD(msg->lParam); /* Y pos */
262 ClientToScreen16( msg->hwnd, (LPPOINT16)&event->paramL );
263 HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0,
264 (LPARAM)SEGPTR_GET(event) );
266 else if ((msg->message >= WM_NCMOUSEMOVE) &&
267 (msg->message <= WM_NCMBUTTONDBLCLK))
269 event->paramL = LOWORD(msg->lParam); /* X pos */
270 event->paramH = HIWORD(msg->lParam); /* Y pos */
271 event->message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
272 HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0,
273 (LPARAM)SEGPTR_GET(event) );
275 SEGPTR_FREE(event);
279 /***********************************************************************
280 * MSG_PeekHardwareMsg
282 * Peek for a hardware message matching the hwnd and message filters.
284 static BOOL MSG_PeekHardwareMsg( MSG16 *msg, HWND hwnd, WORD first, WORD last,
285 BOOL remove )
287 MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
288 int i, pos = sysMsgQueue->nextMessage;
290 /* If the queue is empty, attempt to fill it */
291 if (!sysMsgQueue->msgCount && XPending(display)) EVENT_WaitXEvent( FALSE );
293 for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
295 if (pos >= sysMsgQueue->queueSize) pos = 0;
296 *msg = sysMsgQueue->messages[pos].msg;
298 /* Translate message */
300 if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
302 if (!MSG_TranslateMouseMsg( msg, remove )) continue;
304 else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
306 if (!MSG_TranslateKeyboardMsg( msg, remove )) continue;
308 else /* Non-standard hardware event */
310 HARDWAREHOOKSTRUCT16 *hook;
311 if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
313 BOOL32 ret;
314 hook->hWnd = msg->hwnd;
315 hook->wMessage = msg->message;
316 hook->wParam = msg->wParam;
317 hook->lParam = msg->lParam;
318 ret = HOOK_CallHooks( WH_HARDWARE,
319 remove ? HC_ACTION : HC_NOREMOVE,
320 0, (LPARAM)SEGPTR_GET(hook) );
321 SEGPTR_FREE(hook);
322 if (ret) continue;
326 /* Check message against filters */
328 if (hwnd && (msg->hwnd != hwnd)) continue;
329 if ((first || last) &&
330 ((msg->message < first) || (msg->message > last))) continue;
331 if ((msg->hwnd != GetDesktopWindow()) &&
332 (GetWindowTask16(msg->hwnd) != GetCurrentTask()))
333 continue; /* Not for this task */
334 if (remove && HOOK_GetHook( WH_JOURNALRECORD, GetTaskQueue(0) ))
335 MSG_JournalRecordMsg( msg );
336 if (remove) QUEUE_RemoveMsg( sysMsgQueue, pos );
337 return TRUE;
339 return FALSE;
343 /**********************************************************************
344 * SetDoubleClickTime (USER.20)
346 void SetDoubleClickTime( WORD interval )
348 doubleClickSpeed = interval ? interval : 500;
352 /**********************************************************************
353 * GetDoubleClickTime (USER.21)
355 WORD GetDoubleClickTime()
357 return doubleClickSpeed;
361 /***********************************************************************
362 * MSG_SendMessage
364 * Implementation of an inter-task SendMessage.
366 static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND hwnd, UINT msg,
367 WPARAM wParam, LPARAM lParam )
369 MESSAGEQUEUE *queue, *destQ;
371 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return 0;
372 if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
374 if (IsTaskLocked())
376 fprintf( stderr, "SendMessage: task is locked\n" );
377 return 0;
380 if (queue->hWnd)
382 fprintf( stderr, "Nested SendMessage(), msg %04x skipped\n", msg );
383 return 0;
385 queue->hWnd = hwnd;
386 queue->msg = msg;
387 queue->wParam = wParam;
388 queue->lParam = lParam;
389 queue->hPrevSendingTask = destQ->hSendingTask;
390 destQ->hSendingTask = GetTaskQueue(0);
391 QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
393 /* Wait for the result */
395 printf( "SendMessage %04x to %04x\n", msg, hDestQueue );
397 if (!(queue->wakeBits & QS_SMRESULT))
399 DirectedYield( destQ->hTask );
400 QUEUE_WaitBits( QS_SMRESULT );
402 printf( "SendMessage %04x to %04x: got %08lx\n",
403 msg, hDestQueue, queue->SendMessageReturn );
404 queue->wakeBits &= ~QS_SMRESULT;
405 return queue->SendMessageReturn;
409 /***********************************************************************
410 * ReplyMessage (USER.115)
412 void ReplyMessage( LRESULT result )
414 MESSAGEQUEUE *senderQ;
415 MESSAGEQUEUE *queue;
417 printf( "ReplyMessage\n " );
418 if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
419 if (!(senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
420 return;
421 for (;;)
423 if (queue->wakeBits & QS_SENDMESSAGE) QUEUE_ReceiveMessage( queue );
424 else if (senderQ->wakeBits & QS_SMRESULT) Yield();
425 else break;
427 printf( "ReplyMessage: res = %08lx\n", result );
428 senderQ->SendMessageReturn = result;
429 queue->InSendMessageHandle = 0;
430 QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
431 DirectedYield( queue->hSendingTask );
435 /***********************************************************************
436 * MSG_PeekMessage
438 static BOOL MSG_PeekMessage( LPMSG16 msg, HWND hwnd, WORD first, WORD last,
439 WORD flags, BOOL peek )
441 int pos, mask;
442 MESSAGEQUEUE *msgQueue;
443 HQUEUE16 hQueue;
445 #ifdef CONFIG_IPC
446 DDE_TestDDE(hwnd); /* do we have dde handling in the window ?*/
447 DDE_GetRemoteMessage();
448 #endif /* CONFIG_IPC */
450 mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
451 if (first || last)
453 /* MSWord gets stuck if we do not check for nonclient mouse messages */
455 if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
456 if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
457 ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
458 if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
459 if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
460 if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
462 else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
464 if (IsTaskLocked()) flags |= PM_NOYIELD;
466 while(1)
468 hQueue = GetTaskQueue(0);
469 msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
470 if (!msgQueue) return FALSE;
471 msgQueue->changeBits = 0;
473 /* First handle a message put by SendMessage() */
475 if (msgQueue->wakeBits & QS_SENDMESSAGE)
476 QUEUE_ReceiveMessage( msgQueue );
478 /* Now find a normal message */
480 if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
481 ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
483 QMSG *qmsg = &msgQueue->messages[pos];
484 *msg = qmsg->msg;
485 msgQueue->GetMessageTimeVal = msg->time;
486 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
487 msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
489 if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
490 break;
493 /* Now find a hardware event */
495 if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
496 MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
498 /* Got one */
499 msgQueue->GetMessageTimeVal = msg->time;
500 msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt;
501 msgQueue->GetMessageExtraInfoVal = 0; /* Always 0 for now */
502 break;
505 /* Now handle a WM_QUIT message */
507 if (msgQueue->wPostQMsg)
509 msg->hwnd = hwnd;
510 msg->message = WM_QUIT;
511 msg->wParam = msgQueue->wExitCode;
512 msg->lParam = 0;
513 break;
516 /* Check again for SendMessage */
518 if (msgQueue->wakeBits & QS_SENDMESSAGE)
519 QUEUE_ReceiveMessage( msgQueue );
521 /* Now find a WM_PAINT message */
523 if ((msgQueue->wakeBits & mask) & QS_PAINT)
525 WND* wndPtr;
526 msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
527 msg->message = WM_PAINT;
528 msg->wParam = 0;
529 msg->lParam = 0;
531 if ((wndPtr = WIN_FindWndPtr(msg->hwnd)))
533 if( wndPtr->dwStyle & WS_MINIMIZE &&
534 wndPtr->class->hIcon )
536 msg->message = WM_PAINTICON;
537 msg->wParam = 1;
540 if( !hwnd || msg->hwnd == hwnd || IsChild(hwnd,msg->hwnd) )
542 if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
544 wndPtr->flags &= ~WIN_INTERNAL_PAINT;
545 QUEUE_DecPaintCount( hQueue );
547 break;
552 /* Check for timer messages, but yield first */
554 if (!(flags & PM_NOYIELD))
556 UserYield();
557 if (msgQueue->wakeBits & QS_SENDMESSAGE)
558 QUEUE_ReceiveMessage( msgQueue );
560 if ((msgQueue->wakeBits & mask) & QS_TIMER)
562 if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
565 if (peek)
567 if (!(flags & PM_NOYIELD)) UserYield();
568 return FALSE;
570 msgQueue->wakeMask = mask;
571 QUEUE_WaitBits( mask );
574 /* We got a message */
575 if (peek) return TRUE;
576 else return (msg->message != WM_QUIT);
580 /***********************************************************************
581 * MSG_InternalGetMessage
583 * GetMessage() function for internal use. Behave like GetMessage(),
584 * but also call message filters and optionally send WM_ENTERIDLE messages.
585 * 'hwnd' must be the handle of the dialog or menu window.
586 * 'code' is the message filter value (MSGF_??? codes).
588 BOOL MSG_InternalGetMessage( MSG16 *msg, HWND hwnd, HWND hwndOwner, short code,
589 WORD flags, BOOL sendIdle )
591 for (;;)
593 if (sendIdle)
595 if (!MSG_PeekMessage( msg, 0, 0, 0, flags, TRUE ))
597 /* No message present -> send ENTERIDLE and wait */
598 if (IsWindow(hwndOwner))
599 SendMessage16( hwndOwner, WM_ENTERIDLE,
600 code, (LPARAM)hwnd );
601 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
604 else /* Always wait for a message */
605 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
607 /* Call message filters */
609 if (HOOK_GetHook( WH_SYSMSGFILTER, GetTaskQueue(0) ) ||
610 HOOK_GetHook( WH_MSGFILTER, GetTaskQueue(0) ))
612 MSG16 *pmsg = SEGPTR_NEW(MSG16);
613 if (pmsg)
615 BOOL32 ret;
616 *pmsg = *msg;
617 ret = (HOOK_CallHooks( WH_SYSMSGFILTER, code, 0,
618 (LPARAM)SEGPTR_GET(pmsg) ) ||
619 HOOK_CallHooks( WH_MSGFILTER, code, 0,
620 (LPARAM)SEGPTR_GET(pmsg) ));
621 SEGPTR_FREE(pmsg);
622 if (ret)
624 /* Message filtered -> remove it from the queue */
625 /* if it's still there. */
626 if (!(flags & PM_REMOVE))
627 MSG_PeekMessage( msg, 0, 0, 0, PM_REMOVE, TRUE );
628 continue;
633 return (msg->message != WM_QUIT);
638 /***********************************************************************
639 * PeekMessage16 (USER.109)
641 BOOL16 PeekMessage16( LPMSG16 msg, HWND16 hwnd, UINT16 first,
642 UINT16 last, UINT16 flags )
644 return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
648 /***********************************************************************
649 * GetMessage (USER.108)
651 BOOL GetMessage( SEGPTR msg, HWND hwnd, UINT first, UINT last )
653 MSG16 *lpmsg = (MSG16 *)PTR_SEG_TO_LIN(msg);
654 MSG_PeekMessage( lpmsg,
655 hwnd, first, last, PM_REMOVE, FALSE );
657 dprintf_msg(stddeb,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg->message,
658 hwnd, first, last );
659 HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
660 return (lpmsg->message != WM_QUIT);
664 /***********************************************************************
665 * PostMessage (USER.110)
667 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
669 MSG16 msg;
670 WND *wndPtr;
672 msg.hwnd = hwnd;
673 msg.message = message;
674 msg.wParam = wParam;
675 msg.lParam = lParam;
676 msg.time = GetTickCount();
677 msg.pt.x = 0;
678 msg.pt.y = 0;
680 #ifdef CONFIG_IPC
681 if (DDE_PostMessage(&msg))
682 return TRUE;
683 #endif /* CONFIG_IPC */
685 if (hwnd == HWND_BROADCAST16)
687 dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
688 for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
690 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
692 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
693 wndPtr->hwndSelf, message, wParam, lParam);
694 PostMessage( wndPtr->hwndSelf, message, wParam, lParam );
697 dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
698 return TRUE;
701 wndPtr = WIN_FindWndPtr( hwnd );
702 if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
704 return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
707 /***********************************************************************
708 * PostAppMessage (USER.116)
710 BOOL PostAppMessage( HTASK hTask, WORD message, WORD wParam, LONG lParam )
712 MSG16 msg;
714 if (GetTaskQueue(hTask) == 0) return FALSE;
715 msg.hwnd = 0;
716 msg.message = message;
717 msg.wParam = wParam;
718 msg.lParam = lParam;
719 msg.time = GetTickCount();
720 msg.pt.x = 0;
721 msg.pt.y = 0;
723 return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
727 /***********************************************************************
728 * SendMessage16 (USER.111)
730 LRESULT SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam)
732 WND * wndPtr;
733 LRESULT ret;
735 #ifdef CONFIG_IPC
736 MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
737 if (DDE_SendMessage(&DDE_msg)) return TRUE;
738 #endif /* CONFIG_IPC */
740 if (hwnd == HWND_BROADCAST16)
742 dprintf_msg(stddeb,"SendMessage // HWND_BROADCAST !\n");
743 for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
745 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
747 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
748 wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
749 SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
752 dprintf_msg(stddeb,"SendMessage // End of HWND_BROADCAST !\n");
753 return TRUE;
756 if (HOOK_GetHook( WH_CALLWNDPROC, GetTaskQueue(0) ))
758 struct msgstruct
760 LPARAM lParam;
761 WPARAM16 wParam;
762 UINT16 wMsg;
763 HWND16 hWnd;
764 } *pmsg;
766 if ((pmsg = SEGPTR_NEW(struct msgstruct)))
768 pmsg->hWnd = hwnd;
769 pmsg->wMsg = msg;
770 pmsg->wParam = wParam;
771 pmsg->lParam = lParam;
772 HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 1,
773 (LPARAM)SEGPTR_GET(pmsg) );
774 hwnd = pmsg->hWnd;
775 msg = pmsg->wMsg;
776 wParam = pmsg->wParam;
777 lParam = pmsg->lParam;
781 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
783 fprintf( stderr, "SendMessage16: invalid hwnd %04x\n", hwnd );
784 return 0;
786 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
787 return 0; /* Don't send anything if the task is dying */
788 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
789 return MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam );
791 SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
792 ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
793 hwnd, msg, wParam, lParam );
794 SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
795 return ret;
799 /***********************************************************************
800 * SendMessage32A (USER32.453)
802 LRESULT SendMessage32A(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
804 WND * wndPtr;
805 LRESULT ret;
807 if (hwnd == HWND_BROADCAST32)
809 for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
811 /* FIXME: should use something like EnumWindows here */
812 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
813 SendMessage32A( wndPtr->hwndSelf, msg, wParam, lParam );
815 return TRUE;
818 /* FIXME: call hooks */
820 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
822 fprintf( stderr, "SendMessage32A: invalid hwnd %08x\n", hwnd );
823 return 0;
826 if (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_16)
828 /* Use SendMessage16 for now to get hooks right */
829 UINT16 msg16;
830 WPARAM16 wParam16;
831 if (WINPROC_MapMsg32ATo16( msg, wParam, &msg16, &wParam16, &lParam ) == -1)
832 return 0;
833 ret = SendMessage16( hwnd, msg16, wParam16, lParam );
834 WINPROC_UnmapMsg32ATo16( msg16, wParam16, lParam );
835 return ret;
838 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
839 return 0; /* Don't send anything if the task is dying */
841 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
843 fprintf( stderr, "SendMessage32A: intertask message not supported\n" );
844 return 0;
847 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
848 ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
849 hwnd, msg, wParam, lParam );
850 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
851 return ret;
855 /***********************************************************************
856 * SendMessage32W (USER32.458)
858 LRESULT SendMessage32W(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
860 WND * wndPtr;
861 LRESULT ret;
863 if (hwnd == HWND_BROADCAST32)
865 for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
867 /* FIXME: should use something like EnumWindows here */
868 if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
869 SendMessage32W( wndPtr->hwndSelf, msg, wParam, lParam );
871 return TRUE;
874 /* FIXME: call hooks */
876 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
878 fprintf( stderr, "SendMessage32W: invalid hwnd %08x\n", hwnd );
879 return 0;
881 if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
882 return 0; /* Don't send anything if the task is dying */
883 if (wndPtr->hmemTaskQ != GetTaskQueue(0))
885 fprintf( stderr, "SendMessage32W: intertask message not supported\n" );
886 return 0;
889 SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
890 ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
891 hwnd, msg, wParam, lParam );
892 SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
893 return ret;
897 /***********************************************************************
898 * WaitMessage (USER.112)
900 void WaitMessage( void )
902 QUEUE_WaitBits( QS_ALLINPUT );
906 /***********************************************************************
907 * TranslateMessage (USER.113)
909 * This should call ToAscii but it is currently broken
912 #define ASCII_CHAR_HACK 0x0800
914 BOOL TranslateMessage( LPMSG16 msg )
916 UINT message = msg->message;
917 /* BYTE wparam[2]; */
919 if ((message == WM_KEYDOWN) || (message == WM_KEYUP) ||
920 (message == WM_SYSKEYDOWN) || (message == WM_SYSKEYUP))
922 dprintf_msg(stddeb, "Translating key %04x, scancode %04x\n", msg->wParam,
923 HIWORD(msg->lParam) );
925 if( HIWORD(msg->lParam) & ASCII_CHAR_HACK )
927 /* if( ToAscii( msg->wParam, HIWORD(msg->lParam), (LPSTR)&KeyStateTable,
928 wparam, 0 ) )
931 message += 2 - (message & 0x0001);
933 PostMessage( msg->hwnd, message, lastEventChar, msg->lParam );
935 return TRUE;
938 return FALSE;
942 /***********************************************************************
943 * DispatchMessage (USER.114)
945 LONG DispatchMessage( const MSG16* msg )
947 WND * wndPtr;
948 LONG retval;
949 int painting;
951 /* Process timer messages */
952 if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
954 if (msg->lParam)
956 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
957 return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
958 msg->message, msg->wParam, GetTickCount() );
962 if (!msg->hwnd) return 0;
963 if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
964 if (!wndPtr->winproc) return 0;
965 painting = (msg->message == WM_PAINT);
966 if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
967 /* HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
969 SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
970 msg->wParam, msg->lParam );
971 retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
972 msg->hwnd, msg->message,
973 msg->wParam, msg->lParam );
974 SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval );
976 if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
977 (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
979 fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n",
980 msg->hwnd);
981 wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
982 /* Validate the update region to avoid infinite WM_PAINT loop */
983 ValidateRect32( msg->hwnd, NULL );
985 return retval;
989 /***********************************************************************
990 * RegisterWindowMessage16 (USER.118)
992 WORD RegisterWindowMessage16( SEGPTR str )
994 dprintf_msg(stddeb, "RegisterWindowMessage16: %08lx\n", (DWORD)str );
995 return GlobalAddAtom16( str );
999 /***********************************************************************
1000 * RegisterWindowMessage32A (USER32.436)
1002 WORD RegisterWindowMessage32A( LPCSTR str )
1004 dprintf_msg(stddeb, "RegisterWindowMessage32A: %s\n", str );
1005 return GlobalAddAtom32A( str );
1009 /***********************************************************************
1010 * RegisterWindowMessage32W (USER32.437)
1012 WORD RegisterWindowMessage32W( LPCWSTR str )
1014 dprintf_msg(stddeb, "RegisterWindowMessage32W: %p\n", str );
1015 return GlobalAddAtom32W( str );
1019 /***********************************************************************
1020 * GetTickCount (USER.13) (KERNEL32.299)
1022 DWORD GetTickCount(void)
1024 struct timeval t;
1025 gettimeofday( &t, NULL );
1026 return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
1030 /***********************************************************************
1031 * GetCurrentTime (USER.15)
1033 * (effectively identical to GetTickCount)
1035 DWORD GetCurrentTime(void)
1037 return GetTickCount();
1041 /***********************************************************************
1042 * InSendMessage (USER.192)
1044 BOOL InSendMessage()
1046 MESSAGEQUEUE *queue;
1048 if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
1049 return 0;
1050 return (BOOL)queue->InSendMessageHandle;