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