Release 960805
[wine] / windows / message.c
1 /*
2  * Message queues related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/time.h>
10 #include <sys/types.h>
11
12 #include "message.h"
13 #include "win.h"
14 #include "gdi.h"
15 #include "sysmetrics.h"
16 #include "hook.h"
17 #include "spy.h"
18 #include "stackframe.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"
27
28 #define WM_NCMOUSEFIRST         WM_NCMOUSEMOVE
29 #define WM_NCMOUSELAST          WM_NCMBUTTONDBLCLK
30
31 #define HWND_BROADCAST16  ((HWND16)0xffff)
32 #define HWND_BROADCAST32  ((HWND32)0xffffffff)
33
34 extern BYTE*    KeyStateTable;                           /* event.c */
35 extern WPARAM   lastEventChar;                           /* event.c */
36
37 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
38
39 static WORD doubleClickSpeed = 452;
40
41 /***********************************************************************
42  *           MSG_TranslateMouseMsg
43  *
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.
55  */
56 static BOOL MSG_TranslateMouseMsg( MSG16 *msg, BOOL remove )
57 {
58     WND *pWnd;
59     BOOL eatMsg = FALSE;
60     INT16 hittest;
61     static DWORD lastClickTime = 0;
62     static WORD  lastClickMsg = 0;
63     static POINT16 lastClickPos = { 0, 0 };
64     POINT16 pt = msg->pt;
65     MOUSEHOOKSTRUCT16 hook = { msg->pt, 0, HTCLIENT, 0 };
66
67     BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
68                        (msg->message == WM_RBUTTONDOWN) ||
69                        (msg->message == WM_MBUTTONDOWN));
70
71       /* Find the window */
72
73     if ((msg->hwnd = GetCapture()) != 0)
74     {
75         ScreenToClient16( msg->hwnd, &pt );
76         msg->lParam = MAKELONG( pt.x, pt.y );
77         /* No need to further process the message */
78         hook.hwnd = msg->hwnd;
79         return !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
80                                 msg->message, (LPARAM)MAKE_SEGPTR(&hook));
81     }
82    
83     hittest = WINPOS_WindowFromPoint( msg->pt, &pWnd );
84     if (pWnd->hmemTaskQ != GetTaskQueue(0))
85     {
86         /* Not for the current task */
87         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
88         if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
89         /* Wake up the other task */
90         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
91         if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
92         return FALSE;
93     }
94     msg->hwnd = pWnd->hwndSelf;
95     if ((hittest != HTERROR) && mouseClick)
96     {
97         HWND hwndTop = WIN_GetTopParent( msg->hwnd );
98
99         /* Send the WM_PARENTNOTIFY message */
100
101         WIN_SendParentNotify( msg->hwnd, msg->message, 0,
102                               MAKELONG( msg->pt.x, msg->pt.y ) );
103
104         /* Activate the window if needed */
105
106         if (msg->hwnd != GetActiveWindow() && msg->hwnd != GetDesktopWindow())
107         {
108             LONG ret = SendMessage16( msg->hwnd, WM_MOUSEACTIVATE, hwndTop,
109                                     MAKELONG( hittest, msg->message ) );
110
111             if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
112                 eatMsg = TRUE;
113
114             if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT)) 
115                 && hwndTop != GetActiveWindow() )
116                 WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE );
117         }
118     }
119
120       /* Send the WM_SETCURSOR message */
121
122     SendMessage16( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
123                    MAKELONG( hittest, msg->message ));
124     if (eatMsg) return FALSE;
125
126       /* Check for double-click */
127
128     if (mouseClick)
129     {
130         BOOL dbl_click = FALSE;
131
132         if ((msg->message == lastClickMsg) &&
133             (msg->time - lastClickTime < doubleClickSpeed) &&
134             (abs(msg->pt.x - lastClickPos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
135             (abs(msg->pt.y - lastClickPos.y) < SYSMETRICS_CYDOUBLECLK/2))
136             dbl_click = TRUE;
137
138         if (dbl_click && (hittest == HTCLIENT))
139         {
140             /* Check whether window wants the double click message. */
141             dbl_click = (pWnd->class->style & CS_DBLCLKS) != 0;
142         }
143
144         if (dbl_click) switch(msg->message)
145         {
146             case WM_LBUTTONDOWN: msg->message = WM_LBUTTONDBLCLK; break;
147             case WM_RBUTTONDOWN: msg->message = WM_RBUTTONDBLCLK; break;
148             case WM_MBUTTONDOWN: msg->message = WM_MBUTTONDBLCLK; break;
149         }
150
151         if (remove)
152         {
153             lastClickTime = msg->time;
154             lastClickMsg  = msg->message;
155             lastClickPos  = msg->pt;
156         }
157     }
158
159       /* Build the translated message */
160
161     if (hittest == HTCLIENT)
162         ScreenToClient16( msg->hwnd, &pt );
163     else
164     {
165         msg->wParam = hittest;
166         msg->message += WM_NCLBUTTONDOWN - WM_LBUTTONDOWN;
167     }
168     msg->lParam = MAKELONG( pt.x, pt.y );
169     
170     hook.hwnd = msg->hwnd;
171     hook.wHitTestCode = hittest;
172     return !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
173                             msg->message, (LPARAM)MAKE_SEGPTR(&hook));
174 }
175
176
177 /***********************************************************************
178  *           MSG_TranslateKeyboardMsg
179  *
180  * Translate an keyboard hardware event into a real message.
181  * Return value indicates whether the translated message must be passed
182  * to the user.
183  */
184 static BOOL MSG_TranslateKeyboardMsg( MSG16 *msg, BOOL remove )
185 {
186     WND *pWnd;
187
188       /* Should check Ctrl-Esc and PrintScreen here */
189
190     msg->hwnd = GetFocus();
191     if (!msg->hwnd)
192     {
193           /* Send the message to the active window instead,  */
194           /* translating messages to their WM_SYS equivalent */
195
196         msg->hwnd = GetActiveWindow();
197
198         if( msg->message < WM_SYSKEYDOWN )
199             msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
200     }
201     pWnd = WIN_FindWndPtr( msg->hwnd );
202     if (pWnd && (pWnd->hmemTaskQ != GetTaskQueue(0)))
203     {
204         /* Not for the current task */
205         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
206         if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
207         /* Wake up the other task */
208         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
209         if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
210         return FALSE;
211     }
212     return !HOOK_CallHooks( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
213                             msg->wParam, msg->lParam );
214 }
215
216
217 /***********************************************************************
218  *           MSG_PeekHardwareMsg
219  *
220  * Peek for a hardware message matching the hwnd and message filters.
221  */
222 static BOOL MSG_PeekHardwareMsg( MSG16 *msg, HWND hwnd, WORD first, WORD last,
223                                  BOOL remove )
224 {
225     MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
226     int i, pos = sysMsgQueue->nextMessage;
227
228     /* If the queue is empty, attempt to fill it */
229     if (!sysMsgQueue->msgCount && XPending(display)) EVENT_WaitXEvent( FALSE );
230
231     for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
232     {
233         if (pos >= sysMsgQueue->queueSize) pos = 0;
234         *msg = sysMsgQueue->messages[pos].msg;
235
236           /* Translate message */
237
238         if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
239         {
240             if (!MSG_TranslateMouseMsg( msg, remove )) continue;
241         }
242         else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
243         {
244             if (!MSG_TranslateKeyboardMsg( msg, remove )) continue;
245         }
246         else  /* Non-standard hardware event */
247         {
248             HARDWAREHOOKSTRUCT16 hook = { msg->hwnd, msg->message,
249                                           msg->wParam, msg->lParam };
250             if (HOOK_CallHooks( WH_HARDWARE, remove ? HC_ACTION : HC_NOREMOVE,
251                                 0, (LPARAM)MAKE_SEGPTR(&hook) )) continue;
252         }
253
254           /* Check message against filters */
255
256         if (hwnd && (msg->hwnd != hwnd)) continue;
257         if ((first || last) && 
258             ((msg->message < first) || (msg->message > last))) continue;
259         if ((msg->hwnd != GetDesktopWindow()) && 
260             (GetWindowTask16(msg->hwnd) != GetCurrentTask()))
261             continue;  /* Not for this task */
262         if (remove)
263         {
264             MSG16 tmpMsg = *msg; /* FIXME */
265             HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION,
266                             0, (LPARAM)MAKE_SEGPTR(&tmpMsg) );
267             QUEUE_RemoveMsg( sysMsgQueue, pos );
268         }
269         return TRUE;
270     }
271     return FALSE;
272 }
273
274
275 /**********************************************************************
276  *           SetDoubleClickTime   (USER.20)
277  */
278 void SetDoubleClickTime( WORD interval )
279 {
280     doubleClickSpeed = interval ? interval : 500;
281 }               
282
283
284 /**********************************************************************
285  *           GetDoubleClickTime   (USER.21)
286  */
287 WORD GetDoubleClickTime()
288 {
289     return doubleClickSpeed;
290 }               
291
292
293 /***********************************************************************
294  *           MSG_SendMessage
295  *
296  * Implementation of an inter-task SendMessage.
297  */
298 static LRESULT MSG_SendMessage( HQUEUE hDestQueue, HWND hwnd, UINT msg,
299                          WPARAM wParam, LPARAM lParam )
300 {
301     MESSAGEQUEUE *queue, *destQ;
302
303     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return 0;
304     if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
305
306     if (IsTaskLocked())
307     {
308         fprintf( stderr, "SendMessage: task is locked\n" );
309         return 0;
310     }
311
312     if (queue->hWnd)
313     {
314         fprintf( stderr, "Nested SendMessage() not supported\n" );
315         return 0;
316     }
317     queue->hWnd   = hwnd;
318     queue->msg    = msg;
319     queue->wParam = wParam;
320     queue->lParam = lParam;
321     queue->hPrevSendingTask = destQ->hSendingTask;
322     destQ->hSendingTask = GetTaskQueue(0);
323     QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
324
325     /* Wait for the result */
326
327     printf( "SendMessage %04x to %04x\n", msg, hDestQueue );
328
329     if (!(queue->wakeBits & QS_SMRESULT))
330     {
331         DirectedYield( destQ->hTask );
332         QUEUE_WaitBits( QS_SMRESULT );
333     }
334     printf( "SendMessage %04x to %04x: got %08lx\n",
335             msg, hDestQueue, queue->SendMessageReturn );
336     queue->wakeBits &= ~QS_SMRESULT;
337     return queue->SendMessageReturn;
338 }
339
340
341 /***********************************************************************
342  *           ReplyMessage   (USER.115)
343  */
344 void ReplyMessage( LRESULT result )
345 {
346     MESSAGEQUEUE *senderQ;
347     MESSAGEQUEUE *queue;
348
349     printf( "ReplyMessage\n " );
350     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
351     if (!(senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
352         return;
353     for (;;)
354     {
355         if (queue->wakeBits & QS_SENDMESSAGE) QUEUE_ReceiveMessage( queue );
356         else if (senderQ->wakeBits & QS_SMRESULT) Yield();
357         else break;
358     }
359     printf( "ReplyMessage: res = %08lx\n", result );
360     senderQ->SendMessageReturn = result;
361     queue->InSendMessageHandle = 0;
362     QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
363     DirectedYield( queue->hSendingTask );
364 }
365
366
367 /***********************************************************************
368  *           MSG_PeekMessage
369  */
370 static BOOL MSG_PeekMessage( LPMSG16 msg, HWND hwnd, WORD first, WORD last,
371                              WORD flags, BOOL peek )
372 {
373     int pos, mask;
374     MESSAGEQUEUE *msgQueue;
375     HQUEUE        hQueue;
376
377 #ifdef CONFIG_IPC
378     DDE_TestDDE(hwnd);  /* do we have dde handling in the window ?*/
379     DDE_GetRemoteMessage();
380 #endif  /* CONFIG_IPC */
381
382     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
383     if (first || last)
384     {
385         /* MSWord gets stuck if we do not check for nonclient mouse messages */
386
387         if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
388         if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
389              ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
390         if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
391         if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
392         if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
393     }
394     else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
395
396     if (IsTaskLocked()) flags |= PM_NOYIELD;
397
398     while(1)
399     {    
400         hQueue   = GetTaskQueue(0);
401         msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
402         if (!msgQueue) return FALSE;
403         msgQueue->changeBits = 0;
404
405         /* First handle a message put by SendMessage() */
406
407         if (msgQueue->wakeBits & QS_SENDMESSAGE)
408             QUEUE_ReceiveMessage( msgQueue );
409     
410         /* Now find a normal message */
411
412         if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
413             ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
414         {
415             QMSG *qmsg = &msgQueue->messages[pos];
416             *msg = qmsg->msg;
417             msgQueue->GetMessageTimeVal      = msg->time;
418             msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
419             msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
420
421             if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
422             break;
423         }
424
425         /* Now find a hardware event */
426
427         if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
428             MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
429         {
430             /* Got one */
431             msgQueue->GetMessageTimeVal      = msg->time;
432             msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
433             msgQueue->GetMessageExtraInfoVal = 0;  /* Always 0 for now */
434             break;
435         }
436
437         /* Now handle a WM_QUIT message */
438
439         if (msgQueue->wPostQMsg)
440         {
441             msg->hwnd    = hwnd;
442             msg->message = WM_QUIT;
443             msg->wParam  = msgQueue->wExitCode;
444             msg->lParam  = 0;
445             break;
446         }
447
448         /* Check again for SendMessage */
449
450         if (msgQueue->wakeBits & QS_SENDMESSAGE)
451             QUEUE_ReceiveMessage( msgQueue );
452
453         /* Now find a WM_PAINT message */
454
455         if ((msgQueue->wakeBits & mask) & QS_PAINT)
456         {
457             msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
458             msg->message = WM_PAINT;
459             msg->wParam = 0;
460             msg->lParam = 0;
461             if( msg->hwnd &&
462               (!hwnd || msg->hwnd == hwnd || IsChild(hwnd,msg->hwnd)) )
463               {
464                 WND* wndPtr = WIN_FindWndPtr(msg->hwnd);
465
466                 /* FIXME: WM_PAINTICON should be sent sometimes */
467
468                 if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
469                   {
470                     wndPtr->flags &= ~WIN_INTERNAL_PAINT;
471                     QUEUE_DecPaintCount( hQueue );
472                   }
473                 break;
474               }
475         }
476
477         /* Check for timer messages, but yield first */
478
479         if (!(flags & PM_NOYIELD))
480         {
481             UserYield();
482             if (msgQueue->wakeBits & QS_SENDMESSAGE)
483                 QUEUE_ReceiveMessage( msgQueue );
484         }
485         if ((msgQueue->wakeBits & mask) & QS_TIMER)
486         {
487             if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
488         }
489
490         if (peek)
491         {
492             if (!(flags & PM_NOYIELD)) UserYield();
493             return FALSE;
494         }
495         msgQueue->wakeMask = mask;
496         QUEUE_WaitBits( mask );
497     }
498
499       /* We got a message */
500     if (peek) return TRUE;
501     else return (msg->message != WM_QUIT);
502 }
503
504
505 /***********************************************************************
506  *           MSG_InternalGetMessage
507  *
508  * GetMessage() function for internal use. Behave like GetMessage(),
509  * but also call message filters and optionally send WM_ENTERIDLE messages.
510  * 'hwnd' must be the handle of the dialog or menu window.
511  * 'code' is the message filter value (MSGF_??? codes).
512  */
513 BOOL MSG_InternalGetMessage( SEGPTR msg, HWND hwnd, HWND hwndOwner, short code,
514                              WORD flags, BOOL sendIdle ) 
515 {
516     for (;;)
517     {
518         if (sendIdle)
519         {
520             if (!MSG_PeekMessage( (MSG16 *)PTR_SEG_TO_LIN(msg),
521                                   0, 0, 0, flags, TRUE ))
522             {
523                   /* No message present -> send ENTERIDLE and wait */
524                 if (IsWindow(hwndOwner))
525                     SendMessage16( hwndOwner, WM_ENTERIDLE,
526                                    code, (LPARAM)hwnd );
527                 MSG_PeekMessage( (MSG16 *)PTR_SEG_TO_LIN(msg),
528                                  0, 0, 0, flags, FALSE );
529             }
530         }
531         else  /* Always wait for a message */
532             MSG_PeekMessage( (MSG16 *)PTR_SEG_TO_LIN(msg),
533                              0, 0, 0, flags, FALSE );
534
535         if (!CallMsgFilter( msg, code ))
536             return (((MSG16 *)PTR_SEG_TO_LIN(msg))->message != WM_QUIT);
537
538           /* Message filtered -> remove it from the queue */
539           /* if it's still there. */
540         if (!(flags & PM_REMOVE))
541             MSG_PeekMessage( (MSG16 *)PTR_SEG_TO_LIN(msg),
542                              0, 0, 0, PM_REMOVE, TRUE );
543     }
544 }
545
546
547 /***********************************************************************
548  *           PeekMessage16   (USER.109)
549  */
550 BOOL16 PeekMessage16( LPMSG16 msg, HWND16 hwnd, UINT16 first,
551                       UINT16 last, UINT16 flags )
552 {
553     return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
554 }
555
556
557 /***********************************************************************
558  *           GetMessage   (USER.108)
559  */
560 BOOL GetMessage( SEGPTR msg, HWND hwnd, UINT first, UINT last ) 
561 {
562     MSG16 *lpmsg = (MSG16 *)PTR_SEG_TO_LIN(msg);
563     MSG_PeekMessage( lpmsg,
564                      hwnd, first, last, PM_REMOVE, FALSE );
565
566     dprintf_msg(stddeb,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg->message,
567                                                                  hwnd, first, last );
568     HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
569     return (lpmsg->message != WM_QUIT);
570 }
571
572
573 /***********************************************************************
574  *           PostMessage   (USER.110)
575  */
576 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
577 {
578     MSG16       msg;
579     WND         *wndPtr;
580
581     msg.hwnd    = hwnd;
582     msg.message = message;
583     msg.wParam  = wParam;
584     msg.lParam  = lParam;
585     msg.time    = GetTickCount();
586     msg.pt.x    = 0;
587     msg.pt.y    = 0;
588
589 #ifdef CONFIG_IPC
590     if (DDE_PostMessage(&msg))
591        return TRUE;
592 #endif  /* CONFIG_IPC */
593     
594     if (hwnd == HWND_BROADCAST16)
595     {
596         dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
597         for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
598         {
599             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
600             {
601                 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
602                             wndPtr->hwndSelf, message, wParam, lParam);
603                 PostMessage( wndPtr->hwndSelf, message, wParam, lParam );
604             }
605         }
606         dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
607         return TRUE;
608     }
609
610     wndPtr = WIN_FindWndPtr( hwnd );
611     if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
612
613     return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
614 }
615
616 /***********************************************************************
617  *           PostAppMessage   (USER.116)
618  */
619 BOOL PostAppMessage( HTASK hTask, WORD message, WORD wParam, LONG lParam )
620 {
621     MSG16 msg;
622
623     if (GetTaskQueue(hTask) == 0) return FALSE;
624     msg.hwnd    = 0;
625     msg.message = message;
626     msg.wParam  = wParam;
627     msg.lParam  = lParam;
628     msg.time    = GetTickCount();
629     msg.pt.x    = 0;
630     msg.pt.y    = 0;
631
632     return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
633 }
634
635
636 /***********************************************************************
637  *           SendMessage16   (USER.111)
638  */
639 LRESULT SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam)
640 {
641     WND * wndPtr;
642     LRESULT ret;
643     struct
644     {
645         LPARAM   lParam;
646         WPARAM16 wParam;
647         UINT16   wMsg;
648         HWND16   hWnd;
649     } msgstruct = { lParam, wParam, msg, hwnd };
650
651 #ifdef CONFIG_IPC
652     MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
653     if (DDE_SendMessage(&DDE_msg)) return TRUE;
654 #endif  /* CONFIG_IPC */
655
656     if (hwnd == HWND_BROADCAST16)
657     {
658         dprintf_msg(stddeb,"SendMessage // HWND_BROADCAST !\n");
659         for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
660         {
661             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
662             {
663                 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
664                             wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
665                 SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
666             }
667         }
668         dprintf_msg(stddeb,"SendMessage // End of HWND_BROADCAST !\n");
669         return TRUE;
670     }
671
672     HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 1,
673                     (LPARAM)MAKE_SEGPTR(&msgstruct) );
674     hwnd   = msgstruct.hWnd;
675     msg    = msgstruct.wMsg;
676     wParam = msgstruct.wParam;
677     lParam = msgstruct.lParam;
678
679     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
680     {
681         fprintf( stderr, "SendMessage16: invalid hwnd %04x\n", hwnd );
682         return 0;
683     }
684     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
685         return MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam );
686
687     SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
688     ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
689                             hwnd, msg, wParam, lParam );
690     SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
691     return ret;
692 }
693
694
695 /***********************************************************************
696  *           SendMessage32A   (USER32.453)
697  */
698 LRESULT SendMessage32A(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
699 {
700     WND * wndPtr;
701     LRESULT ret;
702
703     if (hwnd == HWND_BROADCAST32)
704     {
705         for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
706         {
707             /* FIXME: should use something like EnumWindows here */
708             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
709                 SendMessage32A( wndPtr->hwndSelf, msg, wParam, lParam );
710         }
711         return TRUE;
712     }
713
714     /* FIXME: call hooks */
715
716     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
717     {
718         fprintf( stderr, "SendMessage32A: invalid hwnd %08x\n", hwnd );
719         return 0;
720     }
721
722     if (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_16)
723     {
724         /* Use SendMessage16 for now to get hooks right */
725         UINT16 msg16;
726         WPARAM16 wParam16;
727         if (WINPROC_MapMsg32ATo16( msg, wParam, &msg16, &wParam16, &lParam ) == -1)
728             return 0;
729         ret = SendMessage16( hwnd, msg16, wParam16, lParam );
730         WINPROC_UnmapMsg32ATo16( msg16, wParam16, lParam );
731         return ret;
732     }
733
734     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
735     {
736         fprintf( stderr, "SendMessage32A: intertask message not supported\n" );
737         return 0;
738     }
739
740     SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
741     ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
742                              hwnd, msg, wParam, lParam );
743     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
744     return ret;
745 }
746
747
748 /***********************************************************************
749  *           SendMessage32W   (USER32.458)
750  */
751 LRESULT SendMessage32W(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
752 {
753     WND * wndPtr;
754     LRESULT ret;
755
756     if (hwnd == HWND_BROADCAST32)
757     {
758         for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
759         {
760             /* FIXME: should use something like EnumWindows here */
761             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
762                 SendMessage32W( wndPtr->hwndSelf, msg, wParam, lParam );
763         }
764         return TRUE;
765     }
766
767     /* FIXME: call hooks */
768
769     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
770     {
771         fprintf( stderr, "SendMessage32W: invalid hwnd %08x\n", hwnd );
772         return 0;
773     }
774     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
775     {
776         fprintf( stderr, "SendMessage32W: intertask message not supported\n" );
777         return 0;
778     }
779
780     SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
781     ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
782                              hwnd, msg, wParam, lParam );
783     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
784     return ret;
785 }
786
787
788 /***********************************************************************
789  *           WaitMessage    (USER.112)
790  */
791 void WaitMessage( void )
792 {
793     QUEUE_WaitBits( QS_ALLINPUT );
794 }
795
796
797 /***********************************************************************
798  *           TranslateMessage   (USER.113)
799  *
800  * This should call ToAscii but it is currently broken
801  */
802
803 #define ASCII_CHAR_HACK 0x0800
804
805 BOOL TranslateMessage( LPMSG16 msg )
806 {
807     UINT message = msg->message;
808     /* BYTE wparam[2]; */
809     
810     if ((message == WM_KEYDOWN) || (message == WM_KEYUP) ||
811         (message == WM_SYSKEYDOWN) || (message == WM_SYSKEYUP))
812     {
813         dprintf_msg(stddeb, "Translating key %04x, scancode %04x\n", msg->wParam, 
814                                                               HIWORD(msg->lParam) );
815
816         if( HIWORD(msg->lParam) & ASCII_CHAR_HACK )
817
818         /*  if( ToAscii( msg->wParam, HIWORD(msg->lParam), (LPSTR)&KeyStateTable,
819                                       wparam, 0 ) ) 
820          */
821               {
822                 message += 2 - (message & 0x0001); 
823
824                 PostMessage( msg->hwnd, message, lastEventChar, msg->lParam );
825
826                 return TRUE;
827               }
828     }
829     return FALSE;
830 }
831
832
833 /***********************************************************************
834  *           DispatchMessage   (USER.114)
835  */
836 LONG DispatchMessage( const MSG16* msg )
837 {
838     WND * wndPtr;
839     LONG retval;
840     int painting;
841     
842       /* Process timer messages */
843     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
844     {
845         if (msg->lParam)
846         {
847 /*            HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
848             return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
849                                    msg->message, msg->wParam, GetTickCount() );
850         }
851     }
852
853     if (!msg->hwnd) return 0;
854     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
855     if (!wndPtr->winproc) return 0;
856     painting = (msg->message == WM_PAINT);
857     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
858 /*    HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
859
860     SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
861                       msg->wParam, msg->lParam );
862     retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
863                                msg->hwnd, msg->message,
864                                msg->wParam, msg->lParam );
865     SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval );
866
867     if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
868         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
869     {
870         fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
871                 msg->hwnd);
872         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
873         /* Validate the update region to avoid infinite WM_PAINT loop */
874         ValidateRect32( msg->hwnd, NULL );
875     }
876     return retval;
877 }
878
879
880 /***********************************************************************
881  *           RegisterWindowMessage16   (USER.118)
882  */
883 WORD RegisterWindowMessage16( SEGPTR str )
884 {
885     dprintf_msg(stddeb, "RegisterWindowMessage16: %08lx\n", (DWORD)str );
886     return GlobalAddAtom16( str );
887 }
888
889
890 /***********************************************************************
891  *           RegisterWindowMessage32A   (USER32.436)
892  */
893 WORD RegisterWindowMessage32A( LPCSTR str )
894 {
895     dprintf_msg(stddeb, "RegisterWindowMessage32A: %s\n", str );
896     return GlobalAddAtom32A( str );
897 }
898
899
900 /***********************************************************************
901  *           RegisterWindowMessage32W   (USER32.437)
902  */
903 WORD RegisterWindowMessage32W( LPCWSTR str )
904 {
905     dprintf_msg(stddeb, "RegisterWindowMessage32W: %p\n", str );
906     return GlobalAddAtom32W( str );
907 }
908
909
910 /***********************************************************************
911  *           GetTickCount   (USER.13) (KERNEL32.299)
912  */
913 DWORD GetTickCount(void)
914 {
915     struct timeval t;
916     gettimeofday( &t, NULL );
917     return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
918 }
919
920
921 /***********************************************************************
922  *           GetCurrentTime    (USER.15)
923  *
924  * (effectively identical to GetTickCount)
925  */
926 DWORD GetCurrentTime(void)
927 {
928     return GetTickCount();
929 }
930
931
932 /***********************************************************************
933  *           InSendMessage    (USER.192)
934  */
935 BOOL InSendMessage()
936 {
937     MESSAGEQUEUE *queue;
938
939     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
940         return 0;
941     return (BOOL)queue->InSendMessageHandle;
942 }