Moved more things to the X11 driver.
[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 <ctype.h>
10 #include <sys/time.h>
11 #include <sys/types.h>
12
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 "input.h"
20 #include "spy.h"
21 #include "winpos.h"
22 #include "dde.h"
23 #include "queue.h"
24 #include "winproc.h"
25 #include "task.h"
26 #include "process.h"
27 #include "thread.h"
28 #include "options.h"
29 #include "struct32.h"
30 #include "debug.h"
31
32 #define WM_NCMOUSEFIRST         WM_NCMOUSEMOVE
33 #define WM_NCMOUSELAST          WM_NCMBUTTONDBLCLK
34
35 typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP, 
36                SYSQ_MSG_ACCEPT, SYSQ_MSG_CONTINUE } SYSQ_STATUS;
37
38 extern MESSAGEQUEUE *pCursorQueue;                       /* queue.c */
39 extern MESSAGEQUEUE *pActiveQueue;
40
41 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
42
43 static UINT32 doubleClickSpeed = 452;
44 static INT32 debugSMRL = 0;       /* intertask SendMessage() recursion level */
45
46 /***********************************************************************
47  *           MSG_CheckFilter
48  */
49 BOOL32 MSG_CheckFilter(WORD uMsg, DWORD filter)
50 {
51    if( filter )
52        return (uMsg >= LOWORD(filter) && uMsg <= HIWORD(filter));
53    return TRUE;
54 }
55
56 /***********************************************************************
57  *           MSG_SendParentNotify
58  *
59  * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
60  * the window has the WS_EX_NOPARENTNOTIFY style.
61  */
62 static void MSG_SendParentNotify(WND* wndPtr, WORD event, WORD idChild, LPARAM lValue)
63 {
64 #define lppt ((LPPOINT16)&lValue)
65
66     /* pt has to be in the client coordinates of the parent window */
67
68     MapWindowPoints16( 0, wndPtr->hwndSelf, lppt, 1 );
69     while (wndPtr)
70     {
71         if (!(wndPtr->dwStyle & WS_CHILD) || (wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY)) break;
72         lppt->x += wndPtr->rectClient.left;
73         lppt->y += wndPtr->rectClient.top;
74         wndPtr = wndPtr->parent;
75         SendMessage32A( wndPtr->hwndSelf, WM_PARENTNOTIFY,
76                         MAKEWPARAM( event, idChild ), lValue );
77     }
78 #undef lppt
79 }
80
81
82 /***********************************************************************
83  *           MSG_TranslateMouseMsg
84  *
85  * Translate an mouse hardware event into a real mouse message.
86  * Return value indicates whether the translated message must be passed
87  * to the user, left in the queue, or skipped entirely (in this case
88  * HIWORD contains hit test code).
89  */
90 static DWORD MSG_TranslateMouseMsg( HWND16 hTopWnd, DWORD filter, 
91                                     MSG16 *msg, BOOL32 remove, WND* pWndScope )
92 {
93     static DWORD   dblclk_time_limit = 0;
94     static UINT16     clk_message = 0;
95     static HWND16     clk_hwnd = 0;
96     static POINT16    clk_pos = { 0, 0 };
97
98     WND *pWnd;
99     HWND16 hWnd;
100     INT16 ht, hittest, sendSC = 0;
101     UINT16 message = msg->message;
102     POINT16 screen_pt, pt;
103     HANDLE16 hQ = GetFastQueue();
104     MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16(hQ);
105     BOOL32 eatMsg = FALSE;
106     BOOL32 mouseClick = ((message == WM_LBUTTONDOWN) ||
107                          (message == WM_RBUTTONDOWN) ||
108                          (message == WM_MBUTTONDOWN))?1:0;
109     SYSQ_STATUS ret = 0;
110
111       /* Find the window */
112
113     ht = hittest = HTCLIENT;
114     hWnd = GetCapture16();
115     if( !hWnd )
116     {
117         ht = hittest = WINPOS_WindowFromPoint( pWndScope, msg->pt, &pWnd );
118         if( !pWnd ) pWnd = WIN_GetDesktop();
119         hWnd = pWnd->hwndSelf;
120         sendSC = 1;
121     } 
122     else 
123     {
124         pWnd = WIN_FindWndPtr(hWnd);
125         ht = EVENT_GetCaptureInfo();
126     }
127
128         /* stop if not the right queue */
129
130     if (pWnd->hmemTaskQ != hQ)
131     {
132         /* Not for the current task */
133         if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
134         /* Wake up the other task */
135         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
136         if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
137         return SYSQ_MSG_ABANDON;
138     }
139
140         /* check if hWnd is within hWndScope */
141
142     if( hTopWnd && hWnd != hTopWnd )
143         if( !IsChild16(hTopWnd, hWnd) ) return SYSQ_MSG_CONTINUE;
144
145     if( mouseClick )
146     {
147         /* translate double clicks -
148          * note that ...MOUSEMOVEs can slip in between
149          * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
150
151         if( pWnd->class->style & CS_DBLCLKS || ht != HTCLIENT )
152         {
153            if ((message == clk_message) && (hWnd == clk_hwnd) &&
154                (msg->time - dblclk_time_limit < doubleClickSpeed) &&
155                (abs(msg->pt.x - clk_pos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
156                (abs(msg->pt.y - clk_pos.y) < SYSMETRICS_CYDOUBLECLK/2))
157            {
158               message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
159               mouseClick++;   /* == 2 */
160            }
161         }
162     }
163     screen_pt = pt = msg->pt;
164
165     if (hittest != HTCLIENT)
166     {
167         message += ((INT16)WM_NCMOUSEMOVE - WM_MOUSEMOVE);
168         msg->wParam = hittest;
169     }
170     else ScreenToClient16( hWnd, &pt );
171
172         /* check message filter */
173
174     if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
175
176     pCursorQueue = queue;
177
178         /* call WH_MOUSE */
179
180     if (HOOK_IsHooked( WH_MOUSE ))
181     { 
182         MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
183         if( hook )
184         {
185             hook->pt           = screen_pt;
186             hook->hwnd         = hWnd;
187             hook->wHitTestCode = hittest;
188             hook->dwExtraInfo  = 0;
189             ret = HOOK_CallHooks16( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
190                                     message, (LPARAM)SEGPTR_GET(hook) );
191             SEGPTR_FREE(hook);
192         }
193         if( ret ) return MAKELONG((INT16)SYSQ_MSG_SKIP, hittest);
194     }
195
196     if ((hittest == HTERROR) || (hittest == HTNOWHERE)) 
197         eatMsg = sendSC = 1;
198     else if( remove && mouseClick )
199     {
200         HWND32 hwndTop = WIN_GetTopParent( hWnd );
201
202         if( mouseClick == 1 )
203         {
204             /* set conditions */
205             dblclk_time_limit = msg->time;
206                clk_message = msg->message;
207                clk_hwnd = hWnd;
208                clk_pos = screen_pt;
209         } else 
210             /* got double click - zero them out */
211             dblclk_time_limit = clk_hwnd = 0;
212
213         if( sendSC )
214         {
215             /* Send the WM_PARENTNOTIFY,
216              * note that even for double/nonclient clicks
217              * notification message is still WM_L/M/RBUTTONDOWN.
218              */
219
220             MSG_SendParentNotify( pWnd, msg->message, 0, MAKELPARAM(screen_pt.x, screen_pt.y) );
221
222             /* Activate the window if needed */
223
224             if (hWnd != GetActiveWindow16() && hWnd != GetDesktopWindow16())
225             {
226                 LONG ret = SendMessage16( hWnd, WM_MOUSEACTIVATE, hwndTop,
227                                           MAKELONG( hittest, message ) );
228
229                 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
230                          eatMsg = TRUE;
231
232                 if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT)) 
233                       && hwndTop != GetActiveWindow16() )
234                       if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
235                          eatMsg = TRUE;
236             }
237         }
238     } else sendSC = (remove && sendSC);
239
240      /* Send the WM_SETCURSOR message */
241
242     if (sendSC)
243         SendMessage16( hWnd, WM_SETCURSOR, (WPARAM16)hWnd,
244                        MAKELONG( hittest, message ));
245     if (eatMsg) return MAKELONG( (UINT16)SYSQ_MSG_SKIP, hittest);
246
247     msg->hwnd    = hWnd;
248     msg->message = message;
249     msg->lParam  = MAKELONG( pt.x, pt.y );
250     return SYSQ_MSG_ACCEPT;
251 }
252
253
254 /***********************************************************************
255  *           MSG_TranslateKbdMsg
256  *
257  * Translate an keyboard hardware event into a real message.
258  */
259 static DWORD MSG_TranslateKbdMsg( HWND16 hTopWnd, DWORD filter,
260                                   MSG16 *msg, BOOL32 remove )
261 {
262     WORD message = msg->message;
263     HWND16 hWnd = GetFocus16();
264     WND *pWnd;
265
266       /* Should check Ctrl-Esc and PrintScreen here */
267
268     if (!hWnd)
269     {
270           /* Send the message to the active window instead,  */
271           /* translating messages to their WM_SYS equivalent */
272
273         hWnd = GetActiveWindow16();
274
275         if( message < WM_SYSKEYDOWN )
276             message += WM_SYSKEYDOWN - WM_KEYDOWN;
277     }
278     pWnd = WIN_FindWndPtr( hWnd );
279     if (pWnd && (pWnd->hmemTaskQ != GetFastQueue()))
280     {
281         /* Not for the current task */
282         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() );
283         if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
284         /* Wake up the other task */
285         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
286         if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
287         return SYSQ_MSG_ABANDON;
288     }
289
290     if (hTopWnd && hWnd != hTopWnd)
291         if (!IsChild16(hTopWnd, hWnd)) return SYSQ_MSG_CONTINUE;
292     if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
293
294     msg->hwnd = hWnd;
295     msg->message = message;
296
297     return (HOOK_CallHooks16( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
298                               msg->wParam, msg->lParam )
299             ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT);
300 }
301
302
303 /***********************************************************************
304  *           MSG_JournalRecordMsg
305  *
306  * Build an EVENTMSG structure and call JOURNALRECORD hook
307  */
308 static void MSG_JournalRecordMsg( MSG16 *msg )
309 {
310     EVENTMSG16 *event = SEGPTR_NEW(EVENTMSG16);
311     if (!event) return;
312     event->message = msg->message;
313     event->time = msg->time;
314     if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
315     {
316         event->paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
317         event->paramH = msg->lParam & 0x7FFF;  
318         if (HIWORD(msg->lParam) & 0x0100)
319             event->paramH |= 0x8000;               /* special_key - bit */
320         HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
321                           (LPARAM)SEGPTR_GET(event) );
322     }
323     else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
324     {
325         event->paramL = LOWORD(msg->lParam);       /* X pos */
326         event->paramH = HIWORD(msg->lParam);       /* Y pos */ 
327         ClientToScreen16( msg->hwnd, (LPPOINT16)&event->paramL );
328         HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
329                           (LPARAM)SEGPTR_GET(event) );
330     }
331     else if ((msg->message >= WM_NCMOUSEFIRST) &&
332              (msg->message <= WM_NCMOUSELAST))
333     {
334         event->paramL = LOWORD(msg->lParam);       /* X pos */
335         event->paramH = HIWORD(msg->lParam);       /* Y pos */ 
336         event->message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
337         HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
338                           (LPARAM)SEGPTR_GET(event) );
339     }
340     SEGPTR_FREE(event);
341 }
342
343 /***********************************************************************
344  *          MSG_JournalPlayBackMsg
345  *
346  * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function 
347  */
348 static int MSG_JournalPlayBackMsg(void)
349 {
350  EVENTMSG16 *tmpMsg;
351  long wtime,lParam;
352  WORD keyDown,i,wParam,result=0;
353
354  if ( HOOK_IsHooked( WH_JOURNALPLAYBACK ) )
355  {
356   tmpMsg = SEGPTR_NEW(EVENTMSG16);
357   wtime=HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_GETNEXT, 0,
358                           (LPARAM)SEGPTR_GET(tmpMsg));
359   /*  TRACE(msg,"Playback wait time =%ld\n",wtime); */
360   if (wtime<=0)
361   {
362    wtime=0;
363    if ((tmpMsg->message>= WM_KEYFIRST) && (tmpMsg->message <= WM_KEYLAST))
364    {
365      wParam=tmpMsg->paramL & 0xFF;
366      lParam=MAKELONG(tmpMsg->paramH&0x7ffff,tmpMsg->paramL>>8);
367      if (tmpMsg->message == WM_KEYDOWN || tmpMsg->message == WM_SYSKEYDOWN)
368      {
369        for (keyDown=i=0; i<256 && !keyDown; i++)
370           if (InputKeyStateTable[i] & 0x80)
371             keyDown++;
372        if (!keyDown)
373          lParam |= 0x40000000;       
374        AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] |= 0x80;
375      }  
376      else                                       /* WM_KEYUP, WM_SYSKEYUP */
377      {
378        lParam |= 0xC0000000;      
379        AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] &= ~0x80;
380      }
381      if (InputKeyStateTable[VK_MENU] & 0x80)
382        lParam |= 0x20000000;     
383      if (tmpMsg->paramH & 0x8000)              /*special_key bit*/
384        lParam |= 0x01000000;
385      hardware_event( tmpMsg->message, wParam, lParam,0, 0, tmpMsg->time, 0 );     
386    }
387    else
388    {
389     if ((tmpMsg->message>= WM_MOUSEFIRST) && (tmpMsg->message <= WM_MOUSELAST))
390     {
391      switch (tmpMsg->message)
392      {
393       case WM_LBUTTONDOWN:
394           MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=TRUE;break;
395       case WM_LBUTTONUP:
396           MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=FALSE;break;
397       case WM_MBUTTONDOWN:
398           MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=TRUE;break;
399       case WM_MBUTTONUP:
400           MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=FALSE;break;
401       case WM_RBUTTONDOWN:
402           MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=TRUE;break;
403       case WM_RBUTTONUP:
404           MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=FALSE;break;      
405      }
406      AsyncKeyStateTable[VK_LBUTTON]= InputKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] ? 0x80 : 0;
407      AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
408      AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
409      SetCursorPos32(tmpMsg->paramL,tmpMsg->paramH);
410      lParam=MAKELONG(tmpMsg->paramL,tmpMsg->paramH);
411      wParam=0;             
412      if (MouseButtonsStates[0]) wParam |= MK_LBUTTON;
413      if (MouseButtonsStates[1]) wParam |= MK_MBUTTON;
414      if (MouseButtonsStates[2]) wParam |= MK_RBUTTON;
415      hardware_event( tmpMsg->message, wParam, lParam,  
416                      tmpMsg->paramL, tmpMsg->paramH, tmpMsg->time, 0 );
417     }
418    }
419    HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_SKIP, 0,
420                      (LPARAM)SEGPTR_GET(tmpMsg));
421   }
422   else
423   {
424     if( tmpMsg->message == WM_QUEUESYNC )
425         if (HOOK_IsHooked( WH_CBT ))
426             HOOK_CallHooks16( WH_CBT, HCBT_QS, 0, 0L);
427
428     result= QS_MOUSE | QS_KEY; /* ? */
429   }
430   SEGPTR_FREE(tmpMsg);
431  }
432  return result;
433
434
435 /***********************************************************************
436  *           MSG_PeekHardwareMsg
437  *
438  * Peek for a hardware message matching the hwnd and message filters.
439  */
440 static BOOL32 MSG_PeekHardwareMsg( MSG16 *msg, HWND16 hwnd, DWORD filter,
441                                    BOOL32 remove )
442 {
443     DWORD status = SYSQ_MSG_ACCEPT;
444     MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
445     int i, kbd_msg, pos = sysMsgQueue->nextMessage;
446
447     /* FIXME: there has to be a better way to do this */
448     joySendMessages();
449
450     /* If the queue is empty, attempt to fill it */
451     if (!sysMsgQueue->msgCount && THREAD_IsWin16( THREAD_Current() )
452                                && EVENT_Pending())
453         EVENT_WaitNetEvent( FALSE, FALSE );
454
455     for (i = kbd_msg = 0; i < sysMsgQueue->msgCount; i++, pos++)
456     {
457         if (pos >= sysMsgQueue->queueSize) pos = 0;
458         *msg = sysMsgQueue->messages[pos].msg;
459
460           /* Translate message */
461
462         if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
463         {
464             HWND32 hWndScope = (HWND32)sysMsgQueue->messages[pos].extraInfo;
465
466             status = MSG_TranslateMouseMsg(hwnd, filter, msg, remove, 
467                                           (Options.managed && IsWindow32(hWndScope) ) 
468                                            ? WIN_FindWndPtr(hWndScope) : WIN_GetDesktop() );
469             kbd_msg = 0;
470         }
471         else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
472         {
473             status = MSG_TranslateKbdMsg(hwnd, filter, msg, remove);
474             kbd_msg = 1;
475         }
476         else /* Non-standard hardware event */
477         {
478             HARDWAREHOOKSTRUCT16 *hook;
479             if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
480             {
481                 BOOL32 ret;
482                 hook->hWnd     = msg->hwnd;
483                 hook->wMessage = msg->message;
484                 hook->wParam   = msg->wParam;
485                 hook->lParam   = msg->lParam;
486                 ret = HOOK_CallHooks16( WH_HARDWARE,
487                                         remove ? HC_ACTION : HC_NOREMOVE,
488                                         0, (LPARAM)SEGPTR_GET(hook) );
489                 SEGPTR_FREE(hook);
490                 if (ret) 
491                 {
492                     QUEUE_RemoveMsg( sysMsgQueue, pos );
493                     continue;
494                 }
495                 status = SYSQ_MSG_ACCEPT; 
496             }
497         }
498
499         switch (LOWORD(status))
500         {
501            case SYSQ_MSG_ACCEPT:
502                 break;
503
504            case SYSQ_MSG_SKIP:
505                 if (HOOK_IsHooked( WH_CBT ))
506                 {
507                    if( kbd_msg )
508                        HOOK_CallHooks16( WH_CBT, HCBT_KEYSKIPPED, 
509                                                  msg->wParam, msg->lParam );
510                    else
511                    {
512                        MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
513                        if (hook)
514                        {
515                            hook->pt           = msg->pt;
516                            hook->hwnd         = msg->hwnd;
517                            hook->wHitTestCode = HIWORD(status);
518                            hook->dwExtraInfo  = 0;
519                            HOOK_CallHooks16( WH_CBT, HCBT_CLICKSKIPPED ,msg->message,
520                                           (LPARAM)SEGPTR_GET(hook) );
521                            SEGPTR_FREE(hook);
522                        }
523                    }
524                 }
525
526                 if (remove)
527                     QUEUE_RemoveMsg( sysMsgQueue, pos );
528                 /* continue */
529
530            case SYSQ_MSG_CONTINUE:
531                 continue;
532
533            case SYSQ_MSG_ABANDON: 
534                 return FALSE;
535         }
536
537         if (remove)
538         {
539             if (HOOK_IsHooked( WH_JOURNALRECORD )) MSG_JournalRecordMsg( msg );
540             QUEUE_RemoveMsg( sysMsgQueue, pos );
541         }
542         return TRUE;
543     }
544     return FALSE;
545 }
546
547
548 /**********************************************************************
549  *           SetDoubleClickTime16   (USER.20)
550  */
551 void WINAPI SetDoubleClickTime16( UINT16 interval )
552 {
553     SetDoubleClickTime32( interval );
554 }               
555
556
557 /**********************************************************************
558  *           SetDoubleClickTime32   (USER32.480)
559  */
560 BOOL32 WINAPI SetDoubleClickTime32( UINT32 interval )
561 {
562     doubleClickSpeed = interval ? interval : 500;
563     return TRUE;
564 }               
565
566
567 /**********************************************************************
568  *           GetDoubleClickTime16   (USER.21)
569  */
570 UINT16 WINAPI GetDoubleClickTime16(void)
571 {
572     return doubleClickSpeed;
573 }               
574
575
576 /**********************************************************************
577  *           GetDoubleClickTime32   (USER32.239)
578  */
579 UINT32 WINAPI GetDoubleClickTime32(void)
580 {
581     return doubleClickSpeed;
582 }               
583
584
585 /***********************************************************************
586  *           MSG_SendMessage
587  *
588  * Implementation of an inter-task SendMessage.
589  */
590 static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg,
591                                 WPARAM32 wParam, LPARAM lParam, WORD flags )
592 {
593     INT32         prevSMRL = debugSMRL;
594     QSMCTRL       qCtrl = { 0, 1};
595     MESSAGEQUEUE *queue, *destQ;
596
597     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetFastQueue() ))) return 0;
598     if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
599
600     if (IsTaskLocked() || !IsWindow32(hwnd)) return 0;
601
602     debugSMRL+=4;
603     TRACE(sendmsg,"%*sSM: %s [%04x] (%04x -> %04x)\n", 
604                     prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
605
606     if( !(queue->wakeBits & QS_SMPARAMSFREE) )
607     {
608       TRACE(sendmsg,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
609       QUEUE_WaitBits( QS_SMPARAMSFREE );
610     }
611
612     /* resume sending */ 
613
614     queue->hWnd       = hwnd;
615     queue->msg        = msg;
616     queue->wParam     = LOWORD(wParam);
617     queue->wParamHigh = HIWORD(wParam);
618     queue->lParam     = lParam;
619     queue->hPrevSendingTask = destQ->hSendingTask;
620     destQ->hSendingTask = GetFastQueue();
621
622     QUEUE_ClearWakeBit( queue, QS_SMPARAMSFREE );
623     queue->flags = (queue->flags & ~(QUEUE_SM_WIN32|QUEUE_SM_UNICODE)) | flags;
624
625     TRACE(sendmsg,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
626
627     queue->smResultInit = &qCtrl;
628
629     QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
630
631     /* perform task switch and wait for the result */
632
633     while( qCtrl.bPending )
634     {
635       if (!(queue->wakeBits & QS_SMRESULT))
636       {
637         if (THREAD_IsWin16( THREAD_Current() )) DirectedYield( destQ->hTask );
638         QUEUE_WaitBits( QS_SMRESULT );
639         TRACE(sendmsg,"\tsm: have result!\n");
640       }
641       /* got something */
642
643       TRACE(sendmsg,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult );
644
645       if (queue->smResult) { /* FIXME, smResult should always be set */
646         queue->smResult->lResult = queue->SendMessageReturn;
647         queue->smResult->bPending = FALSE;
648       }
649       QUEUE_ClearWakeBit( queue, QS_SMRESULT );
650
651       if( queue->smResult != &qCtrl )
652           ERR(sendmsg, "%*ssm: weird scenes inside the goldmine!\n", prevSMRL, "");
653     }
654     queue->smResultInit = NULL;
655     
656     TRACE(sendmsg,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult);
657     debugSMRL-=4;
658
659     return qCtrl.lResult;
660 }
661
662
663 /***********************************************************************
664  *           ReplyMessage16   (USER.115)
665  */
666 void WINAPI ReplyMessage16( LRESULT result )
667 {
668     MESSAGEQUEUE *senderQ;
669     MESSAGEQUEUE *queue;
670
671     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetFastQueue() ))) return;
672
673     TRACE(msg,"ReplyMessage, queue %04x\n", queue->self);
674
675     while( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
676     {
677       TRACE(msg,"\trpm: replying to %04x (%04x -> %04x)\n",
678                           queue->msg, queue->self, senderQ->self);
679
680       if( queue->wakeBits & QS_SENDMESSAGE )
681       {
682         QUEUE_ReceiveMessage( queue );
683         continue; /* ReceiveMessage() already called us */
684       }
685
686       if(!(senderQ->wakeBits & QS_SMRESULT) ) break;
687       if (THREAD_IsWin16(THREAD_Current())) OldYield();
688     } 
689     if( !senderQ ) { TRACE(msg,"\trpm: done\n"); return; }
690
691     senderQ->SendMessageReturn = result;
692     TRACE(msg,"\trpm: smResult = %08x, result = %08lx\n", 
693                         (unsigned)queue->smResultCurrent, result );
694
695     senderQ->smResult = queue->smResultCurrent;
696     queue->InSendMessageHandle = 0;
697
698     QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
699     if (THREAD_IsWin16(THREAD_Current())) DirectedYield( senderQ->hTask );
700 }
701
702
703 /***********************************************************************
704  *           MSG_PeekMessage
705  */
706 static BOOL32 MSG_PeekMessage( LPMSG16 msg, HWND16 hwnd, WORD first, WORD last,
707                                WORD flags, BOOL32 peek )
708 {
709     int pos, mask;
710     MESSAGEQUEUE *msgQueue;
711     HQUEUE16 hQueue;
712
713 #ifdef CONFIG_IPC
714     DDE_TestDDE(hwnd);  /* do we have dde handling in the window ?*/
715     DDE_GetRemoteMessage();
716 #endif  /* CONFIG_IPC */
717
718     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
719     if (first || last)
720     {
721         if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
722         if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
723              ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
724         if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
725         if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
726         if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
727     }
728     else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
729
730     if (IsTaskLocked()) flags |= PM_NOYIELD;
731
732     /* Never yield on Win32 threads */
733     if (!THREAD_IsWin16(THREAD_Current())) flags |= PM_NOYIELD;
734
735     while(1)
736     {    
737         hQueue   = GetFastQueue();
738         msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
739         if (!msgQueue) return FALSE;
740         msgQueue->changeBits = 0;
741
742         /* First handle a message put by SendMessage() */
743
744         while (msgQueue->wakeBits & QS_SENDMESSAGE)
745             QUEUE_ReceiveMessage( msgQueue );
746
747         /* Now handle a WM_QUIT message */
748
749         if (msgQueue->wPostQMsg &&
750            (!first || WM_QUIT >= first) && 
751            (!last || WM_QUIT <= last) )
752         {
753             msg->hwnd    = hwnd;
754             msg->message = WM_QUIT;
755             msg->wParam  = msgQueue->wExitCode;
756             msg->lParam  = 0;
757             if (flags & PM_REMOVE) msgQueue->wPostQMsg = 0;
758             break;
759         }
760     
761         /* Now find a normal message */
762
763         if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
764             ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
765         {
766             QMSG *qmsg = &msgQueue->messages[pos];
767             *msg = qmsg->msg;
768             msgQueue->GetMessageTimeVal      = msg->time;
769             msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
770             msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
771
772             if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
773             break;
774         }
775
776         msgQueue->changeBits |= MSG_JournalPlayBackMsg();
777
778         /* Now find a hardware event */
779
780         if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
781             MSG_PeekHardwareMsg( msg, hwnd, MAKELONG(first,last), flags & PM_REMOVE ))
782         {
783             /* Got one */
784             msgQueue->GetMessageTimeVal      = msg->time;
785             msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
786             msgQueue->GetMessageExtraInfoVal = 0;  /* Always 0 for now */
787             break;
788         }
789
790         /* Check again for SendMessage */
791
792         while (msgQueue->wakeBits & QS_SENDMESSAGE)
793             QUEUE_ReceiveMessage( msgQueue );
794
795         /* Now find a WM_PAINT message */
796
797         if ((msgQueue->wakeBits & mask) & QS_PAINT)
798         {
799             WND* wndPtr;
800             msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
801             msg->message = WM_PAINT;
802             msg->wParam = 0;
803             msg->lParam = 0;
804
805             if ((wndPtr = WIN_FindWndPtr(msg->hwnd)))
806             {
807                 if( wndPtr->dwStyle & WS_MINIMIZE &&
808                     wndPtr->class->hIcon )
809                 {
810                     msg->message = WM_PAINTICON;
811                     msg->wParam = 1;
812                 }
813
814                 if( !hwnd || msg->hwnd == hwnd || IsChild16(hwnd,msg->hwnd) )
815                 {
816                     if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
817                     {
818                         wndPtr->flags &= ~WIN_INTERNAL_PAINT;
819                         QUEUE_DecPaintCount( hQueue );
820                     }
821                     break;
822                 }
823             }
824         }
825
826         /* Check for timer messages, but yield first */
827
828         if (!(flags & PM_NOYIELD))
829         {
830             UserYield();
831             while (msgQueue->wakeBits & QS_SENDMESSAGE)
832                 QUEUE_ReceiveMessage( msgQueue );
833         }
834         if ((msgQueue->wakeBits & mask) & QS_TIMER)
835         {
836             if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
837         }
838
839         if (peek)
840         {
841             if (!(flags & PM_NOYIELD)) UserYield();
842             return FALSE;
843         }
844         msgQueue->wakeMask = mask;
845         QUEUE_WaitBits( mask );
846     }
847
848       /* We got a message */
849     if (flags & PM_REMOVE)
850     {
851         WORD message = msg->message;
852
853         if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
854         {
855             BYTE *p = &QueueKeyStateTable[msg->wParam & 0xff];
856
857             if (!(*p & 0x80))
858                 *p ^= 0x01;
859             *p |= 0x80;
860         }
861         else if (message == WM_KEYUP || message == WM_SYSKEYUP)
862             QueueKeyStateTable[msg->wParam & 0xff] &= ~0x80;
863     }
864     if (peek) return TRUE;
865     else return (msg->message != WM_QUIT);
866 }
867
868
869 /***********************************************************************
870  *           MSG_InternalGetMessage
871  *
872  * GetMessage() function for internal use. Behave like GetMessage(),
873  * but also call message filters and optionally send WM_ENTERIDLE messages.
874  * 'hwnd' must be the handle of the dialog or menu window.
875  * 'code' is the message filter value (MSGF_??? codes).
876  */
877 BOOL32 MSG_InternalGetMessage( MSG16 *msg, HWND32 hwnd, HWND32 hwndOwner,
878                                WPARAM32 code, WORD flags, BOOL32 sendIdle ) 
879 {
880     for (;;)
881     {
882         if (sendIdle)
883         {
884             if (!MSG_PeekMessage( msg, 0, 0, 0, flags, TRUE ))
885             {
886                   /* No message present -> send ENTERIDLE and wait */
887                 if (IsWindow32(hwndOwner))
888                     SendMessage16( hwndOwner, WM_ENTERIDLE,
889                                    code, (LPARAM)hwnd );
890                 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
891             }
892         }
893         else  /* Always wait for a message */
894             MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
895
896         /* Call message filters */
897
898         if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER ))
899         {
900             MSG16 *pmsg = SEGPTR_NEW(MSG16);
901             if (pmsg)
902             {
903                 BOOL32 ret;
904                 *pmsg = *msg;
905                 ret = ((BOOL16)HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0,
906                                                  (LPARAM)SEGPTR_GET(pmsg) ) ||
907                        (BOOL16)HOOK_CallHooks16( WH_MSGFILTER, code, 0,
908                                                  (LPARAM)SEGPTR_GET(pmsg) ));
909                 SEGPTR_FREE(pmsg);
910                 if (ret)
911                 {
912                     /* Message filtered -> remove it from the queue */
913                     /* if it's still there. */
914                     if (!(flags & PM_REMOVE))
915                         MSG_PeekMessage( msg, 0, 0, 0, PM_REMOVE, TRUE );
916                     continue;
917                 }
918             }
919         }
920
921         return (msg->message != WM_QUIT);
922     }
923 }
924
925
926 /***********************************************************************
927  *           PeekMessage16   (USER.109)
928  */
929 BOOL16 WINAPI PeekMessage16( LPMSG16 msg, HWND16 hwnd, UINT16 first,
930                              UINT16 last, UINT16 flags )
931 {
932     return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
933 }
934
935 /***********************************************************************
936  *         PeekMessageA
937  */
938 BOOL32 WINAPI PeekMessage32A( LPMSG32 lpmsg, HWND32 hwnd,
939                               UINT32 min,UINT32 max,UINT32 wRemoveMsg)
940 {
941         MSG16 msg;
942         BOOL32 ret;
943         ret=PeekMessage16(&msg,hwnd,min,max,wRemoveMsg);
944         /* FIXME: should translate the message to Win32 */
945         STRUCT32_MSG16to32(&msg,lpmsg);
946         return ret;
947 }
948
949 /***********************************************************************
950  *         PeekMessageW             Check queue for messages
951  *
952  * Checks for a message in the thread's queue, filtered as for
953  * GetMessage(). Returns immediately whether a message is available
954  * or not.
955  *
956  * Whether a retrieved message is removed from the queue is set by the
957  * _wRemoveMsg_ flags, which should be one of the following values:
958  *
959  *    PM_NOREMOVE    Do not remove the message from the queue. 
960  *
961  *    PM_REMOVE      Remove the message from the queue.
962  *
963  * In addition, PM_NOYIELD may be combined into _wRemoveMsg_ to
964  * request that the system not yield control during PeekMessage();
965  * however applications may not rely on scheduling behavior.
966  * 
967  * RETURNS
968  *
969  *  Nonzero if a message is available and is retrieved, zero otherwise.
970  *
971  * CONFORMANCE
972  *
973  * ECMA-234, Win32
974  *
975  */
976 BOOL32 WINAPI PeekMessage32W( 
977   LPMSG32 lpmsg,    /* buffer to receive message */
978   HWND32 hwnd,      /* restrict to messages for hwnd */
979   UINT32 min,       /* minimum message to receive */
980   UINT32 max,       /* maximum message to receive */
981   UINT32 wRemoveMsg /* removal flags */ 
982 ) {
983         /* FIXME: Should perform Unicode translation on specific messages */
984         return PeekMessage32A(lpmsg,hwnd,min,max,wRemoveMsg);
985 }
986
987 /***********************************************************************
988  *           GetMessage16   (USER.108)
989  */
990 BOOL16 WINAPI GetMessage16( SEGPTR msg, HWND16 hwnd, UINT16 first, UINT16 last)
991 {
992     MSG16 *lpmsg = (MSG16 *)PTR_SEG_TO_LIN(msg);
993     MSG_PeekMessage( lpmsg,
994                      hwnd, first, last, PM_REMOVE, FALSE );
995
996     TRACE(msg,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg->message,
997                                                                  hwnd, first, last );
998     HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
999     return (lpmsg->message != WM_QUIT);
1000 }
1001
1002 /***********************************************************************
1003  *          GetMessage32A   (USER32.270)
1004  */
1005 BOOL32 WINAPI GetMessage32A(MSG32* lpmsg,HWND32 hwnd,UINT32 min,UINT32 max)
1006 {
1007     BOOL32 ret;
1008     MSG16 *msg = SEGPTR_NEW(MSG16);
1009     if (!msg) return 0;
1010     ret=GetMessage16(SEGPTR_GET(msg),(HWND16)hwnd,min,max);
1011     /* FIXME */
1012     STRUCT32_MSG16to32(msg,lpmsg);
1013     SEGPTR_FREE(msg);
1014     return ret;
1015 }
1016
1017 /***********************************************************************
1018  *          GetMessage32W   (USER32.274) Retrieve next message
1019  *
1020  * GetMessage retrieves the next event from the calling thread's
1021  * queue and deposits it in *lpmsg.
1022  *
1023  * If _hwnd_ is not NULL, only messages for window _hwnd_ and its
1024  * children as specified by IsChild() are retrieved. If _hwnd_ is NULL
1025  * all application messages are retrieved.
1026  *
1027  * _min_ and _max_ specify the range of messages of interest. If
1028  * min==max==0, no filtering is performed. Useful examples are
1029  * WM_KEYFIRST and WM_KEYLAST to retrieve keyboard input, and
1030  * WM_MOUSEFIRST and WM_MOUSELAST to retrieve mouse input.
1031  *
1032  * WM_PAINT messages are not removed from the queue; they remain until
1033  * processed. Other messages are removed from the queue.
1034  *
1035  * RETURNS
1036  *
1037  * -1 on error, 0 if message is WM_QUIT, nonzero otherwise.
1038  *
1039  * CONFORMANCE
1040  *
1041  * ECMA-234, Win32
1042  * 
1043  */
1044 BOOL32 WINAPI GetMessage32W(
1045   MSG32* lpmsg, /* buffer to receive message */
1046   HWND32 hwnd,  /* restrict to messages for hwnd */
1047   UINT32 min,   /* minimum message to receive */
1048   UINT32 max    /* maximum message to receive */
1049 ) {
1050     BOOL32 ret;
1051     MSG16 *msg = SEGPTR_NEW(MSG16);
1052     if (!msg) return 0;
1053     ret=GetMessage16(SEGPTR_GET(msg),(HWND16)hwnd,min,max);
1054     /* FIXME */
1055     STRUCT32_MSG16to32(msg,lpmsg);
1056     SEGPTR_FREE(msg);
1057     return ret;
1058 }
1059
1060
1061 /***********************************************************************
1062  *           PostMessage16   (USER.110)
1063  */
1064 BOOL16 WINAPI PostMessage16( HWND16 hwnd, UINT16 message, WPARAM16 wParam,
1065                              LPARAM lParam )
1066 {
1067     MSG16       msg;
1068     WND         *wndPtr;
1069
1070     msg.hwnd    = hwnd;
1071     msg.message = message;
1072     msg.wParam  = wParam;
1073     msg.lParam  = lParam;
1074     msg.time    = GetTickCount();
1075     msg.pt.x    = 0;
1076     msg.pt.y    = 0;
1077
1078 #ifdef CONFIG_IPC
1079     if (DDE_PostMessage(&msg))
1080        return TRUE;
1081 #endif  /* CONFIG_IPC */
1082     
1083     if (hwnd == HWND_BROADCAST)
1084     {
1085         TRACE(msg,"HWND_BROADCAST !\n");
1086         for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
1087         {
1088             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1089             {
1090                 TRACE(msg,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
1091                             wndPtr->hwndSelf, message, wParam, lParam);
1092                 PostMessage16( wndPtr->hwndSelf, message, wParam, lParam );
1093             }
1094         }
1095         TRACE(msg,"End of HWND_BROADCAST !\n");
1096         return TRUE;
1097     }
1098
1099     wndPtr = WIN_FindWndPtr( hwnd );
1100     if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
1101
1102     return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
1103 }
1104
1105
1106 /***********************************************************************
1107  *           PostMessage32A   (USER32.419)
1108  */
1109 BOOL32 WINAPI PostMessage32A( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
1110                               LPARAM lParam )
1111 {
1112   /* FIXME */
1113   if (message&0xffff0000)
1114     FIXME(msg,"message is truncated from %d to %d\n", message, message&0xffff);
1115   if (wParam&0xffff0000)
1116     FIXME(msg,"wParam is truncated from %d to %d\n", wParam, wParam&0xffff);
1117   return PostMessage16( hwnd, message, wParam, lParam );
1118 }
1119
1120
1121 /***********************************************************************
1122  *           PostMessage32W   (USER32.420)
1123  */
1124 BOOL32 WINAPI PostMessage32W( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
1125                               LPARAM lParam )
1126 {
1127   /* FIXME */
1128   if (message&0xffff0000)
1129     FIXME(msg,"message is truncated from %d to %d\n", message, message&0xffff);
1130   if (wParam&0xffff0000)
1131     FIXME(msg,"wParam is truncated from %d to %d\n", wParam, wParam&0xffff);
1132   return PostMessage16( hwnd, message, wParam, lParam );
1133 }
1134
1135
1136 /***********************************************************************
1137  *           PostAppMessage16   (USER.116)
1138  */
1139 BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message, WPARAM16 wParam,
1140                                 LPARAM lParam )
1141 {
1142     MSG16 msg;
1143
1144     if (GetTaskQueue(hTask) == 0) return FALSE;
1145     msg.hwnd    = 0;
1146     msg.message = message;
1147     msg.wParam  = wParam;
1148     msg.lParam  = lParam;
1149     msg.time    = GetTickCount();
1150     msg.pt.x    = 0;
1151     msg.pt.y    = 0;
1152
1153     return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
1154 }
1155
1156
1157 /***********************************************************************
1158  *           SendMessage16   (USER.111)
1159  */
1160 LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
1161                               LPARAM lParam)
1162 {
1163     WND * wndPtr;
1164     WND **list, **ppWnd;
1165     LRESULT ret;
1166
1167 #ifdef CONFIG_IPC
1168     MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
1169     if (DDE_SendMessage(&DDE_msg)) return TRUE;
1170 #endif  /* CONFIG_IPC */
1171
1172     if (hwnd == HWND_BROADCAST)
1173     {
1174         if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1175             return TRUE;
1176         TRACE(msg,"HWND_BROADCAST !\n");
1177         for (ppWnd = list; *ppWnd; ppWnd++)
1178         {
1179             wndPtr = *ppWnd;
1180             if (!IsWindow32(wndPtr->hwndSelf)) continue;
1181             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1182             {
1183                 TRACE(msg,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
1184                             wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
1185                 SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
1186             }
1187         }
1188         HeapFree( SystemHeap, 0, list );
1189         TRACE(msg,"End of HWND_BROADCAST !\n");
1190         return TRUE;
1191     }
1192
1193     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1194     {
1195         LPCWPSTRUCT16 pmsg;
1196
1197         if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
1198         {
1199             pmsg->hwnd   = hwnd;
1200             pmsg->message= msg;
1201             pmsg->wParam = wParam;
1202             pmsg->lParam = lParam;
1203             HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
1204                               (LPARAM)SEGPTR_GET(pmsg) );
1205             hwnd   = pmsg->hwnd;
1206             msg    = pmsg->message;
1207             wParam = pmsg->wParam;
1208             lParam = pmsg->lParam;
1209             SEGPTR_FREE( pmsg );
1210         }
1211     }
1212
1213     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1214     {
1215         WARN(msg, "invalid hwnd %04x\n", hwnd );
1216         return 0;
1217     }
1218     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1219         return 0;  /* Don't send anything if the task is dying */
1220
1221     SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
1222
1223     if (wndPtr->hmemTaskQ != GetFastQueue())
1224         ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg,
1225                                wParam, lParam, 0 );
1226     else
1227         ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1228                                 hwnd, msg, wParam, lParam );
1229
1230     SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
1231     return ret;
1232 }
1233
1234 /************************************************************************
1235  *           MSG_CallWndProcHook32
1236  */
1237 static void  MSG_CallWndProcHook32( LPMSG32 pmsg, BOOL32 bUnicode )
1238 {
1239    CWPSTRUCT32 cwp;
1240
1241    cwp.lParam = pmsg->lParam;
1242    cwp.wParam = pmsg->wParam;
1243    cwp.message = pmsg->message;
1244    cwp.hwnd = pmsg->hwnd;
1245
1246    if (bUnicode) HOOK_CallHooks32W(WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp);
1247    else HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
1248
1249    pmsg->lParam = cwp.lParam;
1250    pmsg->wParam = cwp.wParam;
1251    pmsg->message = cwp.message;
1252    pmsg->hwnd = cwp.hwnd;
1253 }
1254
1255 /**********************************************************************
1256  *           PostThreadMessage32A    (USER32.422)
1257  *
1258  * BUGS
1259  *
1260  *  Thread-local message queues are not supported.
1261  * 
1262  */
1263 BOOL32 WINAPI PostThreadMessage32A(DWORD idThread , UINT32 message,
1264                                    WPARAM32 wParam, LPARAM lParam )
1265 {
1266    THDB *thdb = THREAD_ID_TO_THDB(idThread);
1267    if (!thdb || !thdb->process) return FALSE;
1268
1269    FIXME(sendmsg, "(...): Should use thread-local message queue!\n");
1270    return PostAppMessage16(thdb->process->task, message, wParam, lParam);
1271 }
1272
1273 /**********************************************************************
1274  *           PostThreadMessage32W    (USER32.423)
1275  *
1276  * BUGS
1277  *
1278  *  Thread-local message queues are not supported.
1279  * 
1280  */
1281 BOOL32 WINAPI PostThreadMessage32W(DWORD idThread , UINT32 message,
1282                                    WPARAM32 wParam, LPARAM lParam )
1283 {
1284    THDB *thdb = THREAD_ID_TO_THDB(idThread);
1285    if (!thdb || !thdb->process) return FALSE;
1286
1287    FIXME(sendmsg, "(...): Should use thread-local message queue!\n");
1288    return PostAppMessage16(thdb->process->task, message, wParam, lParam);
1289 }
1290
1291 /***********************************************************************
1292  *           SendMessage32A   (USER32.454)
1293  */
1294 LRESULT WINAPI SendMessage32A( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
1295                                LPARAM lParam )
1296 {
1297     WND * wndPtr;
1298     WND **list, **ppWnd;
1299     LRESULT ret;
1300
1301     if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
1302     {
1303         if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1304             return TRUE;
1305         for (ppWnd = list; *ppWnd; ppWnd++)
1306         {
1307             wndPtr = *ppWnd;
1308             if (!IsWindow32(wndPtr->hwndSelf)) continue;
1309             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1310                 SendMessage32A( wndPtr->hwndSelf, msg, wParam, lParam );
1311         }
1312         HeapFree( SystemHeap, 0, list );
1313         return TRUE;
1314     }
1315
1316     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1317         MSG_CallWndProcHook32( (LPMSG32)&hwnd, FALSE);
1318
1319     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1320     {
1321         WARN(msg, "invalid hwnd %08x\n", hwnd );
1322         return 0;
1323     }
1324
1325     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1326         return 0;  /* Don't send anything if the task is dying */
1327
1328     SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1329
1330     if (wndPtr->hmemTaskQ != GetFastQueue())
1331         ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
1332                                QUEUE_SM_WIN32 );
1333     else
1334         ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1335                                  hwnd, msg, wParam, lParam );
1336
1337     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1338     return ret;
1339 }
1340
1341
1342 /***********************************************************************
1343  *           SendMessage32W   (USER32.459)  Send Window Message
1344  *
1345  *  Sends a message to the window procedure of the specified window.
1346  *  SendMessage() will not return until the called window procedure
1347  *  either returns or calls ReplyMessage().
1348  *
1349  *  Use PostMessage() to send message and return immediately. A window
1350  *  procedure may use InSendMessage() to detect
1351  *  SendMessage()-originated messages.
1352  *
1353  *  Applications which communicate via HWND_BROADCAST may use
1354  *  RegisterWindowMessage() to obtain a unique message to avoid conflicts
1355  *  with other applications.
1356  *
1357  * CONFORMANCE
1358  * 
1359  *  ECMA-234, Win32 
1360  */
1361 LRESULT WINAPI SendMessage32W( 
1362   HWND32 hwnd,    /* Window to send message to. If HWND_BROADCAST, 
1363                  the message will be sent to all top-level windows. */
1364
1365   UINT32 msg,      /* message */
1366   WPARAM32 wParam, /* message parameter */
1367   LPARAM lParam    /* additional message parameter */
1368 ) {
1369     WND * wndPtr;
1370     WND **list, **ppWnd;
1371     LRESULT ret;
1372
1373     if (hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST)
1374     {
1375         if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1376             return TRUE;
1377         for (ppWnd = list; *ppWnd; ppWnd++)
1378         {
1379             wndPtr = *ppWnd;
1380             if (!IsWindow32(wndPtr->hwndSelf)) continue;
1381             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1382                 SendMessage32W( wndPtr->hwndSelf, msg, wParam, lParam );
1383         }
1384         HeapFree( SystemHeap, 0, list );
1385         return TRUE;
1386     }
1387
1388     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1389         MSG_CallWndProcHook32( (LPMSG32)&hwnd, TRUE);
1390
1391     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1392     {
1393         WARN(msg, "invalid hwnd %08x\n", hwnd );
1394         return 0;
1395     }
1396     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1397         return 0;  /* Don't send anything if the task is dying */
1398
1399     SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1400
1401     if (wndPtr->hmemTaskQ != GetFastQueue())
1402         ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
1403                                 QUEUE_SM_WIN32 | QUEUE_SM_UNICODE );
1404     else
1405         ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1406                                  hwnd, msg, wParam, lParam );
1407
1408     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1409     return ret;
1410 }
1411
1412
1413 /***********************************************************************
1414  *           SendMessageTimeout16    (not a WINAPI)
1415  */
1416 LRESULT WINAPI SendMessageTimeout16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
1417                                      LPARAM lParam, UINT16 flags,
1418                                      UINT16 timeout, LPWORD resultp)
1419 {
1420   FIXME(sendmsg, "(...): semistub\n");
1421   return SendMessage16 (hwnd, msg, wParam, lParam);
1422 }
1423
1424
1425 /***********************************************************************
1426  *           SendMessageTimeout32A   (USER32.457)
1427  */
1428 LRESULT WINAPI SendMessageTimeout32A( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
1429                                       LPARAM lParam, UINT32 flags,
1430                                       UINT32 timeout, LPDWORD resultp)
1431 {
1432   FIXME(sendmsg, "(...): semistub\n");
1433   return SendMessage32A (hwnd, msg, wParam, lParam);
1434 }
1435
1436
1437 /***********************************************************************
1438  *           SendMessageTimeout32W   (USER32.458)
1439  */
1440 LRESULT WINAPI SendMessageTimeout32W( HWND32 hwnd, UINT32 msg, WPARAM32 wParam,
1441                                       LPARAM lParam, UINT32 flags,
1442                                       UINT32 timeout, LPDWORD resultp)
1443 {
1444   FIXME(sendmsg, "(...): semistub\n");
1445   return SendMessage32W (hwnd, msg, wParam, lParam);
1446 }
1447
1448
1449 /***********************************************************************
1450  *  WaitMessage    (USER.112) (USER32.578)  Suspend thread pending messages
1451  *
1452  * WaitMessage() suspends a thread until events appear in the thread's
1453  * queue.
1454  *
1455  * BUGS
1456  *
1457  * Is supposed to return BOOL under Win32.
1458  *
1459  * Thread-local message queues are not supported.
1460  *
1461  * CONFORMANCE
1462  *
1463  * ECMA-234, Win32
1464  * 
1465  */
1466 void WINAPI WaitMessage( void )
1467 {
1468     QUEUE_WaitBits( QS_ALLINPUT );
1469 }
1470
1471 /***********************************************************************
1472  *           MsgWaitForMultipleObjects    (USER32.400)
1473  */
1474 DWORD WINAPI MsgWaitForMultipleObjects( DWORD nCount, HANDLE32 *pHandles,
1475                                         BOOL32 fWaitAll, DWORD dwMilliseconds,
1476                                         DWORD dwWakeMask )
1477 {
1478     DWORD retv;
1479
1480     TDB *currTask = (TDB *)GlobalLock16( GetCurrentTask() );
1481     HQUEUE16 hQueue = currTask? currTask->hQueue : 0;
1482     MESSAGEQUEUE *msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
1483     if (!msgQueue) return 0xFFFFFFFF;
1484
1485     msgQueue->changeBits = 0;
1486     msgQueue->wakeMask = dwWakeMask;
1487
1488     retv = SYNC_DoWait( nCount, pHandles, fWaitAll, dwMilliseconds, FALSE, TRUE );
1489
1490     return retv;
1491 }
1492
1493
1494
1495 struct accent_char
1496 {
1497     BYTE ac_accent;
1498     BYTE ac_char;
1499     BYTE ac_result;
1500 };
1501
1502 static const struct accent_char accent_chars[] =
1503 {
1504 /* A good idea should be to read /usr/X11/lib/X11/locale/iso8859-x/Compose */
1505     {'`', 'A', '\300'},  {'`', 'a', '\340'},
1506     {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
1507     {'^', 'A', '\302'},  {'^', 'a', '\342'},
1508     {'~', 'A', '\303'},  {'~', 'a', '\343'},
1509     {'"', 'A', '\304'},  {'"', 'a', '\344'},
1510     {'O', 'A', '\305'},  {'o', 'a', '\345'},
1511     {'0', 'A', '\305'},  {'0', 'a', '\345'},
1512     {'A', 'A', '\305'},  {'a', 'a', '\345'},
1513     {'A', 'E', '\306'},  {'a', 'e', '\346'},
1514     {',', 'C', '\307'},  {',', 'c', '\347'},
1515     {'`', 'E', '\310'},  {'`', 'e', '\350'},
1516     {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
1517     {'^', 'E', '\312'},  {'^', 'e', '\352'},
1518     {'"', 'E', '\313'},  {'"', 'e', '\353'},
1519     {'`', 'I', '\314'},  {'`', 'i', '\354'},
1520     {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
1521     {'^', 'I', '\316'},  {'^', 'i', '\356'},
1522     {'"', 'I', '\317'},  {'"', 'i', '\357'},
1523     {'-', 'D', '\320'},  {'-', 'd', '\360'},
1524     {'~', 'N', '\321'},  {'~', 'n', '\361'},
1525     {'`', 'O', '\322'},  {'`', 'o', '\362'},
1526     {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
1527     {'^', 'O', '\324'},  {'^', 'o', '\364'},
1528     {'~', 'O', '\325'},  {'~', 'o', '\365'},
1529     {'"', 'O', '\326'},  {'"', 'o', '\366'},
1530     {'/', 'O', '\330'},  {'/', 'o', '\370'},
1531     {'`', 'U', '\331'},  {'`', 'u', '\371'},
1532     {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
1533     {'^', 'U', '\333'},  {'^', 'u', '\373'},
1534     {'"', 'U', '\334'},  {'"', 'u', '\374'},
1535     {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
1536     {'T', 'H', '\336'},  {'t', 'h', '\376'},
1537     {'s', 's', '\337'},  {'"', 'y', '\377'},
1538     {'s', 'z', '\337'},  {'i', 'j', '\377'},
1539         /* iso-8859-2 uses this */
1540     {'<', 'L', '\245'},  {'<', 'l', '\265'},    /* caron */
1541     {'<', 'S', '\251'},  {'<', 's', '\271'},
1542     {'<', 'T', '\253'},  {'<', 't', '\273'},
1543     {'<', 'Z', '\256'},  {'<', 'z', '\276'},
1544     {'<', 'C', '\310'},  {'<', 'c', '\350'},
1545     {'<', 'E', '\314'},  {'<', 'e', '\354'},
1546     {'<', 'D', '\317'},  {'<', 'd', '\357'},
1547     {'<', 'N', '\322'},  {'<', 'n', '\362'},
1548     {'<', 'R', '\330'},  {'<', 'r', '\370'},
1549     {';', 'A', '\241'},  {';', 'a', '\261'},    /* ogonek */
1550     {';', 'E', '\312'},  {';', 'e', '\332'},
1551     {'\'', 'Z', '\254'}, {'\'', 'z', '\274'},   /* acute */
1552     {'\'', 'R', '\300'}, {'\'', 'r', '\340'},
1553     {'\'', 'L', '\305'}, {'\'', 'l', '\345'},
1554     {'\'', 'C', '\306'}, {'\'', 'c', '\346'},
1555     {'\'', 'N', '\321'}, {'\'', 'n', '\361'},
1556 /*  collision whith S, from iso-8859-9 !!! */
1557     {',', 'S', '\252'},  {',', 's', '\272'},    /* cedilla */
1558     {',', 'T', '\336'},  {',', 't', '\376'},
1559     {'.', 'Z', '\257'},  {'.', 'z', '\277'},    /* dot above */
1560     {'/', 'L', '\243'},  {'/', 'l', '\263'},    /* slash */
1561     {'/', 'D', '\320'},  {'/', 'd', '\360'},
1562     {'(', 'A', '\303'},  {'(', 'a', '\343'},    /* breve */
1563     {'\275', 'O', '\325'}, {'\275', 'o', '\365'},       /* double acute */
1564     {'\275', 'U', '\334'}, {'\275', 'u', '\374'},
1565     {'0', 'U', '\332'},  {'0', 'u', '\372'},    /* ring above */
1566         /* iso-8859-3 uses this */
1567     {'/', 'H', '\241'},  {'/', 'h', '\261'},    /* slash */
1568     {'>', 'H', '\246'},  {'>', 'h', '\266'},    /* circumflex */
1569     {'>', 'J', '\254'},  {'>', 'j', '\274'},
1570     {'>', 'C', '\306'},  {'>', 'c', '\346'},
1571     {'>', 'G', '\330'},  {'>', 'g', '\370'},
1572     {'>', 'S', '\336'},  {'>', 's', '\376'},
1573 /*  collision whith G( from iso-8859-9 !!!   */
1574     {'(', 'G', '\253'},  {'(', 'g', '\273'},    /* breve */
1575     {'(', 'U', '\335'},  {'(', 'u', '\375'},
1576 /*  collision whith I. from iso-8859-3 !!!   */
1577     {'.', 'I', '\251'},  {'.', 'i', '\271'},    /* dot above */
1578     {'.', 'C', '\305'},  {'.', 'c', '\345'},
1579     {'.', 'G', '\325'},  {'.', 'g', '\365'},
1580         /* iso-8859-4 uses this */
1581     {',', 'R', '\243'},  {',', 'r', '\263'},    /* cedilla */
1582     {',', 'L', '\246'},  {',', 'l', '\266'},
1583     {',', 'G', '\253'},  {',', 'g', '\273'},
1584     {',', 'N', '\321'},  {',', 'n', '\361'},
1585     {',', 'K', '\323'},  {',', 'k', '\363'},
1586     {'~', 'I', '\245'},  {'~', 'i', '\265'},    /* tilde */
1587     {'-', 'E', '\252'},  {'-', 'e', '\272'},    /* macron */
1588     {'-', 'A', '\300'},  {'-', 'a', '\340'},
1589     {'-', 'I', '\317'},  {'-', 'i', '\357'},
1590     {'-', 'O', '\322'},  {'-', 'o', '\362'},
1591     {'-', 'U', '\336'},  {'-', 'u', '\376'},
1592     {'/', 'T', '\254'},  {'/', 't', '\274'},    /* slash */
1593     {'.', 'E', '\314'},  {'.', 'e', '\344'},    /* dot above */
1594     {';', 'I', '\307'},  {';', 'i', '\347'},    /* ogonek */
1595     {';', 'U', '\331'},  {';', 'u', '\371'},
1596         /* iso-8859-9 uses this */
1597         /* iso-8859-9 has really bad choosen G( S, and I. as they collide
1598          * whith the same letters on other iso-8859-x (that is they are on
1599          * different places :-( ), if you use turkish uncomment these and
1600          * comment out the lines in iso-8859-2 and iso-8859-3 sections
1601          * FIXME: should be dynamic according to chosen language
1602          *        if/when Wine has turkish support.  
1603          */ 
1604 /*  collision whith G( from iso-8859-3 !!!   */
1605 /*  {'(', 'G', '\320'},  {'(', 'g', '\360'}, */ /* breve */
1606 /*  collision whith S, from iso-8859-2 !!! */
1607 /*  {',', 'S', '\336'},  {',', 's', '\376'}, */ /* cedilla */
1608 /*  collision whith I. from iso-8859-3 !!!   */
1609 /*  {'.', 'I', '\335'},  {'.', 'i', '\375'}, */ /* dot above */
1610 };
1611
1612
1613 /***********************************************************************
1614  *           MSG_DoTranslateMessage
1615  *
1616  * Implementation of TranslateMessage.
1617  *
1618  * TranslateMessage translates virtual-key messages into character-messages,
1619  * as follows :
1620  * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
1621  * ditto replacing WM_* with WM_SYS*
1622  * This produces WM_CHAR messages only for keys mapped to ASCII characters
1623  * by the keyboard driver.
1624  */
1625 static BOOL32 MSG_DoTranslateMessage( UINT32 message, HWND32 hwnd,
1626                                       WPARAM32 wParam, LPARAM lParam )
1627 {
1628     static int dead_char;
1629     BYTE wp[2];
1630     
1631     if (message != WM_MOUSEMOVE && message != WM_TIMER)
1632         TRACE(msg, "(%s, %04X, %08lX)\n",
1633                      SPY_GetMsgName(message), wParam, lParam );
1634     if(message >= WM_KEYFIRST && message <= WM_KEYLAST)
1635         TRACE(key, "(%s, %04X, %08lX)\n",
1636                      SPY_GetMsgName(message), wParam, lParam );
1637
1638     if ((message != WM_KEYDOWN) && (message != WM_SYSKEYDOWN))  return FALSE;
1639
1640     TRACE(key, "Translating key %04X, scancode %04X\n",
1641                  wParam, HIWORD(lParam) );
1642
1643     /* FIXME : should handle ToAscii yielding 2 */
1644     switch (ToAscii32(wParam, HIWORD(lParam),
1645                       QueueKeyStateTable,(LPWORD)wp, 0)) 
1646     {
1647     case 1 :
1648         message = (message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
1649         /* Should dead chars handling go in ToAscii ? */
1650         if (dead_char)
1651         {
1652             int i;
1653
1654             if (wp[0] == ' ') wp[0] =  dead_char;
1655             if (dead_char == 0xa2) dead_char = '(';
1656             else if (dead_char == 0xa8) dead_char = '"';
1657             else if (dead_char == 0xb2) dead_char = ';';
1658             else if (dead_char == 0xb4) dead_char = '\'';
1659             else if (dead_char == 0xb7) dead_char = '<';
1660             else if (dead_char == 0xb8) dead_char = ',';
1661             else if (dead_char == 0xff) dead_char = '.';
1662             for (i = 0; i < sizeof(accent_chars)/sizeof(accent_chars[0]); i++)
1663                 if ((accent_chars[i].ac_accent == dead_char) &&
1664                     (accent_chars[i].ac_char == wp[0]))
1665                 {
1666                     wp[0] = accent_chars[i].ac_result;
1667                     break;
1668                 }
1669             dead_char = 0;
1670         }
1671         TRACE(key, "1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
1672         PostMessage16( hwnd, message, wp[0], lParam );
1673         return TRUE;
1674
1675     case -1 :
1676         message = (message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
1677         dead_char = wp[0];
1678         TRACE(key, "-1 -> PostMessage(%s)\n",
1679                      SPY_GetMsgName(message));
1680         PostMessage16( hwnd, message, wp[0], lParam );
1681         return TRUE;
1682     }
1683     return FALSE;
1684 }
1685
1686
1687 /***********************************************************************
1688  *           TranslateMessage16   (USER.113)
1689  */
1690 BOOL16 WINAPI TranslateMessage16( const MSG16 *msg )
1691 {
1692     return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1693                                    msg->wParam, msg->lParam );
1694 }
1695
1696
1697 /***********************************************************************
1698  *           TranslateMessage32   (USER32.556)
1699  */
1700 BOOL32 WINAPI TranslateMessage32( const MSG32 *msg )
1701 {
1702     return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1703                                    msg->wParam, msg->lParam );
1704 }
1705
1706
1707 /***********************************************************************
1708  *           DispatchMessage16   (USER.114)
1709  */
1710 LONG WINAPI DispatchMessage16( const MSG16* msg )
1711 {
1712     WND * wndPtr;
1713     LONG retval;
1714     int painting;
1715     
1716       /* Process timer messages */
1717     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1718     {
1719         if (msg->lParam)
1720         {
1721             return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
1722                                    msg->message, msg->wParam, GetTickCount() );
1723         }
1724     }
1725
1726     if (!msg->hwnd) return 0;
1727     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1728     if (!wndPtr->winproc) return 0;
1729     painting = (msg->message == WM_PAINT);
1730     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1731
1732     SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
1733                       msg->wParam, msg->lParam );
1734     retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1735                                msg->hwnd, msg->message,
1736                                msg->wParam, msg->lParam );
1737     SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval );
1738
1739     if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1740         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1741     {
1742         ERR(msg, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
1743             msg->hwnd);
1744         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1745         /* Validate the update region to avoid infinite WM_PAINT loop */
1746         ValidateRect32( msg->hwnd, NULL );
1747     }
1748     return retval;
1749 }
1750
1751
1752 /***********************************************************************
1753  *           DispatchMessage32A   (USER32.141)
1754  */
1755 LONG WINAPI DispatchMessage32A( const MSG32* msg )
1756 {
1757     WND * wndPtr;
1758     LONG retval;
1759     int painting;
1760     
1761       /* Process timer messages */
1762     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1763     {
1764         if (msg->lParam)
1765         {
1766 /*            HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1767             return CallWindowProc32A( (WNDPROC32)msg->lParam, msg->hwnd,
1768                                    msg->message, msg->wParam, GetTickCount() );
1769         }
1770     }
1771
1772     if (!msg->hwnd) return 0;
1773     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1774     if (!wndPtr->winproc) return 0;
1775     painting = (msg->message == WM_PAINT);
1776     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1777 /*    HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1778
1779     SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1780                       msg->wParam, msg->lParam );
1781     retval = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1782                                 msg->hwnd, msg->message,
1783                                 msg->wParam, msg->lParam );
1784     SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1785
1786     if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1787         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1788     {
1789         ERR(msg, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
1790             msg->hwnd);
1791         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1792         /* Validate the update region to avoid infinite WM_PAINT loop */
1793         ValidateRect32( msg->hwnd, NULL );
1794     }
1795     return retval;
1796 }
1797
1798
1799 /***********************************************************************
1800  *           DispatchMessage32W   (USER32.142)     Process Message
1801  *
1802  * Process the message specified in the structure *_msg_.
1803  *
1804  * If the lpMsg parameter points to a WM_TIMER message and the
1805  * parameter of the WM_TIMER message is not NULL, the lParam parameter
1806  * points to the function that is called instead of the window
1807  * procedure.
1808  *  
1809  * The message must be valid.
1810  *
1811  * RETURNS
1812  *
1813  *   DispatchMessage() returns the result of the window procedure invoked.
1814  *
1815  * CONFORMANCE
1816  *
1817  *   ECMA-234, Win32 
1818  *
1819  */
1820 LONG WINAPI DispatchMessage32W( const MSG32* msg )
1821 {
1822     WND * wndPtr;
1823     LONG retval;
1824     int painting;
1825     
1826       /* Process timer messages */
1827     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1828     {
1829         if (msg->lParam)
1830         {
1831 /*            HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1832             return CallWindowProc32W( (WNDPROC32)msg->lParam, msg->hwnd,
1833                                    msg->message, msg->wParam, GetTickCount() );
1834         }
1835     }
1836
1837     if (!msg->hwnd) return 0;
1838     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1839     if (!wndPtr->winproc) return 0;
1840     painting = (msg->message == WM_PAINT);
1841     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1842 /*    HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1843
1844     SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1845                       msg->wParam, msg->lParam );
1846     retval = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1847                                 msg->hwnd, msg->message,
1848                                 msg->wParam, msg->lParam );
1849     SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1850
1851     if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1852         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1853     {
1854         ERR(msg, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
1855             msg->hwnd);
1856         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1857         /* Validate the update region to avoid infinite WM_PAINT loop */
1858         ValidateRect32( msg->hwnd, NULL );
1859     }
1860     return retval;
1861 }
1862
1863
1864 /***********************************************************************
1865  *           RegisterWindowMessage16   (USER.118)
1866  */
1867 WORD WINAPI RegisterWindowMessage16( SEGPTR str )
1868 {
1869     TRACE(msg, "%08lx\n", (DWORD)str );
1870     return GlobalAddAtom16( str );
1871 }
1872
1873
1874 /***********************************************************************
1875  *           RegisterWindowMessage32A   (USER32.437)
1876  */
1877 WORD WINAPI RegisterWindowMessage32A( LPCSTR str )
1878 {
1879     TRACE(msg, "%s\n", str );
1880     return GlobalAddAtom32A( str );
1881 }
1882
1883
1884 /***********************************************************************
1885  *           RegisterWindowMessage32W   (USER32.438)
1886  */
1887 WORD WINAPI RegisterWindowMessage32W( LPCWSTR str )
1888 {
1889     TRACE(msg, "%p\n", str );
1890     return GlobalAddAtom32W( str );
1891 }
1892
1893
1894 /***********************************************************************
1895  *           GetTickCount   (USER.13) (KERNEL32.299)  System Time
1896  * Returns the number of milliseconds, modulo 2^32, since the start
1897  * of the current session.
1898  *
1899  * CONFORMANCE
1900  *
1901  * ECMA-234, Win32
1902  */
1903 DWORD WINAPI GetTickCount(void)
1904 {
1905     struct timeval t;
1906     gettimeofday( &t, NULL );
1907     /* make extremely compatible: granularity is 25 msec */
1908     return ((t.tv_sec * 1000) + (t.tv_usec / 25000) * 25) - MSG_WineStartTicks;
1909 }
1910
1911
1912 /***********************************************************************
1913  *           GetCurrentTime16    (USER.15)
1914  *
1915  * (effectively identical to GetTickCount)
1916  */
1917 DWORD WINAPI GetCurrentTime16(void)
1918 {
1919     return GetTickCount();
1920 }
1921
1922
1923 /***********************************************************************
1924  *           InSendMessage16    (USER.192)
1925  */
1926 BOOL16 WINAPI InSendMessage16(void)
1927 {
1928     return InSendMessage32();
1929 }
1930
1931
1932 /***********************************************************************
1933  *           InSendMessage32    (USER32.320)
1934  */
1935 BOOL32 WINAPI InSendMessage32(void)
1936 {
1937     MESSAGEQUEUE *queue;
1938
1939     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() )))
1940         return 0;
1941     return (BOOL32)queue->InSendMessageHandle;
1942 }
1943
1944 /***********************************************************************
1945  *           BroadcastSystemMessage    (USER32.12)
1946  */
1947 LONG WINAPI BroadcastSystemMessage(
1948         DWORD dwFlags,LPDWORD recipients,UINT32 uMessage,WPARAM32 wParam,
1949         LPARAM lParam
1950 ) {
1951         FIXME(sendmsg,"(%08lx,%08lx,%08x,%08x,%08lx): stub!\n",
1952               dwFlags,*recipients,uMessage,wParam,lParam
1953         );
1954         return 0;
1955 }
1956
1957 /***********************************************************************
1958  *           SendNotifyMessageA    (USER32.460)
1959  * FIXME
1960  *  The message sended with PostMessage has to be put in the queue
1961  *  with a higher priority as the other "Posted" messages.
1962  *  QUEUE_AddMsg has to be modifyed.
1963  */
1964 BOOL32 WINAPI SendNotifyMessage32A(HWND32 hwnd,UINT32 msg,WPARAM32 wParam,LPARAM lParam)
1965 {       BOOL32 ret = TRUE;
1966         FIXME(msg,"(%04x,%08x,%08x,%08lx) not complete\n",
1967               hwnd, msg, wParam, lParam);
1968               
1969         if ( GetCurrentThreadId() == GetWindowThreadProcessId ( hwnd, NULL))
1970         {       ret=SendMessage32A ( hwnd, msg, wParam, lParam );
1971         }
1972         else
1973         {       PostMessage32A ( hwnd, msg, wParam, lParam );
1974         }
1975         return ret;
1976 }
1977
1978 /***********************************************************************
1979  *           SendNotifyMessageW    (USER32.461)
1980  * FIXME
1981  *  The message sended with PostMessage has to be put in the queue
1982  *  with a higher priority as the other "Posted" messages.
1983  *  QUEUE_AddMsg has to be modifyed.
1984  */
1985 BOOL32 WINAPI SendNotifyMessage32W(HWND32 hwnd,UINT32 msg,WPARAM32 wParam,LPARAM lParam)
1986 {       BOOL32 ret = TRUE;
1987         FIXME(msg,"(%04x,%08x,%08x,%08lx) not complete\n",
1988               hwnd, msg, wParam, lParam);
1989
1990         if ( GetCurrentThreadId() == GetWindowThreadProcessId ( hwnd, NULL))
1991         {       ret=SendMessage32W ( hwnd, msg, wParam, lParam );
1992         }
1993         else
1994         {       PostMessage32W ( hwnd, msg, wParam, lParam );
1995         }
1996         return ret;
1997 }
1998
1999 /***********************************************************************
2000  *           SendMessageCallBack32A
2001  * FIXME: It's like PostMessage. The callback gets called when the message
2002  * is processed. We have to modify the message processing for a exact
2003  * implementation...
2004  */
2005 BOOL32 WINAPI SendMessageCallBack32A(
2006         HWND32 hWnd,UINT32 Msg,WPARAM32 wParam,LPARAM lParam,
2007         FARPROC32 lpResultCallBack,DWORD dwData)
2008 {       
2009         FIXME(msg,"(0x%04x,0x%04x,0x%08x,0x%08lx,%p,0x%08lx),stub!\n",
2010                 hWnd,Msg,wParam,lParam,lpResultCallBack,dwData);
2011         if ( hWnd == HWND_BROADCAST)
2012         {       PostMessage32A( hWnd, Msg, wParam, lParam);
2013                 FIXME(msg,"Broadcast: Callback will not be called!\n");
2014                 return TRUE;
2015         }
2016         (lpResultCallBack)( hWnd, Msg, dwData, SendMessage32A ( hWnd, Msg, wParam, lParam ));
2017                 return TRUE;
2018 }