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