Release 970804
[wine] / windows / message.c
1 /*
2  * Message queues related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include <sys/time.h>
11 #include <sys/types.h>
12
13 #include "message.h"
14 #include "win.h"
15 #include "gdi.h"
16 #include "sysmetrics.h"
17 #include "heap.h"
18 #include "hook.h"
19 #include "keyboard.h"
20 #include "spy.h"
21 #include "winpos.h"
22 #include "atom.h"
23 #include "dde.h"
24 #include "queue.h"
25 #include "winproc.h"
26 #include "options.h"
27 #include "stddebug.h"
28 /* #define DEBUG_MSG */
29 #include "debug.h"
30
31 #define WM_NCMOUSEFIRST         WM_NCMOUSEMOVE
32 #define WM_NCMOUSELAST          WM_NCMBUTTONDBLCLK
33
34 typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP, 
35                SYSQ_MSG_ACCEPT, SYSQ_MSG_CONTINUE } SYSQ_STATUS;
36
37 extern MESSAGEQUEUE *pCursorQueue;                       /* queue.c */
38 extern MESSAGEQUEUE *pActiveQueue;
39
40 extern void JoySendMessages(void);
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(WORD uMsg, DWORD filter)
51 {
52    if( filter )
53        return (uMsg >= LOWORD(filter) && uMsg <= HIWORD(filter));
54    return TRUE;
55 }
56
57 /***********************************************************************
58  *           MSG_TranslateMouseMsg
59  *
60  * Translate an mouse hardware event into a real mouse message.
61  * Return value indicates whether the translated message must be passed
62  * to the user, left in the queue, or skipped entirely (in this case
63  * HIWORD contains hit test code).
64  */
65 static DWORD MSG_TranslateMouseMsg( HWND16 hTopWnd, DWORD filter, 
66                                     MSG16 *msg, BOOL32 remove, WND* pWndScope )
67 {
68     static DWORD   dblclk_time_limit = 0;
69     static UINT16     clk_message = 0;
70     static HWND16     clk_hwnd = 0;
71     static POINT16    clk_pos = { 0, 0 };
72
73     WND *pWnd;
74     HWND16 hWnd;
75     INT16 ht, hittest, sendSC = 0;
76     UINT16 message = msg->message;
77     POINT16 screen_pt, pt;
78     HANDLE16 hQ = GetTaskQueue(0);
79     MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16(hQ);
80     BOOL32 eatMsg = FALSE;
81     BOOL32 mouseClick = ((message == WM_LBUTTONDOWN) ||
82                          (message == WM_RBUTTONDOWN) ||
83                          (message == WM_MBUTTONDOWN))?1:0;
84     SYSQ_STATUS ret = 0;
85
86       /* Find the window */
87
88     ht = hittest = HTCLIENT;
89     hWnd = GetCapture16();
90     if( !hWnd )
91     {
92         ht = hittest = WINPOS_WindowFromPoint( pWndScope, msg->pt, &pWnd );
93         if( !pWnd ) pWnd = WIN_GetDesktop();
94         hWnd = pWnd->hwndSelf;
95         sendSC = 1;
96     } 
97     else 
98     {
99         pWnd = WIN_FindWndPtr(hWnd);
100         ht = EVENT_GetCaptureInfo();
101     }
102
103         /* stop if not the right queue */
104
105     if (pWnd->hmemTaskQ != hQ)
106     {
107         /* Not for the current task */
108         if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
109         /* Wake up the other task */
110         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
111         if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
112         return SYSQ_MSG_ABANDON;
113     }
114
115         /* check if hWnd is within hWndScope */
116
117     if( hTopWnd && hWnd != hTopWnd )
118         if( !IsChild16(hTopWnd, hWnd) ) return SYSQ_MSG_CONTINUE;
119
120     if( mouseClick )
121     {
122         /* translate double clicks -
123          * note that ...MOUSEMOVEs can slip in between
124          * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
125
126         if( pWnd->class->style & CS_DBLCLKS || ht != HTCLIENT )
127         {
128            if ((message == clk_message) && (hWnd == clk_hwnd) &&
129                (msg->time - dblclk_time_limit < doubleClickSpeed) &&
130                (abs(msg->pt.x - clk_pos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
131                (abs(msg->pt.y - clk_pos.y) < SYSMETRICS_CYDOUBLECLK/2))
132            {
133               message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
134               mouseClick++;   /* == 2 */
135            }
136         }
137     }
138     screen_pt = pt = msg->pt;
139
140     if (hittest != HTCLIENT)
141     {
142         message += ((INT16)WM_NCMOUSEMOVE - WM_MOUSEMOVE);
143         msg->wParam = hittest;
144     }
145     else ScreenToClient16( hWnd, &pt );
146
147         /* check message filter */
148
149     if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
150
151     pCursorQueue = queue;
152
153         /* call WH_MOUSE */
154
155     if (HOOK_IsHooked( WH_MOUSE ))
156     { 
157         MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
158         if( hook )
159         {
160             hook->pt           = screen_pt;
161             hook->hwnd         = hWnd;
162             hook->wHitTestCode = hittest;
163             hook->dwExtraInfo  = 0;
164             ret = HOOK_CallHooks16( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
165                                     message, (LPARAM)SEGPTR_GET(hook) );
166             SEGPTR_FREE(hook);
167         }
168         if( ret ) return MAKELONG((INT16)SYSQ_MSG_SKIP, hittest);
169     }
170
171     if ((hittest == HTERROR) || (hittest == HTNOWHERE)) 
172         eatMsg = sendSC = 1;
173     else if( remove && mouseClick )
174     {
175         HWND32 hwndTop = WIN_GetTopParent( hWnd );
176
177         if( mouseClick == 1 )
178         {
179             /* set conditions */
180             dblclk_time_limit = msg->time;
181                clk_message = msg->message;
182                clk_hwnd = hWnd;
183                clk_pos = screen_pt;
184         } else 
185             /* got double click - zero them out */
186             dblclk_time_limit = clk_hwnd = 0;
187
188         if( sendSC )
189         {
190             /* Send the WM_PARENTNOTIFY,
191              * note that even for double/nonclient clicks
192              * notification message is still WM_L/M/RBUTTONDOWN.
193              */
194
195             WIN_SendParentNotify( hWnd, msg->message, 0,
196                               MAKELPARAM( screen_pt.x, screen_pt.y ) );
197
198             /* Activate the window if needed */
199
200             if (hWnd != GetActiveWindow16() && hWnd != GetDesktopWindow16())
201             {
202                 LONG ret = SendMessage16( hWnd, WM_MOUSEACTIVATE, hwndTop,
203                                           MAKELONG( hittest, message ) );
204
205                 if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
206                          eatMsg = TRUE;
207
208                 if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT)) 
209                       && hwndTop != GetActiveWindow16() )
210                       if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
211                          eatMsg = TRUE;
212             }
213         }
214     } else sendSC = (remove && sendSC);
215
216      /* Send the WM_SETCURSOR message */
217
218     if (sendSC)
219         SendMessage16( hWnd, WM_SETCURSOR, (WPARAM16)hWnd,
220                        MAKELONG( hittest, message ));
221     if (eatMsg) return MAKELONG( (UINT16)SYSQ_MSG_SKIP, hittest);
222
223     msg->hwnd    = hWnd;
224     msg->message = message;
225     msg->lParam  = MAKELONG( pt.x, pt.y );
226     return SYSQ_MSG_ACCEPT;
227 }
228
229
230 /***********************************************************************
231  *           MSG_TranslateKbdMsg
232  *
233  * Translate an keyboard hardware event into a real message.
234  */
235 static DWORD MSG_TranslateKbdMsg( HWND16 hTopWnd, DWORD filter,
236                                   MSG16 *msg, BOOL32 remove )
237 {
238     WORD message = msg->message;
239     HWND16 hWnd = GetFocus16();
240     WND *pWnd;
241
242       /* Should check Ctrl-Esc and PrintScreen here */
243
244     if (!hWnd)
245     {
246           /* Send the message to the active window instead,  */
247           /* translating messages to their WM_SYS equivalent */
248
249         hWnd = GetActiveWindow16();
250
251         if( message < WM_SYSKEYDOWN )
252             message += WM_SYSKEYDOWN - WM_KEYDOWN;
253     }
254     pWnd = WIN_FindWndPtr( hWnd );
255     if (pWnd && (pWnd->hmemTaskQ != GetTaskQueue(0)))
256     {
257         /* Not for the current task */
258         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
259         if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
260         /* Wake up the other task */
261         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
262         if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
263         return SYSQ_MSG_ABANDON;
264     }
265
266     if (hTopWnd && hWnd != hTopWnd)
267         if (!IsChild16(hTopWnd, hWnd)) return SYSQ_MSG_CONTINUE;
268     if (!MSG_CheckFilter(message, filter)) return SYSQ_MSG_CONTINUE;
269
270     msg->hwnd = hWnd;
271     msg->message = message;
272
273     return (HOOK_CallHooks16( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
274                               msg->wParam, msg->lParam )
275             ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT);
276 }
277
278
279 /***********************************************************************
280  *           MSG_JournalRecordMsg
281  *
282  * Build an EVENTMSG structure and call JOURNALRECORD hook
283  */
284 static void MSG_JournalRecordMsg( MSG16 *msg )
285 {
286     EVENTMSG16 *event = SEGPTR_NEW(EVENTMSG16);
287     if (!event) return;
288     event->message = msg->message;
289     event->time = msg->time;
290     if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
291     {
292         event->paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
293         event->paramH = msg->lParam & 0x7FFF;  
294         if (HIWORD(msg->lParam) & 0x0100)
295             event->paramH |= 0x8000;               /* special_key - bit */
296         HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
297                           (LPARAM)SEGPTR_GET(event) );
298     }
299     else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
300     {
301         event->paramL = LOWORD(msg->lParam);       /* X pos */
302         event->paramH = HIWORD(msg->lParam);       /* Y pos */ 
303         ClientToScreen16( msg->hwnd, (LPPOINT16)&event->paramL );
304         HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
305                           (LPARAM)SEGPTR_GET(event) );
306     }
307     else if ((msg->message >= WM_NCMOUSEFIRST) &&
308              (msg->message <= WM_NCMOUSELAST))
309     {
310         event->paramL = LOWORD(msg->lParam);       /* X pos */
311         event->paramH = HIWORD(msg->lParam);       /* Y pos */ 
312         event->message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
313         HOOK_CallHooks16( WH_JOURNALRECORD, HC_ACTION, 0,
314                           (LPARAM)SEGPTR_GET(event) );
315     }
316     SEGPTR_FREE(event);
317 }
318
319 /***********************************************************************
320  *          MSG_JournalPlayBackMsg
321  *
322  * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function 
323  */
324 static int MSG_JournalPlayBackMsg(void)
325 {
326  EVENTMSG16 *tmpMsg;
327  long wtime,lParam;
328  WORD keyDown,i,wParam,result=0;
329
330  if ( HOOK_IsHooked( WH_JOURNALPLAYBACK ) )
331  {
332   tmpMsg = SEGPTR_NEW(EVENTMSG16);
333   wtime=HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_GETNEXT, 0,
334                           (LPARAM)SEGPTR_GET(tmpMsg));
335   /*  dprintf_msg(stddeb,"Playback wait time =%ld\n",wtime); */
336   if (wtime<=0)
337   {
338    wtime=0;
339    if ((tmpMsg->message>= WM_KEYFIRST) && (tmpMsg->message <= WM_KEYLAST))
340    {
341      wParam=tmpMsg->paramL & 0xFF;
342      lParam=MAKELONG(tmpMsg->paramH&0x7ffff,tmpMsg->paramL>>8);
343      if (tmpMsg->message == WM_KEYDOWN || tmpMsg->message == WM_SYSKEYDOWN)
344      {
345        for (keyDown=i=0; i<256 && !keyDown; i++)
346           if (InputKeyStateTable[i] & 0x80)
347             keyDown++;
348        if (!keyDown)
349          lParam |= 0x40000000;       
350        AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] |= 0x80;
351      }  
352      else                                       /* WM_KEYUP, WM_SYSKEYUP */
353      {
354        lParam |= 0xC0000000;      
355        AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] &= ~0x80;
356      }
357      if (InputKeyStateTable[VK_MENU] & 0x80)
358        lParam |= 0x20000000;     
359      if (tmpMsg->paramH & 0x8000)              /*special_key bit*/
360        lParam |= 0x01000000;
361      hardware_event( tmpMsg->message, wParam, lParam,0, 0, tmpMsg->time, 0 );     
362    }
363    else
364    {
365     if ((tmpMsg->message>= WM_MOUSEFIRST) && (tmpMsg->message <= WM_MOUSELAST))
366     {
367      switch (tmpMsg->message)
368      {
369       case WM_LBUTTONDOWN:MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=1;break;
370       case WM_LBUTTONUP:  MouseButtonsStates[0]=AsyncMouseButtonsStates[0]=0;break;
371       case WM_MBUTTONDOWN:MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=1;break;
372       case WM_MBUTTONUP:  MouseButtonsStates[1]=AsyncMouseButtonsStates[1]=0;break;
373       case WM_RBUTTONDOWN:MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=1;break;
374       case WM_RBUTTONUP:  MouseButtonsStates[2]=AsyncMouseButtonsStates[2]=0;break;      
375      }
376      AsyncKeyStateTable[VK_LBUTTON]= InputKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] << 8;
377      AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] << 8;
378      AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] << 8;
379      SetCursorPos32(tmpMsg->paramL,tmpMsg->paramH);
380      lParam=MAKELONG(tmpMsg->paramL,tmpMsg->paramH);
381      wParam=0;             
382      if (MouseButtonsStates[0]) wParam |= MK_LBUTTON;
383      if (MouseButtonsStates[1]) wParam |= MK_MBUTTON;
384      if (MouseButtonsStates[2]) wParam |= MK_RBUTTON;
385      hardware_event( tmpMsg->message, wParam, lParam,  
386                      tmpMsg->paramL, tmpMsg->paramH, tmpMsg->time, 0 );
387     }
388    }
389    HOOK_CallHooks16( WH_JOURNALPLAYBACK, HC_SKIP, 0,
390                      (LPARAM)SEGPTR_GET(tmpMsg));
391   }
392   else
393   {
394     if( tmpMsg->message == WM_QUEUESYNC )
395         if (HOOK_IsHooked( WH_CBT ))
396             HOOK_CallHooks16( WH_CBT, HCBT_QS, 0, 0L);
397
398     result= QS_MOUSE | QS_KEY; /* ? */
399   }
400   SEGPTR_FREE(tmpMsg);
401  }
402  return result;
403
404
405 /***********************************************************************
406  *           MSG_PeekHardwareMsg
407  *
408  * Peek for a hardware message matching the hwnd and message filters.
409  */
410 static BOOL32 MSG_PeekHardwareMsg( MSG16 *msg, HWND16 hwnd, DWORD filter,
411                                    BOOL32 remove )
412 {
413     DWORD status = SYSQ_MSG_ACCEPT;
414     MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
415     int i, kbd_msg, pos = sysMsgQueue->nextMessage;
416
417     /* FIXME: there has to be a better way to do this */
418     JoySendMessages();
419
420     /* If the queue is empty, attempt to fill it */
421     if (!sysMsgQueue->msgCount && XPending(display))
422         EVENT_WaitXEvent( FALSE, FALSE );
423
424     for (i = kbd_msg = 0; i < sysMsgQueue->msgCount; i++, pos++)
425     {
426         if (pos >= sysMsgQueue->queueSize) pos = 0;
427         *msg = sysMsgQueue->messages[pos].msg;
428
429           /* Translate message */
430
431         if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
432         {
433             HWND32 hWndScope = (HWND32)sysMsgQueue->messages[pos].extraInfo;
434
435             status = MSG_TranslateMouseMsg(hwnd, filter, msg, remove, 
436                                           (Options.managed && IsWindow32(hWndScope) ) 
437                                            ? WIN_FindWndPtr(hWndScope) : WIN_GetDesktop() );
438             kbd_msg = 0;
439         }
440         else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
441         {
442             status = MSG_TranslateKbdMsg(hwnd, filter, msg, remove);
443             kbd_msg = 1;
444         }
445         else /* Non-standard hardware event */
446         {
447             HARDWAREHOOKSTRUCT16 *hook;
448             if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
449             {
450                 BOOL32 ret;
451                 hook->hWnd     = msg->hwnd;
452                 hook->wMessage = msg->message;
453                 hook->wParam   = msg->wParam;
454                 hook->lParam   = msg->lParam;
455                 ret = HOOK_CallHooks16( WH_HARDWARE,
456                                         remove ? HC_ACTION : HC_NOREMOVE,
457                                         0, (LPARAM)SEGPTR_GET(hook) );
458                 SEGPTR_FREE(hook);
459                 if (ret) 
460                 {
461                     QUEUE_RemoveMsg( sysMsgQueue, pos );
462                     continue;
463                 }
464                 status = SYSQ_MSG_ACCEPT; 
465             }
466         }
467
468         switch (LOWORD(status))
469         {
470            case SYSQ_MSG_ACCEPT:
471                 break;
472
473            case SYSQ_MSG_SKIP:
474                 if (HOOK_IsHooked( WH_CBT ))
475                    if( kbd_msg )
476                        HOOK_CallHooks16( WH_CBT, HCBT_KEYSKIPPED, 
477                                                  msg->wParam, msg->lParam );
478                    else
479                    {
480                        MOUSEHOOKSTRUCT16 *hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16);
481                        if (hook)
482                        {
483                            hook->pt           = msg->pt;
484                            hook->hwnd         = msg->hwnd;
485                            hook->wHitTestCode = HIWORD(status);
486                            hook->dwExtraInfo  = 0;
487                            HOOK_CallHooks16( WH_CBT, HCBT_CLICKSKIPPED ,msg->message,
488                                           (LPARAM)SEGPTR_GET(hook) );
489                            SEGPTR_FREE(hook);
490                        }
491                    }
492
493                 if (remove)
494                     QUEUE_RemoveMsg( sysMsgQueue, pos );
495                 /* continue */
496
497            case SYSQ_MSG_CONTINUE:
498                 continue;
499
500            case SYSQ_MSG_ABANDON: 
501                 return FALSE;
502         }
503
504         if (remove)
505         {
506             if (HOOK_IsHooked( WH_JOURNALRECORD )) MSG_JournalRecordMsg( msg );
507             QUEUE_RemoveMsg( sysMsgQueue, pos );
508         }
509         return TRUE;
510     }
511     return FALSE;
512 }
513
514
515 /**********************************************************************
516  *           SetDoubleClickTime16   (USER.20)
517  */
518 void SetDoubleClickTime16( UINT16 interval )
519 {
520     SetDoubleClickTime32( interval );
521 }               
522
523
524 /**********************************************************************
525  *           SetDoubleClickTime32   (USER32.479)
526  */
527 BOOL32 SetDoubleClickTime32( UINT32 interval )
528 {
529     doubleClickSpeed = interval ? interval : 500;
530     return TRUE;
531 }               
532
533
534 /**********************************************************************
535  *           GetDoubleClickTime16   (USER.21)
536  */
537 UINT16 GetDoubleClickTime16(void)
538 {
539     return doubleClickSpeed;
540 }               
541
542
543 /**********************************************************************
544  *           GetDoubleClickTime32   (USER32.238)
545  */
546 UINT32 GetDoubleClickTime32(void)
547 {
548     return doubleClickSpeed;
549 }               
550
551
552 /***********************************************************************
553  *           MSG_SendMessage
554  *
555  * Implementation of an inter-task SendMessage.
556  */
557 static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg,
558                                 WPARAM32 wParam, LPARAM lParam, WORD flags )
559 {
560     INT32         prevSMRL = debugSMRL;
561     QSMCTRL       qCtrl = { 0, 1};
562     MESSAGEQUEUE *queue, *destQ;
563
564     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return 0;
565     if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
566
567     if (IsTaskLocked() || !IsWindow32(hwnd)) return 0;
568
569     debugSMRL+=4;
570     dprintf_sendmsg(stddeb,"%*sSM: %s [%04x] (%04x -> %04x)\n", 
571                     prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
572
573     if( !(queue->wakeBits & QS_SMPARAMSFREE) )
574     {
575       dprintf_sendmsg(stddeb,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
576       queue->changeBits &= ~QS_SMPARAMSFREE;
577       QUEUE_WaitBits( QS_SMPARAMSFREE );
578     }
579
580     /* resume sending */ 
581
582     queue->hWnd       = hwnd;
583     queue->msg        = msg;
584     queue->wParam     = LOWORD(wParam);
585     queue->wParamHigh = HIWORD(wParam);
586     queue->lParam     = lParam;
587     queue->hPrevSendingTask = destQ->hSendingTask;
588     destQ->hSendingTask = GetTaskQueue(0);
589
590     queue->wakeBits &= ~QS_SMPARAMSFREE;
591     queue->flags = (queue->flags & ~(QUEUE_SM_WIN32|QUEUE_SM_UNICODE)) | flags;
592
593     dprintf_sendmsg(stddeb,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
594
595     queue->smResultInit = &qCtrl;
596
597     QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
598
599     /* perform task switch and wait for the result */
600
601     while( qCtrl.bPending )
602     {
603       if (!(queue->wakeBits & QS_SMRESULT))
604       {
605         queue->changeBits &= ~QS_SMRESULT;
606         DirectedYield( destQ->hTask );
607         QUEUE_WaitBits( QS_SMRESULT );
608         dprintf_sendmsg(stddeb,"\tsm: have result!\n");
609       }
610       /* got something */
611
612       dprintf_sendmsg(stddeb,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult );
613
614       if (queue->smResult) { /* FIXME, smResult should always be set */
615         queue->smResult->lResult = queue->SendMessageReturn;
616         queue->smResult->bPending = FALSE;
617       }
618       queue->wakeBits &= ~QS_SMRESULT;
619
620       if( queue->smResult != &qCtrl )
621           dprintf_sendmsg(stddeb,"%*ssm: weird scenes inside the goldmine!\n", prevSMRL, "");
622     }
623     queue->smResultInit = NULL;
624     
625     dprintf_sendmsg(stddeb,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult);
626     debugSMRL-=4;
627
628     return qCtrl.lResult;
629 }
630
631
632 /***********************************************************************
633  *           ReplyMessage16   (USER.115)
634  */
635 void ReplyMessage16( LRESULT result )
636 {
637     MESSAGEQUEUE *senderQ;
638     MESSAGEQUEUE *queue;
639
640     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
641
642     dprintf_msg(stddeb,"ReplyMessage, queue %04x\n", queue->self);
643
644     while( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
645     {
646       dprintf_msg(stddeb,"\trpm: replying to %04x (%04x -> %04x)\n",
647                           queue->msg, queue->self, senderQ->self);
648
649       if( queue->wakeBits & QS_SENDMESSAGE )
650       {
651         QUEUE_ReceiveMessage( queue );
652         continue; /* ReceiveMessage() already called us */
653       }
654
655       if(!(senderQ->wakeBits & QS_SMRESULT) ) break;
656       OldYield();
657     } 
658     if( !senderQ ) { dprintf_msg(stddeb,"\trpm: done\n"); return; }
659
660     senderQ->SendMessageReturn = result;
661     dprintf_msg(stddeb,"\trpm: smResult = %08x, result = %08lx\n", 
662                         (unsigned)queue->smResultCurrent, result );
663
664     senderQ->smResult = queue->smResultCurrent;
665     queue->InSendMessageHandle = 0;
666
667     QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
668     DirectedYield( queue->hSendingTask );
669 }
670
671
672 /***********************************************************************
673  *           MSG_PeekMessage
674  */
675 static BOOL32 MSG_PeekMessage( LPMSG16 msg, HWND16 hwnd, WORD first, WORD last,
676                                WORD flags, BOOL32 peek )
677 {
678     int pos, mask;
679     MESSAGEQUEUE *msgQueue;
680     HQUEUE16 hQueue;
681
682 #ifdef CONFIG_IPC
683     DDE_TestDDE(hwnd);  /* do we have dde handling in the window ?*/
684     DDE_GetRemoteMessage();
685 #endif  /* CONFIG_IPC */
686
687     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
688     if (first || last)
689     {
690         if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
691         if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
692              ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
693         if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
694         if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
695         if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
696     }
697     else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
698
699     if (IsTaskLocked()) flags |= PM_NOYIELD;
700
701     while(1)
702     {    
703         hQueue   = GetTaskQueue(0);
704         msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
705         if (!msgQueue) return FALSE;
706         msgQueue->changeBits = 0;
707
708         /* First handle a message put by SendMessage() */
709
710         while (msgQueue->wakeBits & QS_SENDMESSAGE)
711             QUEUE_ReceiveMessage( msgQueue );
712
713         /* Now handle a WM_QUIT message */
714
715         if (msgQueue->wPostQMsg &&
716            (!first || WM_QUIT >= first) && 
717            (!last || WM_QUIT <= last) )
718         {
719             msg->hwnd    = hwnd;
720             msg->message = WM_QUIT;
721             msg->wParam  = msgQueue->wExitCode;
722             msg->lParam  = 0;
723             if (flags & PM_REMOVE) msgQueue->wPostQMsg = 0;
724             break;
725         }
726     
727         /* Now find a normal message */
728
729         if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
730             ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
731         {
732             QMSG *qmsg = &msgQueue->messages[pos];
733             *msg = qmsg->msg;
734             msgQueue->GetMessageTimeVal      = msg->time;
735             msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
736             msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
737
738             if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
739             break;
740         }
741
742         msgQueue->changeBits |= MSG_JournalPlayBackMsg();
743
744         /* Now find a hardware event */
745
746         if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
747             MSG_PeekHardwareMsg( msg, hwnd, MAKELONG(first,last), flags & PM_REMOVE ))
748         {
749             /* Got one */
750             msgQueue->GetMessageTimeVal      = msg->time;
751             msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
752             msgQueue->GetMessageExtraInfoVal = 0;  /* Always 0 for now */
753             break;
754         }
755
756         /* Check again for SendMessage */
757
758         while (msgQueue->wakeBits & QS_SENDMESSAGE)
759             QUEUE_ReceiveMessage( msgQueue );
760
761         /* Now find a WM_PAINT message */
762
763         if ((msgQueue->wakeBits & mask) & QS_PAINT)
764         {
765             WND* wndPtr;
766             msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
767             msg->message = WM_PAINT;
768             msg->wParam = 0;
769             msg->lParam = 0;
770
771             if ((wndPtr = WIN_FindWndPtr(msg->hwnd)))
772             {
773                 if( wndPtr->dwStyle & WS_MINIMIZE &&
774                     wndPtr->class->hIcon )
775                 {
776                     msg->message = WM_PAINTICON;
777                     msg->wParam = 1;
778                 }
779
780                 if( !hwnd || msg->hwnd == hwnd || IsChild16(hwnd,msg->hwnd) )
781                 {
782                     if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
783                     {
784                         wndPtr->flags &= ~WIN_INTERNAL_PAINT;
785                         QUEUE_DecPaintCount( hQueue );
786                     }
787                     break;
788                 }
789             }
790         }
791
792         /* Check for timer messages, but yield first */
793
794         if (!(flags & PM_NOYIELD))
795         {
796             UserYield();
797             while (msgQueue->wakeBits & QS_SENDMESSAGE)
798                 QUEUE_ReceiveMessage( msgQueue );
799         }
800         if ((msgQueue->wakeBits & mask) & QS_TIMER)
801         {
802             if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
803         }
804
805         if (peek)
806         {
807             if (!(flags & PM_NOYIELD)) UserYield();
808             return FALSE;
809         }
810         msgQueue->wakeMask = mask;
811         QUEUE_WaitBits( mask );
812     }
813
814       /* We got a message */
815     if (flags & PM_REMOVE)
816     {
817         WORD message = msg->message;
818
819         if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
820         {
821             BYTE *p = &QueueKeyStateTable[msg->wParam & 0xff];
822
823             if (!(*p & 0x80))
824                 *p ^= 0x01;
825             *p |= 0x80;
826         }
827         else if (message == WM_KEYUP || message == WM_SYSKEYUP)
828             QueueKeyStateTable[msg->wParam & 0xff] &= ~0x80;
829     }
830     if (peek) return TRUE;
831     else return (msg->message != WM_QUIT);
832 }
833
834
835 /***********************************************************************
836  *           MSG_InternalGetMessage
837  *
838  * GetMessage() function for internal use. Behave like GetMessage(),
839  * but also call message filters and optionally send WM_ENTERIDLE messages.
840  * 'hwnd' must be the handle of the dialog or menu window.
841  * 'code' is the message filter value (MSGF_??? codes).
842  */
843 BOOL32 MSG_InternalGetMessage( MSG16 *msg, HWND32 hwnd, HWND32 hwndOwner,
844                                WPARAM32 code, WORD flags, BOOL32 sendIdle ) 
845 {
846     for (;;)
847     {
848         if (sendIdle)
849         {
850             if (!MSG_PeekMessage( msg, 0, 0, 0, flags, TRUE ))
851             {
852                   /* No message present -> send ENTERIDLE and wait */
853                 if (IsWindow32(hwndOwner))
854                     SendMessage16( hwndOwner, WM_ENTERIDLE,
855                                    code, (LPARAM)hwnd );
856                 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
857             }
858         }
859         else  /* Always wait for a message */
860             MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
861
862         /* Call message filters */
863
864         if (HOOK_IsHooked( WH_SYSMSGFILTER ) || HOOK_IsHooked( WH_MSGFILTER ))
865         {
866             MSG16 *pmsg = SEGPTR_NEW(MSG16);
867             if (pmsg)
868             {
869                 BOOL32 ret;
870                 *pmsg = *msg;
871                 ret = ((BOOL16)HOOK_CallHooks16( WH_SYSMSGFILTER, code, 0,
872                                                  (LPARAM)SEGPTR_GET(pmsg) ) ||
873                        (BOOL16)HOOK_CallHooks16( WH_MSGFILTER, code, 0,
874                                                  (LPARAM)SEGPTR_GET(pmsg) ));
875                 SEGPTR_FREE(pmsg);
876                 if (ret)
877                 {
878                     /* Message filtered -> remove it from the queue */
879                     /* if it's still there. */
880                     if (!(flags & PM_REMOVE))
881                         MSG_PeekMessage( msg, 0, 0, 0, PM_REMOVE, TRUE );
882                     continue;
883                 }
884             }
885         }
886
887         return (msg->message != WM_QUIT);
888     }
889 }
890
891
892 /***********************************************************************
893  *           PeekMessage16   (USER.109)
894  */
895 BOOL16 PeekMessage16( LPMSG16 msg, HWND16 hwnd, UINT16 first,
896                       UINT16 last, UINT16 flags )
897 {
898     return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
899 }
900
901
902 /***********************************************************************
903  *           GetMessage16   (USER.108)
904  */
905 BOOL16 GetMessage16( SEGPTR msg, HWND16 hwnd, UINT16 first, UINT16 last ) 
906 {
907     MSG16 *lpmsg = (MSG16 *)PTR_SEG_TO_LIN(msg);
908     MSG_PeekMessage( lpmsg,
909                      hwnd, first, last, PM_REMOVE, FALSE );
910
911     dprintf_msg(stddeb,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg->message,
912                                                                  hwnd, first, last );
913     HOOK_CallHooks16( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
914     return (lpmsg->message != WM_QUIT);
915 }
916
917
918 /***********************************************************************
919  *           PostMessage16   (USER.110)
920  */
921 BOOL16 PostMessage16( HWND16 hwnd, UINT16 message, WPARAM16 wParam,
922                       LPARAM lParam )
923 {
924     MSG16       msg;
925     WND         *wndPtr;
926
927     msg.hwnd    = hwnd;
928     msg.message = message;
929     msg.wParam  = wParam;
930     msg.lParam  = lParam;
931     msg.time    = GetTickCount();
932     msg.pt.x    = 0;
933     msg.pt.y    = 0;
934
935 #ifdef CONFIG_IPC
936     if (DDE_PostMessage(&msg))
937        return TRUE;
938 #endif  /* CONFIG_IPC */
939     
940     if (hwnd == HWND_BROADCAST)
941     {
942         dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
943         for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
944         {
945             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
946             {
947                 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
948                             wndPtr->hwndSelf, message, wParam, lParam);
949                 PostMessage16( wndPtr->hwndSelf, message, wParam, lParam );
950             }
951         }
952         dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
953         return TRUE;
954     }
955
956     wndPtr = WIN_FindWndPtr( hwnd );
957     if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
958
959     return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
960 }
961
962
963 /***********************************************************************
964  *           PostMessage32A   (USER32.418)
965  */
966 BOOL32 PostMessage32A( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
967                        LPARAM lParam )
968 {
969     /* FIXME */
970     return PostMessage16( hwnd, message, wParam, lParam );
971 }
972
973
974 /***********************************************************************
975  *           PostMessage32W   (USER32.419)
976  */
977 BOOL32 PostMessage32W( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
978                        LPARAM lParam )
979 {
980     /* FIXME */
981     return PostMessage16( hwnd, message, wParam, lParam );
982 }
983
984
985 /***********************************************************************
986  *           PostAppMessage16   (USER.116)
987  */
988 BOOL16 PostAppMessage16( HTASK16 hTask, UINT16 message, WPARAM16 wParam,
989                          LPARAM lParam )
990 {
991     MSG16 msg;
992
993     if (GetTaskQueue(hTask) == 0) return FALSE;
994     msg.hwnd    = 0;
995     msg.message = message;
996     msg.wParam  = wParam;
997     msg.lParam  = lParam;
998     msg.time    = GetTickCount();
999     msg.pt.x    = 0;
1000     msg.pt.y    = 0;
1001
1002     return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
1003 }
1004
1005
1006 /***********************************************************************
1007  *           SendMessage16   (USER.111)
1008  */
1009 LRESULT SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam)
1010 {
1011     WND * wndPtr;
1012     WND **list, **ppWnd;
1013     LRESULT ret;
1014
1015 #ifdef CONFIG_IPC
1016     MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
1017     if (DDE_SendMessage(&DDE_msg)) return TRUE;
1018 #endif  /* CONFIG_IPC */
1019
1020     if (hwnd == HWND_BROADCAST)
1021     {
1022         if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1023             return TRUE;
1024         dprintf_msg(stddeb,"SendMessage // HWND_BROADCAST !\n");
1025         for (ppWnd = list; *ppWnd; ppWnd++)
1026         {
1027             wndPtr = *ppWnd;
1028             if (!IsWindow32(wndPtr->hwndSelf)) continue;
1029             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1030             {
1031                 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
1032                             wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
1033                 SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
1034             }
1035         }
1036         HeapFree( SystemHeap, 0, list );
1037         dprintf_msg(stddeb,"SendMessage // End of HWND_BROADCAST !\n");
1038         return TRUE;
1039     }
1040
1041     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1042     {
1043         LPCWPSTRUCT16 pmsg;
1044
1045         if ((pmsg = SEGPTR_NEW(CWPSTRUCT16)))
1046         {
1047             pmsg->hwnd   = hwnd;
1048             pmsg->message= msg;
1049             pmsg->wParam = wParam;
1050             pmsg->lParam = lParam;
1051             HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1,
1052                               (LPARAM)SEGPTR_GET(pmsg) );
1053             hwnd   = pmsg->hwnd;
1054             msg    = pmsg->message;
1055             wParam = pmsg->wParam;
1056             lParam = pmsg->lParam;
1057             SEGPTR_FREE( pmsg );
1058         }
1059     }
1060
1061     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1062     {
1063         fprintf( stderr, "SendMessage16: invalid hwnd %04x\n", hwnd );
1064         return 0;
1065     }
1066     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1067         return 0;  /* Don't send anything if the task is dying */
1068
1069     SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
1070
1071     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1072         ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg,
1073                                wParam, lParam, 0 );
1074     else
1075         ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1076                                 hwnd, msg, wParam, lParam );
1077
1078     SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
1079     return ret;
1080 }
1081
1082 /************************************************************************
1083  *           MSG_CallWndProcHook32
1084  */
1085 static void  MSG_CallWndProcHook32( LPMSG32 pmsg, BOOL32 bUnicode )
1086 {
1087    CWPSTRUCT32 cwp;
1088
1089    cwp.lParam = pmsg->lParam;
1090    cwp.wParam = pmsg->wParam;
1091    cwp.message = pmsg->message;
1092    cwp.hwnd = pmsg->hwnd;
1093
1094    if (bUnicode) HOOK_CallHooks32W(WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp);
1095    else HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 1, (LPARAM)&cwp );
1096
1097    pmsg->lParam = cwp.lParam;
1098    pmsg->wParam = cwp.wParam;
1099    pmsg->message = cwp.message;
1100    pmsg->hwnd = cwp.hwnd;
1101 }
1102
1103 /***********************************************************************
1104  *           SendMessage32A   (USER32.453)
1105  */
1106 LRESULT SendMessage32A(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1107 {
1108     WND * wndPtr;
1109     WND **list, **ppWnd;
1110     LRESULT ret;
1111
1112     if (hwnd == HWND_BROADCAST)
1113     {
1114         if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1115             return TRUE;
1116         for (ppWnd = list; *ppWnd; ppWnd++)
1117         {
1118             wndPtr = *ppWnd;
1119             if (!IsWindow32(wndPtr->hwndSelf)) continue;
1120             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1121                 SendMessage32A( wndPtr->hwndSelf, msg, wParam, lParam );
1122         }
1123         HeapFree( SystemHeap, 0, list );
1124         return TRUE;
1125     }
1126
1127     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1128         MSG_CallWndProcHook32( (LPMSG32)&hwnd, FALSE);
1129
1130     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1131     {
1132         fprintf( stderr, "SendMessage32A: invalid hwnd %08x\n", hwnd );
1133         return 0;
1134     }
1135
1136     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1137         return 0;  /* Don't send anything if the task is dying */
1138
1139     SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1140
1141     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1142         ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
1143                                QUEUE_SM_WIN32 );
1144     else
1145         ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1146                                  hwnd, msg, wParam, lParam );
1147
1148     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1149     return ret;
1150 }
1151
1152
1153 /***********************************************************************
1154  *           SendMessage32W   (USER32.458)
1155  */
1156 LRESULT SendMessage32W(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1157 {
1158     WND * wndPtr;
1159     WND **list, **ppWnd;
1160     LRESULT ret;
1161
1162     if (hwnd == HWND_BROADCAST)
1163     {
1164         if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
1165             return TRUE;
1166         for (ppWnd = list; *ppWnd; ppWnd++)
1167         {
1168             wndPtr = *ppWnd;
1169             if (!IsWindow32(wndPtr->hwndSelf)) continue;
1170             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1171                 SendMessage32W( wndPtr->hwndSelf, msg, wParam, lParam );
1172         }
1173         HeapFree( SystemHeap, 0, list );
1174         return TRUE;
1175     }
1176
1177     if (HOOK_IsHooked( WH_CALLWNDPROC ))
1178         MSG_CallWndProcHook32( (LPMSG32)&hwnd, TRUE);
1179
1180     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1181     {
1182         fprintf( stderr, "SendMessage32W: invalid hwnd %08x\n", hwnd );
1183         return 0;
1184     }
1185     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
1186         return 0;  /* Don't send anything if the task is dying */
1187
1188     SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1189
1190     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1191         ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam,
1192                                 QUEUE_SM_WIN32 | QUEUE_SM_UNICODE );
1193     else
1194         ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1195                                  hwnd, msg, wParam, lParam );
1196
1197     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1198     return ret;
1199 }
1200
1201
1202 /***********************************************************************
1203  *           WaitMessage    (USER.112) (USER32.577)
1204  */
1205 void WaitMessage( void )
1206 {
1207     QUEUE_WaitBits( QS_ALLINPUT );
1208 }
1209
1210
1211 struct accent_char
1212 {
1213     BYTE ac_accent;
1214     BYTE ac_char;
1215     BYTE ac_result;
1216 };
1217
1218 static const struct accent_char accent_chars[] =
1219 {
1220 /* A good idea should be to read /usr/X11/lib/X11/locale/iso8859-x/Compose */
1221     {'`', 'A', '\300'},  {'`', 'a', '\340'},
1222     {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
1223     {'^', 'A', '\302'},  {'^', 'a', '\342'},
1224     {'~', 'A', '\303'},  {'~', 'a', '\343'},
1225     {'"', 'A', '\304'},  {'"', 'a', '\344'},
1226     {'O', 'A', '\305'},  {'o', 'a', '\345'},
1227     {'0', 'A', '\305'},  {'0', 'a', '\345'},
1228     {'A', 'A', '\305'},  {'a', 'a', '\345'},
1229     {'A', 'E', '\306'},  {'a', 'e', '\346'},
1230     {',', 'C', '\307'},  {',', 'c', '\347'},
1231     {'`', 'E', '\310'},  {'`', 'e', '\350'},
1232     {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
1233     {'^', 'E', '\312'},  {'^', 'e', '\352'},
1234     {'"', 'E', '\313'},  {'"', 'e', '\353'},
1235     {'`', 'I', '\314'},  {'`', 'i', '\354'},
1236     {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
1237     {'^', 'I', '\316'},  {'^', 'i', '\356'},
1238     {'"', 'I', '\317'},  {'"', 'i', '\357'},
1239     {'-', 'D', '\320'},  {'-', 'd', '\360'},
1240     {'~', 'N', '\321'},  {'~', 'n', '\361'},
1241     {'`', 'O', '\322'},  {'`', 'o', '\362'},
1242     {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
1243     {'^', 'O', '\324'},  {'^', 'o', '\364'},
1244     {'~', 'O', '\325'},  {'~', 'o', '\365'},
1245     {'"', 'O', '\326'},  {'"', 'o', '\366'},
1246     {'/', 'O', '\330'},  {'/', 'o', '\370'},
1247     {'`', 'U', '\331'},  {'`', 'u', '\371'},
1248     {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
1249     {'^', 'U', '\333'},  {'^', 'u', '\373'},
1250     {'"', 'U', '\334'},  {'"', 'u', '\374'},
1251     {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
1252     {'T', 'H', '\336'},  {'t', 'h', '\376'},
1253     {'s', 's', '\337'},  {'"', 'y', '\377'},
1254     {'s', 'z', '\337'},  {'i', 'j', '\377'},
1255         /* iso-8859-2 uses this */
1256     {'<', 'L', '\245'},  {'<', 'l', '\265'},    /* caron */
1257     {'<', 'S', '\251'},  {'<', 's', '\271'},
1258     {'<', 'T', '\253'},  {'<', 't', '\273'},
1259     {'<', 'Z', '\256'},  {'<', 'z', '\276'},
1260     {'<', 'C', '\310'},  {'<', 'c', '\350'},
1261     {'<', 'E', '\314'},  {'<', 'e', '\354'},
1262     {'<', 'D', '\317'},  {'<', 'd', '\357'},
1263     {'<', 'N', '\322'},  {'<', 'n', '\362'},
1264     {'<', 'R', '\330'},  {'<', 'r', '\370'},
1265     {';', 'A', '\241'},  {';', 'a', '\261'},    /* ogonek */
1266     {';', 'E', '\312'},  {';', 'e', '\332'},
1267     {'\'', 'Z', '\254'}, {'\'', 'z', '\274'},   /* acute */
1268     {'\'', 'R', '\300'}, {'\'', 'r', '\340'},
1269     {'\'', 'L', '\305'}, {'\'', 'l', '\345'},
1270     {'\'', 'C', '\306'}, {'\'', 'c', '\346'},
1271     {'\'', 'N', '\321'}, {'\'', 'n', '\361'},
1272 /*  collision whith S, from iso-8859-9 !!! */
1273     {',', 'S', '\252'},  {',', 's', '\272'},    /* cedilla */
1274     {',', 'T', '\336'},  {',', 't', '\376'},
1275     {'.', 'Z', '\257'},  {'.', 'z', '\277'},    /* dot above */
1276     {'/', 'L', '\243'},  {'/', 'l', '\263'},    /* slash */
1277     {'/', 'D', '\320'},  {'/', 'd', '\360'},
1278     {'(', 'A', '\303'},  {'(', 'a', '\343'},    /* breve */
1279     {'\275', 'O', '\325'}, {'\275', 'o', '\365'},       /* double acute */
1280     {'\275', 'U', '\334'}, {'\275', 'u', '\374'},
1281     {'0', 'U', '\332'},  {'0', 'u', '\372'},    /* ring above */
1282         /* iso-8859-3 uses this */
1283     {'/', 'H', '\241'},  {'/', 'h', '\261'},    /* slash */
1284     {'>', 'H', '\246'},  {'>', 'h', '\266'},    /* circumflex */
1285     {'>', 'J', '\254'},  {'>', 'j', '\274'},
1286     {'>', 'C', '\306'},  {'>', 'c', '\346'},
1287     {'>', 'G', '\330'},  {'>', 'g', '\370'},
1288     {'>', 'S', '\336'},  {'>', 's', '\376'},
1289 /*  collision whith G( from iso-8859-9 !!!   */
1290     {'(', 'G', '\253'},  {'(', 'g', '\273'},    /* breve */
1291     {'(', 'U', '\335'},  {'(', 'u', '\375'},
1292 /*  collision whith I. from iso-8859-3 !!!   */
1293     {'.', 'I', '\251'},  {'.', 'i', '\271'},    /* dot above */
1294     {'.', 'C', '\305'},  {'.', 'c', '\345'},
1295     {'.', 'G', '\325'},  {'.', 'g', '\365'},
1296         /* iso-8859-4 uses this */
1297     {',', 'R', '\243'},  {',', 'r', '\263'},    /* cedilla */
1298     {',', 'L', '\246'},  {',', 'l', '\266'},
1299     {',', 'G', '\253'},  {',', 'g', '\273'},
1300     {',', 'N', '\321'},  {',', 'n', '\361'},
1301     {',', 'K', '\323'},  {',', 'k', '\363'},
1302     {'~', 'I', '\245'},  {'~', 'i', '\265'},    /* tilde */
1303     {'-', 'E', '\252'},  {'-', 'e', '\272'},    /* macron */
1304     {'-', 'A', '\300'},  {'-', 'a', '\340'},
1305     {'-', 'I', '\317'},  {'-', 'i', '\357'},
1306     {'-', 'O', '\322'},  {'-', 'o', '\362'},
1307     {'-', 'U', '\336'},  {'-', 'u', '\376'},
1308     {'/', 'T', '\254'},  {'/', 't', '\274'},    /* slash */
1309     {'.', 'E', '\314'},  {'.', 'e', '\344'},    /* dot above */
1310     {';', 'I', '\307'},  {';', 'i', '\347'},    /* ogonek */
1311     {';', 'U', '\331'},  {';', 'u', '\371'},
1312         /* iso-8859-9 uses this */
1313         /* iso-8859-9 has really bad choosen G( S, and I. as they collide
1314          * whith the same letters on other iso-8859-x (that is they are on
1315          * different places :-( ), if you use turkish uncomment these and
1316          * comment out the lines in iso-8859-2 and iso-8859-3 sections
1317          * FIXME: should be dynamic according to chosen language
1318          *        if/when Wine has turkish support.  
1319          */ 
1320 /*  collision whith G( from iso-8859-3 !!!   */
1321 /*  {'(', 'G', '\320'},  {'(', 'g', '\360'}, */ /* breve */
1322 /*  collision whith S, from iso-8859-2 !!! */
1323 /*  {',', 'S', '\336'},  {',', 's', '\376'}, */ /* cedilla */
1324 /*  collision whith I. from iso-8859-3 !!!   */
1325 /*  {'.', 'I', '\335'},  {'.', 'i', '\375'}, */ /* dot above */
1326 };
1327
1328
1329 /***********************************************************************
1330  *           MSG_DoTranslateMessage
1331  *
1332  * Implementation of TranslateMessage.
1333  *
1334  * TranslateMessage translates virtual-key messages into character-messages,
1335  * as follows :
1336  * WM_KEYDOWN/WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message.
1337  * ditto replacing WM_* with WM_SYS*
1338  * This produces WM_CHAR messages only for keys mapped to ASCII characters
1339  * by the keyboard driver.
1340  */
1341 static BOOL32 MSG_DoTranslateMessage( UINT32 message, HWND32 hwnd,
1342                                       WPARAM32 wParam, LPARAM lParam )
1343 {
1344     static int dead_char;
1345     BYTE wp[2];
1346     
1347     if ((debugging_msg && message != WM_MOUSEMOVE && message != WM_TIMER)
1348         || (debugging_key
1349             && message >= WM_KEYFIRST && message <= WM_KEYLAST))
1350         fprintf(stddeb, "TranslateMessage(%s, %04X, %08lX)\n",
1351                 SPY_GetMsgName(message), wParam, lParam );
1352
1353     if ((message != WM_KEYDOWN) && (message != WM_SYSKEYDOWN)) return FALSE;
1354
1355     dprintf_key( stddeb, "Translating key %04X, scancode %04X\n",
1356                  wParam, HIWORD(lParam) );
1357
1358     /* FIXME : should handle ToAscii yielding 2 */
1359     switch (ToAscii32(wParam, HIWORD(lParam),
1360                       QueueKeyStateTable,(LPWORD)wp, 0)) 
1361     {
1362     case 1 :
1363         message = (message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
1364         /* Should dead chars handling go in ToAscii ? */
1365         if (dead_char)
1366         {
1367             int i;
1368
1369             if (wp[0] == ' ') wp[0] =  dead_char;
1370             if (dead_char == 0xa2) dead_char = '(';
1371             else if (dead_char == 0xa8) dead_char = '"';
1372             else if (dead_char == 0xb2) dead_char = ';';
1373             else if (dead_char == 0xb4) dead_char = '\'';
1374             else if (dead_char == 0xb7) dead_char = '<';
1375             else if (dead_char == 0xb8) dead_char = ',';
1376             else if (dead_char == 0xff) dead_char = '.';
1377             for (i = 0; i < sizeof(accent_chars)/sizeof(accent_chars[0]); i++)
1378                 if ((accent_chars[i].ac_accent == dead_char) &&
1379                     (accent_chars[i].ac_char == wp[0]))
1380                 {
1381                     wp[0] = accent_chars[i].ac_result;
1382                     break;
1383                 }
1384             dead_char = 0;
1385         }
1386         dprintf_key(stddeb, "1 -> PostMessage(%s)\n", SPY_GetMsgName(message));
1387         PostMessage16( hwnd, message, wp[0], lParam );
1388         return TRUE;
1389
1390     case -1 :
1391         message = (message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
1392         dead_char = wp[0];
1393         dprintf_key( stddeb, "-1 -> PostMessage(%s)\n",
1394                      SPY_GetMsgName(message));
1395         PostMessage16( hwnd, message, wp[0], lParam );
1396         return TRUE;
1397     }
1398     return FALSE;
1399 }
1400
1401
1402 /***********************************************************************
1403  *           TranslateMessage16   (USER.113)
1404  */
1405 BOOL16 TranslateMessage16( const MSG16 *msg )
1406 {
1407     return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1408                                    msg->wParam, msg->lParam );
1409 }
1410
1411
1412 /***********************************************************************
1413  *           TranslateMessage32   (USER32.555)
1414  */
1415 BOOL32 TranslateMessage32( const MSG32 *msg )
1416 {
1417     return MSG_DoTranslateMessage( msg->message, msg->hwnd,
1418                                    msg->wParam, msg->lParam );
1419 }
1420
1421
1422 /***********************************************************************
1423  *           DispatchMessage16   (USER.114)
1424  */
1425 LONG DispatchMessage16( const MSG16* msg )
1426 {
1427     WND * wndPtr;
1428     LONG retval;
1429     int painting;
1430     
1431       /* Process timer messages */
1432     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1433     {
1434         if (msg->lParam)
1435         {
1436             return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
1437                                    msg->message, msg->wParam, GetTickCount() );
1438         }
1439     }
1440
1441     if (!msg->hwnd) return 0;
1442     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1443     if (!wndPtr->winproc) return 0;
1444     painting = (msg->message == WM_PAINT);
1445     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1446
1447     SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
1448                       msg->wParam, msg->lParam );
1449     retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1450                                msg->hwnd, msg->message,
1451                                msg->wParam, msg->lParam );
1452     SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval );
1453
1454     if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1455         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1456     {
1457         fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
1458                 msg->hwnd);
1459         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1460         /* Validate the update region to avoid infinite WM_PAINT loop */
1461         ValidateRect32( msg->hwnd, NULL );
1462     }
1463     return retval;
1464 }
1465
1466
1467 /***********************************************************************
1468  *           DispatchMessage32A   (USER32.140)
1469  */
1470 LONG DispatchMessage32A( const MSG32* msg )
1471 {
1472     WND * wndPtr;
1473     LONG retval;
1474     int painting;
1475     
1476       /* Process timer messages */
1477     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1478     {
1479         if (msg->lParam)
1480         {
1481 /*            HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1482             return CallWindowProc32A( (WNDPROC32)msg->lParam, msg->hwnd,
1483                                    msg->message, msg->wParam, GetTickCount() );
1484         }
1485     }
1486
1487     if (!msg->hwnd) return 0;
1488     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1489     if (!wndPtr->winproc) return 0;
1490     painting = (msg->message == WM_PAINT);
1491     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1492 /*    HOOK_CallHooks32A( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1493
1494     SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1495                       msg->wParam, msg->lParam );
1496     retval = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1497                                 msg->hwnd, msg->message,
1498                                 msg->wParam, msg->lParam );
1499     SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1500
1501     if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1502         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1503     {
1504         fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
1505                 msg->hwnd);
1506         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1507         /* Validate the update region to avoid infinite WM_PAINT loop */
1508         ValidateRect32( msg->hwnd, NULL );
1509     }
1510     return retval;
1511 }
1512
1513
1514 /***********************************************************************
1515  *           DispatchMessage32W   (USER32.141)
1516  */
1517 LONG DispatchMessage32W( const MSG32* msg )
1518 {
1519     WND * wndPtr;
1520     LONG retval;
1521     int painting;
1522     
1523       /* Process timer messages */
1524     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1525     {
1526         if (msg->lParam)
1527         {
1528 /*            HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1529             return CallWindowProc32W( (WNDPROC32)msg->lParam, msg->hwnd,
1530                                    msg->message, msg->wParam, GetTickCount() );
1531         }
1532     }
1533
1534     if (!msg->hwnd) return 0;
1535     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1536     if (!wndPtr->winproc) return 0;
1537     painting = (msg->message == WM_PAINT);
1538     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1539 /*    HOOK_CallHooks32W( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1540
1541     SPY_EnterMessage( SPY_DISPATCHMESSAGE32, msg->hwnd, msg->message,
1542                       msg->wParam, msg->lParam );
1543     retval = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1544                                 msg->hwnd, msg->message,
1545                                 msg->wParam, msg->lParam );
1546     SPY_ExitMessage( SPY_RESULT_OK32, msg->hwnd, msg->message, retval );
1547
1548     if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1549         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1550     {
1551         fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
1552                 msg->hwnd);
1553         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1554         /* Validate the update region to avoid infinite WM_PAINT loop */
1555         ValidateRect32( msg->hwnd, NULL );
1556     }
1557     return retval;
1558 }
1559
1560
1561 /***********************************************************************
1562  *           RegisterWindowMessage16   (USER.118)
1563  */
1564 WORD RegisterWindowMessage16( SEGPTR str )
1565 {
1566     dprintf_msg(stddeb, "RegisterWindowMessage16: %08lx\n", (DWORD)str );
1567     return GlobalAddAtom16( str );
1568 }
1569
1570
1571 /***********************************************************************
1572  *           RegisterWindowMessage32A   (USER32.436)
1573  */
1574 WORD RegisterWindowMessage32A( LPCSTR str )
1575 {
1576     dprintf_msg(stddeb, "RegisterWindowMessage32A: %s\n", str );
1577     return GlobalAddAtom32A( str );
1578 }
1579
1580
1581 /***********************************************************************
1582  *           RegisterWindowMessage32W   (USER32.437)
1583  */
1584 WORD RegisterWindowMessage32W( LPCWSTR str )
1585 {
1586     dprintf_msg(stddeb, "RegisterWindowMessage32W: %p\n", str );
1587     return GlobalAddAtom32W( str );
1588 }
1589
1590
1591 /***********************************************************************
1592  *           GetTickCount   (USER.13) (KERNEL32.299)
1593  */
1594 DWORD GetTickCount(void)
1595 {
1596     struct timeval t;
1597     gettimeofday( &t, NULL );
1598     return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
1599 }
1600
1601
1602 /***********************************************************************
1603  *           GetCurrentTime16    (USER.15)
1604  *
1605  * (effectively identical to GetTickCount)
1606  */
1607 DWORD GetCurrentTime16(void)
1608 {
1609     return GetTickCount();
1610 }
1611
1612
1613 /***********************************************************************
1614  *           InSendMessage16    (USER.192)
1615  */
1616 BOOL16 InSendMessage16(void)
1617 {
1618     return InSendMessage32();
1619 }
1620
1621
1622 /***********************************************************************
1623  *           InSendMessage32    (USER32.319)
1624  */
1625 BOOL32 InSendMessage32(void)
1626 {
1627     MESSAGEQUEUE *queue;
1628
1629     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
1630         return 0;
1631     return (BOOL32)queue->InSendMessageHandle;
1632 }