Release 960928
[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 "spy.h"
20 #include "winpos.h"
21 #include "atom.h"
22 #include "dde.h"
23 #include "queue.h"
24 #include "winproc.h"
25 #include "stddebug.h"
26 /* #define DEBUG_MSG */
27 #include "debug.h"
28
29 #define WM_NCMOUSEFIRST         WM_NCMOUSEMOVE
30 #define WM_NCMOUSELAST          WM_NCMBUTTONDBLCLK
31
32 #define HWND_BROADCAST16  ((HWND16)0xffff)
33 #define HWND_BROADCAST32  ((HWND32)0xffffffff)
34
35 #define ASCII_CHAR_HACK 0x0800 
36
37 typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP, SYSQ_MSG_ACCEPT } SYSQ_STATUS;
38
39 extern WPARAM   lastEventChar;                           /* event.c */
40 extern BOOL MouseButtonsStates[3];
41 extern BOOL AsyncMouseButtonsStates[3];
42 extern BYTE KeyStateTable[256];
43 extern BYTE AsyncKeyStateTable[256];
44
45 extern MESSAGEQUEUE *pCursorQueue;                       /* queue.c */
46 extern MESSAGEQUEUE *pActiveQueue;
47
48 DWORD MSG_WineStartTicks; /* Ticks at Wine startup */
49
50 static WORD doubleClickSpeed = 452;
51 static INT32 debugSMRL = 0;       /* intertask SendMessage() recursion level */
52
53 /***********************************************************************
54  *           MSG_TranslateMouseMsg
55  *
56  * Translate an mouse hardware event into a real mouse message.
57  * Return value indicates whether the translated message must be passed
58  * to the user.
59  * Actions performed:
60  * - Find the window for this message.
61  * - Translate button-down messages in double-clicks.
62  * - Send the WM_NCHITTEST message to find where the cursor is.
63  * - Activate the window if needed.
64  * - Translate the message into a non-client message, or translate
65  *   the coordinates to client coordinates.
66  * - Send the WM_SETCURSOR message.
67  */
68 static SYSQ_STATUS MSG_TranslateMouseMsg( MSG16 *msg, BOOL remove )
69 {
70     WND *pWnd;
71     BOOL eatMsg = FALSE;
72     INT16 hittest;
73     MOUSEHOOKSTRUCT16 *hook;
74     BOOL32 ret;
75     static DWORD lastClickTime = 0;
76     static WORD  lastClickMsg = 0;
77     static POINT16 lastClickPos = { 0, 0 };
78     POINT16 pt = msg->pt;
79     MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16(GetTaskQueue(0));
80
81     BOOL mouseClick = ((msg->message == WM_LBUTTONDOWN) ||
82                        (msg->message == WM_RBUTTONDOWN) ||
83                        (msg->message == WM_MBUTTONDOWN));
84
85       /* Find the window */
86
87     if ((msg->hwnd = GetCapture16()) != 0)
88     {
89         BOOL32 ret;
90
91         ScreenToClient16( msg->hwnd, &pt );
92         msg->lParam = MAKELONG( pt.x, pt.y );
93         /* No need to further process the message */
94
95         if (!HOOK_GetHook( WH_MOUSE, GetTaskQueue(0)) ||
96             !(hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16)))
97             return SYSQ_MSG_ACCEPT;
98         hook->pt           = msg->pt;
99         hook->hwnd         = msg->hwnd;
100         hook->wHitTestCode = HTCLIENT;
101         hook->dwExtraInfo  = 0;
102         ret = !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
103                                msg->message, (LPARAM)SEGPTR_GET(hook));
104         SEGPTR_FREE(hook);
105         return ret ? SYSQ_MSG_ACCEPT : SYSQ_MSG_SKIP ;
106     }
107    
108     hittest = WINPOS_WindowFromPoint( msg->pt, &pWnd );
109     if (pWnd->hmemTaskQ != GetTaskQueue(0))
110     {
111         /* Not for the current task */
112         if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
113         /* Wake up the other task */
114         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
115         if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE );
116         return SYSQ_MSG_ABANDON;
117     }
118     pCursorQueue = queue;
119     msg->hwnd    = pWnd->hwndSelf;
120
121     if ((hittest != HTERROR) && mouseClick)
122     {
123         HWND hwndTop = WIN_GetTopParent( msg->hwnd );
124
125         /* Send the WM_PARENTNOTIFY message */
126
127         WIN_SendParentNotify( msg->hwnd, msg->message, 0,
128                               MAKELPARAM( msg->pt.x, msg->pt.y ) );
129
130         /* Activate the window if needed */
131
132         if (msg->hwnd != GetActiveWindow() &&
133             msg->hwnd != GetDesktopWindow16())
134         {
135             LONG ret = SendMessage16( msg->hwnd, WM_MOUSEACTIVATE, hwndTop,
136                                     MAKELONG( hittest, msg->message ) );
137
138             if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
139                 eatMsg = TRUE;
140
141             if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT)) 
142                 && hwndTop != GetActiveWindow() )
143                 WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE );
144         }
145     }
146
147       /* Send the WM_SETCURSOR message */
148
149     SendMessage16( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
150                    MAKELONG( hittest, msg->message ));
151     if (eatMsg) return SYSQ_MSG_SKIP;
152
153       /* Check for double-click */
154
155     if (mouseClick)
156     {
157         BOOL dbl_click = FALSE;
158
159         if ((msg->message == lastClickMsg) &&
160             (msg->time - lastClickTime < doubleClickSpeed) &&
161             (abs(msg->pt.x - lastClickPos.x) < SYSMETRICS_CXDOUBLECLK/2) &&
162             (abs(msg->pt.y - lastClickPos.y) < SYSMETRICS_CYDOUBLECLK/2))
163             dbl_click = TRUE;
164
165         if (dbl_click && (hittest == HTCLIENT))
166         {
167             /* Check whether window wants the double click message. */
168             dbl_click = (pWnd->class->style & CS_DBLCLKS) != 0;
169         }
170
171         if (dbl_click) switch(msg->message)
172         {
173             case WM_LBUTTONDOWN: msg->message = WM_LBUTTONDBLCLK; break;
174             case WM_RBUTTONDOWN: msg->message = WM_RBUTTONDBLCLK; break;
175             case WM_MBUTTONDOWN: msg->message = WM_MBUTTONDBLCLK; break;
176         }
177
178         if (remove)
179         {
180             lastClickTime = msg->time;
181             lastClickMsg  = msg->message;
182             lastClickPos  = msg->pt;
183         }
184     }
185
186       /* Build the translated message */
187
188     if (hittest == HTCLIENT)
189         ScreenToClient16( msg->hwnd, &pt );
190     else
191     {
192         msg->wParam = hittest;
193         msg->message += WM_NCLBUTTONDOWN - WM_LBUTTONDOWN;
194     }
195     msg->lParam = MAKELONG( pt.x, pt.y );
196
197     /* Call the WH_MOUSE hook */
198
199     if (!HOOK_GetHook( WH_MOUSE, GetTaskQueue(0)) ||
200         !(hook = SEGPTR_NEW(MOUSEHOOKSTRUCT16)))
201         return SYSQ_MSG_ACCEPT;
202
203     hook->pt           = msg->pt;
204     hook->hwnd         = msg->hwnd;
205     hook->wHitTestCode = hittest;
206     hook->dwExtraInfo  = 0;
207     ret = !HOOK_CallHooks( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
208                            msg->message, (LPARAM)SEGPTR_GET(hook) );
209     SEGPTR_FREE(hook);
210     return ret ? SYSQ_MSG_ACCEPT : SYSQ_MSG_SKIP;
211 }
212
213
214 /***********************************************************************
215  *           MSG_TranslateKeyboardMsg
216  *
217  * Translate an keyboard hardware event into a real message.
218  * Return value indicates whether the translated message must be passed
219  * to the user.
220  */
221 static SYSQ_STATUS MSG_TranslateKeyboardMsg( MSG16 *msg, BOOL remove )
222 {
223     WND *pWnd;
224
225       /* Should check Ctrl-Esc and PrintScreen here */
226
227     msg->hwnd = GetFocus16();
228     if (!msg->hwnd)
229     {
230           /* Send the message to the active window instead,  */
231           /* translating messages to their WM_SYS equivalent */
232
233         msg->hwnd = GetActiveWindow();
234
235         if( msg->message < WM_SYSKEYDOWN )
236             msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
237     }
238     pWnd = WIN_FindWndPtr( msg->hwnd );
239     if (pWnd && (pWnd->hmemTaskQ != GetTaskQueue(0)))
240     {
241         /* Not for the current task */
242         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) );
243         if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
244         /* Wake up the other task */
245         queue = (MESSAGEQUEUE *)GlobalLock16( pWnd->hmemTaskQ );
246         if (queue) QUEUE_SetWakeBit( queue, QS_KEY );
247         return SYSQ_MSG_ABANDON;
248     }
249     return (HOOK_CallHooks( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
250                             msg->wParam, msg->lParam ))
251             ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT;
252 }
253
254
255 /***********************************************************************
256  *           MSG_JournalRecordMsg
257  *
258  * Build an EVENTMSG structure and call JOURNALRECORD hook
259  */
260 static void MSG_JournalRecordMsg( MSG16 *msg )
261 {
262     EVENTMSG16 *event = SEGPTR_NEW(EVENTMSG16);
263     if (!event) return;
264     event->message = msg->message;
265     event->time = msg->time;
266     if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
267     {
268         event->paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
269         event->paramH = msg->lParam & 0x7FFF;  
270         if (HIWORD(msg->lParam) & 0x0100)
271             event->paramH |= 0x8000;               /* special_key - bit */
272         HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0,
273                         (LPARAM)SEGPTR_GET(event) );
274     }
275     else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
276     {
277         event->paramL = LOWORD(msg->lParam);       /* X pos */
278         event->paramH = HIWORD(msg->lParam);       /* Y pos */ 
279         ClientToScreen16( msg->hwnd, (LPPOINT16)&event->paramL );
280         HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0,
281                         (LPARAM)SEGPTR_GET(event) );
282     }
283     else if ((msg->message >= WM_NCMOUSEFIRST) &&
284              (msg->message <= WM_NCMOUSELAST))
285     {
286         event->paramL = LOWORD(msg->lParam);       /* X pos */
287         event->paramH = HIWORD(msg->lParam);       /* Y pos */ 
288         event->message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
289         HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0,
290                         (LPARAM)SEGPTR_GET(event) );
291     }
292     SEGPTR_FREE(event);
293 }
294
295 /*****************************************************************
296  *              MSG_JournalPlayBackIsAscii
297  */
298 static BOOL MSG_JournalPlayBackIsAscii(WPARAM wParam)
299 {
300  return ((wParam>VK_HELP && wParam<VK_F1) || 
301           wParam == VK_SPACE  ||
302           wParam == VK_ESCAPE ||
303           wParam == VK_RETURN ||
304           wParam == VK_TAB    ||
305           wParam == VK_BACK);   
306 }
307
308
309 /***********************************************************************
310  *          MSG_JournalPlayBackMsg
311  *
312  * Get an EVENTMSG struct via call JOURNALPAYBACK hook function 
313  */
314 static int MSG_JournalPlayBackMsg(void)
315 {
316  EVENTMSG16 *tmpMsg;
317  long wtime,lParam;
318  WORD keyDown,i,wParam,result=0;
319
320  if ( HOOK_GetHook(WH_JOURNALPLAYBACK, 0) )
321  {
322   tmpMsg = SEGPTR_NEW(EVENTMSG16);
323   wtime=HOOK_CallHooks( WH_JOURNALPLAYBACK, HC_GETNEXT, 0, (LPARAM)SEGPTR_GET(tmpMsg));
324   /*  dprintf_msg(stddeb,"Playback wait time =%ld\n",wtime); */
325   if (wtime<=0)
326   {
327    wtime=0;
328    if ((tmpMsg->message>= WM_KEYFIRST) && (tmpMsg->message <= WM_KEYLAST))
329    {
330      wParam=tmpMsg->paramL & 0xFF;
331      lParam=MAKELONG(tmpMsg->paramH&0x7ffff,tmpMsg->paramL>>8);
332      if (tmpMsg->message == WM_KEYDOWN || tmpMsg->message == WM_SYSKEYDOWN)
333      {
334        for (keyDown=i=0; i<256 && !keyDown; i++)
335           if (KeyStateTable[i] & 0x80)
336             keyDown++;
337        if (!keyDown)
338          lParam |= 0x40000000;       
339        AsyncKeyStateTable[wParam]=KeyStateTable[wParam] |= 0x80;
340        if (MSG_JournalPlayBackIsAscii(wParam))
341        {
342          lastEventChar= wParam;         /* control TranslateMessage() */
343          lParam |= (LONG)((LONG)ASCII_CHAR_HACK*0x10000L);
344
345          if (!(KeyStateTable[VK_SHIFT] & 0x80) &&
346              !(KeyStateTable[VK_CAPITAL] & 0x80))
347            lastEventChar= tolower(lastEventChar);
348          if (KeyStateTable[VK_CONTROL] & 0x80)
349            lastEventChar&=0x1f;
350        }  
351      }  
352      else                                       /* WM_KEYUP, WM_SYSKEYUP */
353      {
354        lParam |= 0xC0000000;      
355        AsyncKeyStateTable[wParam]=KeyStateTable[wParam] &= ~0x80;
356      }
357      if (KeyStateTable[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]= KeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] << 8;
377      AsyncKeyStateTable[VK_MBUTTON]= KeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] << 8;
378      AsyncKeyStateTable[VK_RBUTTON]= KeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] << 8;
379      SetCursorPos(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_CallHooks( WH_JOURNALPLAYBACK, HC_SKIP, 0, (LPARAM)SEGPTR_GET(tmpMsg));
390   }
391   else
392     result= QS_MOUSE | QS_KEY;
393   SEGPTR_FREE(tmpMsg);
394  }
395  return result;
396
397
398 /***********************************************************************
399  *           MSG_PeekHardwareMsg
400  *
401  * Peek for a hardware message matching the hwnd and message filters.
402  */
403 static BOOL MSG_PeekHardwareMsg( MSG16 *msg, HWND hwnd, WORD first, WORD last,
404                                  BOOL remove )
405 {
406     SYSQ_STATUS status;
407     MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
408     int i, pos = sysMsgQueue->nextMessage;
409
410     /* If the queue is empty, attempt to fill it */
411     if (!sysMsgQueue->msgCount && XPending(display))
412         EVENT_WaitXEvent( FALSE, FALSE );
413
414     for (i = 0; i < sysMsgQueue->msgCount; i++, pos++)
415     {
416         if (pos >= sysMsgQueue->queueSize) pos = 0;
417         *msg = sysMsgQueue->messages[pos].msg;
418
419           /* Translate message; return FALSE immediately on SYSQ_MSG_ABANDON */
420
421         if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
422         {
423             if ((status = MSG_TranslateMouseMsg(msg,remove)) == SYSQ_MSG_ABANDON)
424                 return FALSE;
425         }
426         else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
427         {
428             if ((status = MSG_TranslateKeyboardMsg(msg,remove)) == SYSQ_MSG_ABANDON)
429                 return FALSE;
430         }
431         else  /* Non-standard hardware event */
432         {
433             HARDWAREHOOKSTRUCT16 *hook;
434             if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
435             {
436                 BOOL32 ret;
437                 hook->hWnd     = msg->hwnd;
438                 hook->wMessage = msg->message;
439                 hook->wParam   = msg->wParam;
440                 hook->lParam   = msg->lParam;
441                 ret = HOOK_CallHooks( WH_HARDWARE,
442                                       remove ? HC_ACTION : HC_NOREMOVE,
443                                       0, (LPARAM)SEGPTR_GET(hook) );
444                 SEGPTR_FREE(hook);
445                 status = ret ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT;
446             }
447         }
448
449         if (status == SYSQ_MSG_SKIP)
450         {
451             if (remove) QUEUE_RemoveMsg( sysMsgQueue, pos );
452             /* FIXME: call CBT_CLICKSKIPPED from here */
453             continue;
454         }
455
456           /* Check message against filters */
457
458         if (hwnd && (msg->hwnd != hwnd)) continue;
459         if ((first || last) && 
460             ((msg->message < first) || (msg->message > last))) continue;
461         if (remove)
462         {
463             if (HOOK_GetHook( WH_JOURNALRECORD, GetTaskQueue(0) ))
464                 MSG_JournalRecordMsg( msg );
465             QUEUE_RemoveMsg( sysMsgQueue, pos );
466         }
467         return TRUE;
468     }
469     return FALSE;
470 }
471
472
473 /**********************************************************************
474  *           SetDoubleClickTime   (USER.20)
475  */
476 void SetDoubleClickTime( WORD interval )
477 {
478     doubleClickSpeed = interval ? interval : 500;
479 }               
480
481
482 /**********************************************************************
483  *           GetDoubleClickTime   (USER.21)
484  */
485 WORD GetDoubleClickTime()
486 {
487     return doubleClickSpeed;
488 }               
489
490
491 /***********************************************************************
492  *           MSG_SendMessage
493  *
494  * Implementation of an inter-task SendMessage.
495  */
496 static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND hwnd, UINT msg,
497                                 WPARAM wParam, LPARAM lParam )
498 {
499     INT32         prevSMRL = debugSMRL;
500     QSMCTRL       qCtrl = { 0, 1};
501     MESSAGEQUEUE *queue, *destQ;
502
503     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return 0;
504     if (!(destQ = (MESSAGEQUEUE*)GlobalLock16( hDestQueue ))) return 0;
505
506     if (IsTaskLocked() || !IsWindow(hwnd)) return 0;
507
508     debugSMRL+=4;
509     dprintf_sendmsg(stddeb,"%*sSM: %s [%04x] (%04x -> %04x)\n", 
510                     prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue );
511
512     if( !(queue->wakeBits & QS_SMPARAMSFREE) )
513     {
514       dprintf_sendmsg(stddeb,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n");
515       queue->changeBits &= ~QS_SMPARAMSFREE;
516       QUEUE_WaitBits( QS_SMPARAMSFREE );
517     }
518
519     /* resume sending */ 
520
521     queue->hWnd   = hwnd;
522     queue->msg    = msg;
523     queue->wParam = wParam;
524     queue->lParam = lParam;
525     queue->hPrevSendingTask = destQ->hSendingTask;
526     destQ->hSendingTask = GetTaskQueue(0);
527
528     queue->wakeBits &= ~QS_SMPARAMSFREE;
529
530     dprintf_sendmsg(stddeb,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl);
531
532     queue->smResultInit = &qCtrl;
533
534     QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE );
535
536     /* perform task switch and wait for the result */
537
538     while( qCtrl.bPending )
539     {
540       if (!(queue->wakeBits & QS_SMRESULT))
541       {
542         queue->changeBits &= ~QS_SMRESULT;
543         DirectedYield( destQ->hTask );
544         QUEUE_WaitBits( QS_SMRESULT );
545         dprintf_sendmsg(stddeb,"\tsm: have result!\n");
546       }
547       /* got something */
548
549       dprintf_sendmsg(stddeb,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult );
550
551       queue->smResult->lResult = queue->SendMessageReturn;
552       queue->smResult->bPending = FALSE;
553       queue->wakeBits &= ~QS_SMRESULT;
554
555       if( queue->smResult != &qCtrl )
556           dprintf_msg(stddeb,"%*ssm: weird scenes inside the goldmine!\n", prevSMRL, "");
557     }
558     queue->smResultInit = NULL;
559     
560     dprintf_sendmsg(stddeb,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult);
561     debugSMRL-=4;
562
563     return qCtrl.lResult;
564 }
565
566
567 /***********************************************************************
568  *           ReplyMessage   (USER.115)
569  */
570 void ReplyMessage( LRESULT result )
571 {
572     MESSAGEQUEUE *senderQ;
573     MESSAGEQUEUE *queue;
574
575     if (!(queue = (MESSAGEQUEUE*)GlobalLock16( GetTaskQueue(0) ))) return;
576
577     dprintf_msg(stddeb,"ReplyMessage, queue %04x\n", queue->self);
578
579     while( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->InSendMessageHandle)))
580     {
581       dprintf_msg(stddeb,"\trpm: replying to %04x (%04x -> %04x)\n",
582                           queue->msg, queue->self, senderQ->self);
583
584       if( queue->wakeBits & QS_SENDMESSAGE )
585       {
586         QUEUE_ReceiveMessage( queue );
587         continue; /* ReceiveMessage() already called us */
588       }
589
590       if(!(senderQ->wakeBits & QS_SMRESULT) ) break;
591       OldYield();
592     } 
593     if( !senderQ ) { dprintf_msg(stddeb,"\trpm: done\n"); return; }
594
595     senderQ->SendMessageReturn = result;
596     dprintf_msg(stddeb,"\trpm: smResult = %08x, result = %08lx\n", 
597                         (unsigned)queue->smResultCurrent, result );
598
599     senderQ->smResult = queue->smResultCurrent;
600     queue->InSendMessageHandle = 0;
601
602     QUEUE_SetWakeBit( senderQ, QS_SMRESULT );
603     DirectedYield( queue->hSendingTask );
604 }
605
606
607 /***********************************************************************
608  *           MSG_PeekMessage
609  */
610 static BOOL MSG_PeekMessage( LPMSG16 msg, HWND hwnd, WORD first, WORD last,
611                              WORD flags, BOOL peek )
612 {
613     int pos, mask;
614     MESSAGEQUEUE *msgQueue;
615     HQUEUE16 hQueue;
616
617 #ifdef CONFIG_IPC
618     DDE_TestDDE(hwnd);  /* do we have dde handling in the window ?*/
619     DDE_GetRemoteMessage();
620 #endif  /* CONFIG_IPC */
621
622     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
623     if (first || last)
624     {
625         /* MSWord gets stuck if we do not check for nonclient mouse messages */
626
627         if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
628         if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
629              ((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
630         if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
631         if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
632         if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
633     }
634     else mask |= QS_MOUSE | QS_KEY | QS_TIMER | QS_PAINT;
635
636     if (IsTaskLocked()) flags |= PM_NOYIELD;
637
638     while(1)
639     {    
640         hQueue   = GetTaskQueue(0);
641         msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
642         if (!msgQueue) return FALSE;
643         msgQueue->changeBits = 0;
644
645         /* First handle a message put by SendMessage() */
646
647         if (msgQueue->wakeBits & QS_SENDMESSAGE)
648             QUEUE_ReceiveMessage( msgQueue );
649
650         /* Now handle a WM_QUIT message 
651          *
652          * FIXME: PostQuitMessage() should post WM_QUIT and 
653          *        set QS_POSTMESSAGE wakebit instead of this.
654          */
655
656         if (msgQueue->wPostQMsg &&
657            (!first || WM_QUIT >= first) && 
658            (!last || WM_QUIT <= last) )
659         {
660             msg->hwnd    = hwnd;
661             msg->message = WM_QUIT;
662             msg->wParam  = msgQueue->wExitCode;
663             msg->lParam  = 0;
664             break;
665         }
666     
667         /* Now find a normal message */
668
669         if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
670             ((pos = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != -1))
671         {
672             QMSG *qmsg = &msgQueue->messages[pos];
673             *msg = qmsg->msg;
674             msgQueue->GetMessageTimeVal      = msg->time;
675             msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
676             msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo;
677
678             if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, pos );
679             break;
680         }
681
682         msgQueue->changeBits |= MSG_JournalPlayBackMsg();
683
684         /* Now find a hardware event */
685
686         if (((msgQueue->wakeBits & mask) & (QS_MOUSE | QS_KEY)) &&
687             MSG_PeekHardwareMsg( msg, hwnd, first, last, flags & PM_REMOVE ))
688         {
689             /* Got one */
690             msgQueue->GetMessageTimeVal      = msg->time;
691             msgQueue->GetMessagePosVal       = *(DWORD *)&msg->pt;
692             msgQueue->GetMessageExtraInfoVal = 0;  /* Always 0 for now */
693             break;
694         }
695
696         /* Check again for SendMessage */
697
698         if (msgQueue->wakeBits & QS_SENDMESSAGE)
699             QUEUE_ReceiveMessage( msgQueue );
700
701         /* Now find a WM_PAINT message */
702
703         if ((msgQueue->wakeBits & mask) & QS_PAINT)
704         {
705             WND* wndPtr;
706             msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
707             msg->message = WM_PAINT;
708             msg->wParam = 0;
709             msg->lParam = 0;
710
711             if ((wndPtr = WIN_FindWndPtr(msg->hwnd)))
712             {
713                 if( wndPtr->dwStyle & WS_MINIMIZE &&
714                     wndPtr->class->hIcon )
715                 {
716                     msg->message = WM_PAINTICON;
717                     msg->wParam = 1;
718                 }
719
720                 if( !hwnd || msg->hwnd == hwnd || IsChild(hwnd,msg->hwnd) )
721                 {
722                     if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
723                     {
724                         wndPtr->flags &= ~WIN_INTERNAL_PAINT;
725                         QUEUE_DecPaintCount( hQueue );
726                     }
727                     break;
728                 }
729             }
730         }
731
732         /* Check for timer messages, but yield first */
733
734         if (!(flags & PM_NOYIELD))
735         {
736             UserYield();
737             if (msgQueue->wakeBits & QS_SENDMESSAGE)
738                 QUEUE_ReceiveMessage( msgQueue );
739         }
740         if ((msgQueue->wakeBits & mask) & QS_TIMER)
741         {
742             if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
743         }
744
745         if (peek)
746         {
747             if (!(flags & PM_NOYIELD)) UserYield();
748             return FALSE;
749         }
750         msgQueue->wakeMask = mask;
751         QUEUE_WaitBits( mask );
752     }
753
754       /* We got a message */
755     if (peek) return TRUE;
756     else return (msg->message != WM_QUIT);
757 }
758
759
760 /***********************************************************************
761  *           MSG_InternalGetMessage
762  *
763  * GetMessage() function for internal use. Behave like GetMessage(),
764  * but also call message filters and optionally send WM_ENTERIDLE messages.
765  * 'hwnd' must be the handle of the dialog or menu window.
766  * 'code' is the message filter value (MSGF_??? codes).
767  */
768 BOOL32 MSG_InternalGetMessage( MSG16 *msg, HWND32 hwnd, HWND32 hwndOwner,
769                                WPARAM32 code, WORD flags, BOOL32 sendIdle ) 
770 {
771     for (;;)
772     {
773         if (sendIdle)
774         {
775             if (!MSG_PeekMessage( msg, 0, 0, 0, flags, TRUE ))
776             {
777                   /* No message present -> send ENTERIDLE and wait */
778                 if (IsWindow(hwndOwner))
779                     SendMessage16( hwndOwner, WM_ENTERIDLE,
780                                    code, (LPARAM)hwnd );
781                 MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
782             }
783         }
784         else  /* Always wait for a message */
785             MSG_PeekMessage( msg, 0, 0, 0, flags, FALSE );
786
787         /* Call message filters */
788
789         if (HOOK_GetHook( WH_SYSMSGFILTER, GetTaskQueue(0) ) ||
790             HOOK_GetHook( WH_MSGFILTER, GetTaskQueue(0) ))
791         {
792             MSG16 *pmsg = SEGPTR_NEW(MSG16);
793             if (pmsg)
794             {
795                 BOOL32 ret;
796                 *pmsg = *msg;
797                 ret = ((BOOL16)HOOK_CallHooks( WH_SYSMSGFILTER, code, 0,
798                                                (LPARAM)SEGPTR_GET(pmsg) ) ||
799                        (BOOL16)HOOK_CallHooks( WH_MSGFILTER, code, 0,
800                                                (LPARAM)SEGPTR_GET(pmsg) ));
801                 SEGPTR_FREE(pmsg);
802                 if (ret)
803                 {
804                     /* Message filtered -> remove it from the queue */
805                     /* if it's still there. */
806                     if (!(flags & PM_REMOVE))
807                         MSG_PeekMessage( msg, 0, 0, 0, PM_REMOVE, TRUE );
808                     continue;
809                 }
810             }
811         }
812
813         return (msg->message != WM_QUIT);
814     }
815 }
816
817
818 /***********************************************************************
819  *           PeekMessage16   (USER.109)
820  */
821 BOOL16 PeekMessage16( LPMSG16 msg, HWND16 hwnd, UINT16 first,
822                       UINT16 last, UINT16 flags )
823 {
824     return MSG_PeekMessage( msg, hwnd, first, last, flags, TRUE );
825 }
826
827
828 /***********************************************************************
829  *           GetMessage   (USER.108)
830  */
831 BOOL GetMessage( SEGPTR msg, HWND hwnd, UINT first, UINT last ) 
832 {
833     MSG16 *lpmsg = (MSG16 *)PTR_SEG_TO_LIN(msg);
834     MSG_PeekMessage( lpmsg,
835                      hwnd, first, last, PM_REMOVE, FALSE );
836
837     dprintf_msg(stddeb,"message %04x, hwnd %04x, filter(%04x - %04x)\n", lpmsg->message,
838                                                                  hwnd, first, last );
839     HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, 0, (LPARAM)msg );
840     return (lpmsg->message != WM_QUIT);
841 }
842
843
844 /***********************************************************************
845  *           PostMessage   (USER.110)
846  */
847 BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam )
848 {
849     MSG16       msg;
850     WND         *wndPtr;
851
852     msg.hwnd    = hwnd;
853     msg.message = message;
854     msg.wParam  = wParam;
855     msg.lParam  = lParam;
856     msg.time    = GetTickCount();
857     msg.pt.x    = 0;
858     msg.pt.y    = 0;
859
860 #ifdef CONFIG_IPC
861     if (DDE_PostMessage(&msg))
862        return TRUE;
863 #endif  /* CONFIG_IPC */
864     
865     if (hwnd == HWND_BROADCAST16)
866     {
867         dprintf_msg(stddeb,"PostMessage // HWND_BROADCAST !\n");
868         for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
869         {
870             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
871             {
872                 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n",
873                             wndPtr->hwndSelf, message, wParam, lParam);
874                 PostMessage( wndPtr->hwndSelf, message, wParam, lParam );
875             }
876         }
877         dprintf_msg(stddeb,"PostMessage // End of HWND_BROADCAST !\n");
878         return TRUE;
879     }
880
881     wndPtr = WIN_FindWndPtr( hwnd );
882     if (!wndPtr || !wndPtr->hmemTaskQ) return FALSE;
883
884     return QUEUE_AddMsg( wndPtr->hmemTaskQ, &msg, 0 );
885 }
886
887 /***********************************************************************
888  *           PostAppMessage   (USER.116)
889  */
890 BOOL PostAppMessage( HTASK hTask, WORD message, WORD wParam, LONG lParam )
891 {
892     MSG16 msg;
893
894     if (GetTaskQueue(hTask) == 0) return FALSE;
895     msg.hwnd    = 0;
896     msg.message = message;
897     msg.wParam  = wParam;
898     msg.lParam  = lParam;
899     msg.time    = GetTickCount();
900     msg.pt.x    = 0;
901     msg.pt.y    = 0;
902
903     return QUEUE_AddMsg( GetTaskQueue(hTask), &msg, 0 );
904 }
905
906
907 /***********************************************************************
908  *           SendMessage16   (USER.111)
909  */
910 LRESULT SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam)
911 {
912     WND * wndPtr;
913     LRESULT ret;
914
915 #ifdef CONFIG_IPC
916     MSG16 DDE_msg = { hwnd, msg, wParam, lParam };
917     if (DDE_SendMessage(&DDE_msg)) return TRUE;
918 #endif  /* CONFIG_IPC */
919
920     if (hwnd == HWND_BROADCAST16)
921     {
922         dprintf_msg(stddeb,"SendMessage // HWND_BROADCAST !\n");
923         for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
924         {
925             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
926             {
927                 dprintf_msg(stddeb,"BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n",
928                             wndPtr->hwndSelf, msg, (DWORD)wParam, lParam);
929                 SendMessage16( wndPtr->hwndSelf, msg, wParam, lParam );
930             }
931         }
932         dprintf_msg(stddeb,"SendMessage // End of HWND_BROADCAST !\n");
933         return TRUE;
934     }
935
936     if (HOOK_GetHook( WH_CALLWNDPROC, GetTaskQueue(0) ))
937     { 
938         struct msgstruct
939         {
940             LPARAM   lParam;
941             WPARAM16 wParam;
942             UINT16   wMsg;
943             HWND16   hWnd;
944         } *pmsg;
945         
946         if ((pmsg = SEGPTR_NEW(struct msgstruct)))
947         {
948             pmsg->hWnd   = hwnd;
949             pmsg->wMsg   = msg;
950             pmsg->wParam = wParam;
951             pmsg->lParam = lParam;
952             HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 1,
953                             (LPARAM)SEGPTR_GET(pmsg) );
954             hwnd   = pmsg->hWnd;
955             msg    = pmsg->wMsg;
956             wParam = pmsg->wParam;
957             lParam = pmsg->lParam;
958         }
959     }
960
961     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
962     {
963         fprintf( stderr, "SendMessage16: invalid hwnd %04x\n", hwnd );
964         return 0;
965     }
966     if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
967         return 0;  /* Don't send anything if the task is dying */
968     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
969         return MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam );
970
971     SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
972     ret = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
973                             hwnd, msg, wParam, lParam );
974     SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, ret );
975     return ret;
976 }
977
978
979 /***********************************************************************
980  *           SendMessage32A   (USER32.453)
981  */
982 LRESULT SendMessage32A(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
983 {
984     WND * wndPtr;
985     LRESULT ret;
986
987     if (hwnd == HWND_BROADCAST32)
988     {
989         for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
990         {
991             /* FIXME: should use something like EnumWindows here */
992             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
993                 SendMessage32A( wndPtr->hwndSelf, msg, wParam, lParam );
994         }
995         return TRUE;
996     }
997
998     /* FIXME: call hooks */
999
1000     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1001     {
1002         fprintf( stderr, "SendMessage32A: invalid hwnd %08x\n", hwnd );
1003         return 0;
1004     }
1005
1006     if (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_16)
1007     {
1008         /* Use SendMessage16 for now to get hooks right */
1009         UINT16 msg16;
1010         WPARAM16 wParam16;
1011         if (WINPROC_MapMsg32ATo16( msg, wParam, &msg16, &wParam16, &lParam ) == -1)
1012             return 0;
1013         ret = SendMessage16( hwnd, msg16, wParam16, lParam );
1014         WINPROC_UnmapMsg32ATo16( msg16, wParam16, lParam );
1015         return ret;
1016     }
1017
1018     if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1019         return 0;  /* Don't send anything if the task is dying */
1020
1021     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1022     {
1023         fprintf( stderr, "SendMessage32A: intertask message not supported\n" );
1024         return 0;
1025     }
1026
1027     SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1028     ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc,
1029                              hwnd, msg, wParam, lParam );
1030     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1031     return ret;
1032 }
1033
1034
1035 /***********************************************************************
1036  *           SendMessage32W   (USER32.458)
1037  */
1038 LRESULT SendMessage32W(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1039 {
1040     WND * wndPtr;
1041     LRESULT ret;
1042
1043     if (hwnd == HWND_BROADCAST32)
1044     {
1045         for (wndPtr = WIN_GetDesktop()->child; wndPtr; wndPtr = wndPtr->next)
1046         {
1047             /* FIXME: should use something like EnumWindows here */
1048             if (wndPtr->dwStyle & WS_POPUP || wndPtr->dwStyle & WS_CAPTION)
1049                 SendMessage32W( wndPtr->hwndSelf, msg, wParam, lParam );
1050         }
1051         return TRUE;
1052     }
1053
1054     /* FIXME: call hooks */
1055
1056     if (!(wndPtr = WIN_FindWndPtr( hwnd )))
1057     {
1058         fprintf( stderr, "SendMessage32W: invalid hwnd %08x\n", hwnd );
1059         return 0;
1060     }
1061     if (QUEUE_IsDoomedQueue(wndPtr->hmemTaskQ))
1062         return 0;  /* Don't send anything if the task is dying */
1063     if (wndPtr->hmemTaskQ != GetTaskQueue(0))
1064     {
1065         fprintf( stderr, "SendMessage32W: intertask message not supported\n" );
1066         return 0;
1067     }
1068
1069     SPY_EnterMessage( SPY_SENDMESSAGE32, hwnd, msg, wParam, lParam );
1070     ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc,
1071                              hwnd, msg, wParam, lParam );
1072     SPY_ExitMessage( SPY_RESULT_OK32, hwnd, msg, ret );
1073     return ret;
1074 }
1075
1076
1077 /***********************************************************************
1078  *           WaitMessage    (USER.112)
1079  */
1080 void WaitMessage( void )
1081 {
1082     QUEUE_WaitBits( QS_ALLINPUT );
1083 }
1084
1085
1086 /***********************************************************************
1087  *           TranslateMessage   (USER.113)
1088  *
1089  * This should call ToAscii but it is currently broken
1090  */
1091
1092
1093 BOOL TranslateMessage( LPMSG16 msg )
1094 {
1095     UINT message = msg->message;
1096     /* BYTE wparam[2]; */
1097     
1098     if ((message == WM_KEYDOWN) || (message == WM_KEYUP) ||
1099         (message == WM_SYSKEYDOWN) || (message == WM_SYSKEYUP))
1100     {
1101         dprintf_msg(stddeb, "Translating key %04x, scancode %04x\n", msg->wParam, 
1102                                                               HIWORD(msg->lParam) );
1103
1104         if( HIWORD(msg->lParam) & ASCII_CHAR_HACK )
1105
1106         /*  if( ToAscii( msg->wParam, HIWORD(msg->lParam), (LPSTR)&KeyStateTable,
1107                                       wparam, 0 ) ) 
1108          */
1109               {
1110                 message += 2 - (message & 0x0001); 
1111
1112                 PostMessage( msg->hwnd, message, lastEventChar, msg->lParam );
1113
1114                 return TRUE;
1115               }
1116     }
1117     return FALSE;
1118 }
1119
1120
1121 /***********************************************************************
1122  *           DispatchMessage   (USER.114)
1123  */
1124 LONG DispatchMessage( const MSG16* msg )
1125 {
1126     WND * wndPtr;
1127     LONG retval;
1128     int painting;
1129     
1130       /* Process timer messages */
1131     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
1132     {
1133         if (msg->lParam)
1134         {
1135 /*            HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1136             return CallWindowProc16( (WNDPROC16)msg->lParam, msg->hwnd,
1137                                    msg->message, msg->wParam, GetTickCount() );
1138         }
1139     }
1140
1141     if (!msg->hwnd) return 0;
1142     if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0;
1143     if (!wndPtr->winproc) return 0;
1144     painting = (msg->message == WM_PAINT);
1145     if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT;
1146 /*    HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, 0, FIXME ); */
1147
1148     SPY_EnterMessage( SPY_DISPATCHMESSAGE16, msg->hwnd, msg->message,
1149                       msg->wParam, msg->lParam );
1150     retval = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
1151                                msg->hwnd, msg->message,
1152                                msg->wParam, msg->lParam );
1153     SPY_ExitMessage( SPY_RESULT_OK16, msg->hwnd, msg->message, retval );
1154
1155     if (painting && (wndPtr = WIN_FindWndPtr( msg->hwnd )) &&
1156         (wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate)
1157     {
1158         fprintf(stderr, "BeginPaint not called on WM_PAINT for hwnd %04x!\n", 
1159                 msg->hwnd);
1160         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
1161         /* Validate the update region to avoid infinite WM_PAINT loop */
1162         ValidateRect32( msg->hwnd, NULL );
1163     }
1164     return retval;
1165 }
1166
1167
1168 /***********************************************************************
1169  *           RegisterWindowMessage16   (USER.118)
1170  */
1171 WORD RegisterWindowMessage16( SEGPTR str )
1172 {
1173     dprintf_msg(stddeb, "RegisterWindowMessage16: %08lx\n", (DWORD)str );
1174     return GlobalAddAtom16( str );
1175 }
1176
1177
1178 /***********************************************************************
1179  *           RegisterWindowMessage32A   (USER32.436)
1180  */
1181 WORD RegisterWindowMessage32A( LPCSTR str )
1182 {
1183     dprintf_msg(stddeb, "RegisterWindowMessage32A: %s\n", str );
1184     return GlobalAddAtom32A( str );
1185 }
1186
1187
1188 /***********************************************************************
1189  *           RegisterWindowMessage32W   (USER32.437)
1190  */
1191 WORD RegisterWindowMessage32W( LPCWSTR str )
1192 {
1193     dprintf_msg(stddeb, "RegisterWindowMessage32W: %p\n", str );
1194     return GlobalAddAtom32W( str );
1195 }
1196
1197
1198 /***********************************************************************
1199  *           GetTickCount   (USER.13) (KERNEL32.299)
1200  */
1201 DWORD GetTickCount(void)
1202 {
1203     struct timeval t;
1204     gettimeofday( &t, NULL );
1205     return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks;
1206 }
1207
1208
1209 /***********************************************************************
1210  *           GetCurrentTime    (USER.15)
1211  *
1212  * (effectively identical to GetTickCount)
1213  */
1214 DWORD GetCurrentTime(void)
1215 {
1216     return GetTickCount();
1217 }
1218
1219
1220 /***********************************************************************
1221  *           InSendMessage    (USER.192)
1222  */
1223 BOOL InSendMessage()
1224 {
1225     MESSAGEQUEUE *queue;
1226
1227     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
1228         return 0;
1229     return (BOOL)queue->InSendMessageHandle;
1230 }