Moved MsgWaitForMultipleObject implementation to USER routines, using
[wine] / windows / queue.c
1 /*
2  * Message queues related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include <signal.h>
9 #include "miscemu.h"
10 #include "module.h"
11 #include "queue.h"
12 #include "task.h"
13 #include "win.h"
14 #include "clipboard.h"
15 #include "hook.h"
16 #include "heap.h"
17 #include "thread.h"
18 #include "process.h"
19 #include "debug.h"
20
21 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
22
23 static HQUEUE16 hFirstQueue = 0;
24 static HQUEUE16 hExitingQueue = 0;
25 static HQUEUE16 hmemSysMsgQueue = 0;
26 static MESSAGEQUEUE *sysMsgQueue = NULL;
27
28 static MESSAGEQUEUE *pMouseQueue = NULL;  /* Queue for last mouse message */
29 static MESSAGEQUEUE *pKbdQueue = NULL;    /* Queue for last kbd message */
30
31 MESSAGEQUEUE *pCursorQueue = NULL; 
32 MESSAGEQUEUE *pActiveQueue = NULL;
33
34 /***********************************************************************
35  *           QUEUE_DumpQueue
36  */
37 void QUEUE_DumpQueue( HQUEUE16 hQueue )
38 {
39     MESSAGEQUEUE *pq; 
40
41     if (!(pq = (MESSAGEQUEUE*) GlobalLock16( hQueue )) ||
42         GlobalSize16(hQueue) < sizeof(MESSAGEQUEUE)+pq->queueSize*sizeof(QMSG))
43     {
44         WARN(msg, "%04x is not a queue handle\n", hQueue );
45         return;
46     }
47
48     DUMP(    "next: %12.4x  Intertask SendMessage:\n"
49              "hTask: %11.4x  ----------------------\n"
50              "msgSize: %9.4x  hWnd: %10.4x\n"
51              "msgCount: %8.4x  msg: %11.4x\n"
52              "msgNext: %9.4x  wParam: %8.4x\n"
53              "msgFree: %9.4x  lParam: %8.8x\n"
54              "qSize: %11.4x  lRet: %10.8x\n"
55              "wWinVer: %9.4x  ISMH: %10.4x\n"
56              "paints: %10.4x  hSendTask: %5.4x\n"
57              "timers: %10.4x  hPrevSend: %5.4x\n"
58              "wakeBits: %8.4x\n"
59              "wakeMask: %8.4x\n"
60              "hCurHook: %8.4x\n",
61              pq->next, pq->hTask, pq->msgSize, pq->hWnd, 
62              pq->msgCount, pq->msg, pq->nextMessage, pq->wParam,
63              pq->nextFreeMessage, (unsigned)pq->lParam, pq->queueSize,
64              (unsigned)pq->SendMessageReturn, pq->wWinVersion, pq->InSendMessageHandle,
65              pq->wPaintCount, pq->hSendingTask, pq->wTimerCount,
66              pq->hPrevSendingTask, pq->wakeBits, pq->wakeMask, pq->hCurHook);
67 }
68
69
70 /***********************************************************************
71  *           QUEUE_WalkQueues
72  */
73 void QUEUE_WalkQueues(void)
74 {
75     char module[10];
76     HQUEUE16 hQueue = hFirstQueue;
77
78     DUMP( "Queue Size Msgs Task\n" );
79     while (hQueue)
80     {
81         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
82         if (!queue)
83         {
84             WARN( msg, "Bad queue handle %04x\n", hQueue );
85             return;
86         }
87         if (!GetModuleName( queue->hTask, module, sizeof(module )))
88             strcpy( module, "???" );
89         DUMP( "%04x %5d %4d %04x %s\n", hQueue, queue->msgSize,
90                  queue->msgCount, queue->hTask, module );
91         hQueue = queue->next;
92     }
93     DUMP( "\n" );
94 }
95
96
97 /***********************************************************************
98  *           QUEUE_IsExitingQueue
99  */
100 BOOL32 QUEUE_IsExitingQueue( HQUEUE16 hQueue )
101 {
102     return (hExitingQueue && (hQueue == hExitingQueue));
103 }
104
105
106 /***********************************************************************
107  *           QUEUE_SetExitingQueue
108  */
109 void QUEUE_SetExitingQueue( HQUEUE16 hQueue )
110 {
111     hExitingQueue = hQueue;
112 }
113
114
115 /***********************************************************************
116  *           QUEUE_CreateMsgQueue
117  *
118  * Creates a message queue. Doesn't link it into queue list!
119  */
120 static HQUEUE16 QUEUE_CreateMsgQueue( int size )
121 {
122     HQUEUE16 hQueue;
123     MESSAGEQUEUE * msgQueue;
124     int queueSize;
125     TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
126
127     TRACE(msg,"Creating message queue...\n");
128
129     queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
130     if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, queueSize )))
131         return 0;
132     msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
133     msgQueue->self        = hQueue;
134     msgQueue->msgSize     = sizeof(QMSG);
135     msgQueue->queueSize   = size;
136     msgQueue->wakeBits    = msgQueue->changeBits = QS_SMPARAMSFREE;
137     msgQueue->wWinVersion = pTask ? pTask->version : 0;
138     GlobalUnlock16( hQueue );
139     return hQueue;
140 }
141
142
143 /***********************************************************************
144  *           QUEUE_DeleteMsgQueue
145  *
146  * Unlinks and deletes a message queue.
147  *
148  * Note: We need to mask asynchronous events to make sure PostMessage works
149  * even in the signal handler.
150  */
151 BOOL32 QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
152 {
153     MESSAGEQUEUE * msgQueue = (MESSAGEQUEUE*)GlobalLock16(hQueue);
154     HQUEUE16  senderQ;
155     HQUEUE16 *pPrev;
156
157     TRACE(msg,"Deleting message queue %04x\n", hQueue);
158
159     if (!hQueue || !msgQueue)
160     {
161         WARN(msg, "invalid argument.\n");
162         return 0;
163     }
164     if( pCursorQueue == msgQueue ) pCursorQueue = NULL;
165     if( pActiveQueue == msgQueue ) pActiveQueue = NULL;
166
167     /* flush sent messages */
168     senderQ = msgQueue->hSendingTask;
169     while( senderQ )
170     {
171       MESSAGEQUEUE* sq = (MESSAGEQUEUE*)GlobalLock16(senderQ);
172       if( !sq ) break;
173       sq->SendMessageReturn = 0L;
174       QUEUE_SetWakeBit( sq, QS_SMRESULT );
175       senderQ = sq->hPrevSendingTask;
176     }
177
178     SIGNAL_MaskAsyncEvents( TRUE );
179
180     pPrev = &hFirstQueue;
181     while (*pPrev && (*pPrev != hQueue))
182     {
183         MESSAGEQUEUE *msgQ = (MESSAGEQUEUE*)GlobalLock16(*pPrev);
184         pPrev = &msgQ->next;
185     }
186     if (*pPrev) *pPrev = msgQueue->next;
187     msgQueue->self = 0;
188
189     SIGNAL_MaskAsyncEvents( FALSE );
190
191     GlobalFree16( hQueue );
192     return 1;
193 }
194
195
196 /***********************************************************************
197  *           QUEUE_CreateSysMsgQueue
198  *
199  * Create the system message queue, and set the double-click speed.
200  * Must be called only once.
201  */
202 BOOL32 QUEUE_CreateSysMsgQueue( int size )
203 {
204     if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
205     else if (size <= 0) size = 1;
206     if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( size ))) return FALSE;
207     sysMsgQueue = (MESSAGEQUEUE *) GlobalLock16( hmemSysMsgQueue );
208     return TRUE;
209 }
210
211
212 /***********************************************************************
213  *           QUEUE_GetSysQueue
214  */
215 MESSAGEQUEUE *QUEUE_GetSysQueue(void)
216 {
217     return sysMsgQueue;
218 }
219
220 /***********************************************************************
221  *           QUEUE_Signal
222  */
223 void QUEUE_Signal( HTASK16 hTask )
224 {
225     PDB32 *pdb;
226     THREAD_ENTRY *entry;
227
228     TDB *pTask = (TDB *)GlobalLock16( hTask );
229     if ( !pTask ) return;
230
231     /* Wake up thread waiting for message */
232     SetEvent( pTask->thdb->event );
233
234     PostEvent( hTask );
235 }
236
237 /***********************************************************************
238  *           QUEUE_Wait
239  */
240 static void QUEUE_Wait( DWORD wait_mask )
241 {
242     if ( THREAD_IsWin16( THREAD_Current() ) )
243         WaitEvent( 0 );
244     else
245     {
246         TRACE(msg, "current task is 32-bit, calling SYNC_DoWait\n");
247         MsgWaitForMultipleObjects( 0, NULL, FALSE, INFINITE32, wait_mask );
248     }
249 }
250
251
252 /***********************************************************************
253  *           QUEUE_SetWakeBit
254  *
255  * See "Windows Internals", p.449
256  */
257 void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
258 {
259     TRACE(msg,"queue = %04x (wm=%04x), bit = %04x\n", 
260                         queue->self, queue->wakeMask, bit );
261
262     if (bit & QS_MOUSE) pMouseQueue = queue;
263     if (bit & QS_KEY) pKbdQueue = queue;
264     queue->changeBits |= bit;
265     queue->wakeBits   |= bit;
266     if (queue->wakeMask & bit)
267     {
268         queue->wakeMask = 0;
269         QUEUE_Signal( queue->hTask );
270     }
271 }
272
273
274 /***********************************************************************
275  *           QUEUE_ClearWakeBit
276  */
277 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
278 {
279     queue->changeBits &= ~bit;
280     queue->wakeBits   &= ~bit;
281 }
282
283
284 /***********************************************************************
285  *           QUEUE_WaitBits
286  *
287  * See "Windows Internals", p.447
288  */
289 void QUEUE_WaitBits( WORD bits )
290 {
291     MESSAGEQUEUE *queue;
292
293     TRACE(msg,"q %04x waiting for %04x\n", GetFastQueue(), bits);
294
295     for (;;)
296     {
297         if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return;
298
299         if (queue->changeBits & bits)
300         {
301             /* One of the bits is set; we can return */
302             queue->wakeMask = 0;
303             return;
304         }
305         if (queue->wakeBits & QS_SENDMESSAGE)
306         {
307             /* Process the sent message immediately */
308
309             queue->wakeMask = 0;
310             QUEUE_ReceiveMessage( queue );
311             continue;                           /* nested sm crux */
312         }
313
314         queue->wakeMask = bits | QS_SENDMESSAGE;
315         if(queue->changeBits & bits) continue;
316         
317         TRACE(msg,"%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
318
319         QUEUE_Wait( queue->wakeMask );
320     }
321 }
322
323
324 /***********************************************************************
325  *           QUEUE_ReceiveMessage
326  *
327  * This routine is called when a sent message is waiting for the queue.
328  */
329 void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
330 {
331     MESSAGEQUEUE *senderQ = NULL;
332     HQUEUE16      prevSender = 0;
333     QSMCTRL*      prevCtrlPtr = NULL;
334     LRESULT       result = 0;
335
336     TRACE(msg, "ReceiveMessage, queue %04x\n", queue->self );
337     if (!(queue->wakeBits & QS_SENDMESSAGE) ||
338         !(senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask))) 
339         { TRACE(msg,"\trcm: nothing to do\n"); return; }
340
341     if( !senderQ->hPrevSendingTask )
342         QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );   /* no more sent messages */
343
344     /* Save current state on stack */
345     prevSender                 = queue->InSendMessageHandle;
346     prevCtrlPtr                = queue->smResultCurrent;
347
348     /* Remove sending queue from the list */
349     queue->InSendMessageHandle = queue->hSendingTask;
350     queue->smResultCurrent     = senderQ->smResultInit;
351     queue->hSendingTask        = senderQ->hPrevSendingTask;
352
353     TRACE(msg, "\trcm: smResultCurrent = %08x, prevCtrl = %08x\n", 
354                                 (unsigned)queue->smResultCurrent, (unsigned)prevCtrlPtr );
355     QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
356
357     TRACE(msg, "\trcm: calling wndproc - %04x %04x %04x%04x %08x\n",
358                 senderQ->hWnd, senderQ->msg, senderQ->wParamHigh,
359                 senderQ->wParam, (unsigned)senderQ->lParam );
360
361     if (IsWindow32( senderQ->hWnd ))
362     {
363         WND *wndPtr = WIN_FindWndPtr( senderQ->hWnd );
364         DWORD extraInfo = queue->GetMessageExtraInfoVal;
365         queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
366
367         if (senderQ->flags & QUEUE_SM_WIN32)
368         {
369             WPARAM32 wParam = MAKELONG( senderQ->wParam, senderQ->wParamHigh );
370             TRACE(msg, "\trcm: msg is Win32\n" );
371             if (senderQ->flags & QUEUE_SM_UNICODE)
372                 result = CallWindowProc32W( wndPtr->winproc,
373                                             senderQ->hWnd, senderQ->msg,
374                                             wParam, senderQ->lParam );
375             else
376                 result = CallWindowProc32A( wndPtr->winproc,
377                                             senderQ->hWnd, senderQ->msg,
378                                             wParam, senderQ->lParam );
379         }
380         else  /* Win16 message */
381             result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
382                                        senderQ->hWnd, senderQ->msg,
383                                        senderQ->wParam, senderQ->lParam );
384
385         queue->GetMessageExtraInfoVal = extraInfo;  /* Restore extra info */
386         TRACE(msg,"\trcm: result =  %08x\n", (unsigned)result );
387     }
388     else WARN(msg, "\trcm: bad hWnd\n");
389
390     /* Return the result to the sender task */
391     ReplyMessage16( result );
392
393     queue->InSendMessageHandle = prevSender;
394     queue->smResultCurrent     = prevCtrlPtr;
395
396     TRACE(msg,"done!\n");
397 }
398
399 /***********************************************************************
400  *           QUEUE_FlushMessage
401  * 
402  * Try to reply to all pending sent messages on exit.
403  */
404 void QUEUE_FlushMessages( HQUEUE16 hQueue )
405 {
406   MESSAGEQUEUE *queue = (MESSAGEQUEUE*)GlobalLock16( hQueue );
407
408   if( queue )
409   {
410     MESSAGEQUEUE *senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask);
411     QSMCTRL*      CtrlPtr = queue->smResultCurrent;
412
413     TRACE(msg,"Flushing queue %04x:\n", hQueue );
414
415     while( senderQ )
416     {
417       if( !CtrlPtr )
418            CtrlPtr = senderQ->smResultInit;
419
420       TRACE(msg,"\tfrom queue %04x, smResult %08x\n", queue->hSendingTask, (unsigned)CtrlPtr );
421
422       if( !(queue->hSendingTask = senderQ->hPrevSendingTask) )
423         QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
424
425       QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
426       
427       queue->smResultCurrent = CtrlPtr;
428       while( senderQ->wakeBits & QS_SMRESULT ) OldYield();
429
430       senderQ->SendMessageReturn = 0;
431       senderQ->smResult = queue->smResultCurrent;
432       QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
433
434       senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask);
435       CtrlPtr = NULL;
436     }
437     queue->InSendMessageHandle = 0;
438   }  
439 }
440
441 /***********************************************************************
442  *           QUEUE_AddMsg
443  *
444  * Add a message to the queue. Return FALSE if queue is full.
445  */
446 BOOL32 QUEUE_AddMsg( HQUEUE16 hQueue, MSG16 * msg, DWORD extraInfo )
447 {
448     int pos;
449     MESSAGEQUEUE *msgQueue;
450
451     SIGNAL_MaskAsyncEvents( TRUE );
452
453     if (!(msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return FALSE;
454     pos = msgQueue->nextFreeMessage;
455
456       /* Check if queue is full */
457     if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0))
458     {
459         SIGNAL_MaskAsyncEvents( FALSE );
460         WARN( msg,"Queue is full!\n" );
461         return FALSE;
462     }
463
464       /* Store message */
465     msgQueue->messages[pos].msg = *msg;
466     msgQueue->messages[pos].extraInfo = extraInfo;
467     if (pos < msgQueue->queueSize-1) pos++;
468     else pos = 0;
469     msgQueue->nextFreeMessage = pos;
470     msgQueue->msgCount++;
471
472     SIGNAL_MaskAsyncEvents( FALSE );
473
474     QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
475     return TRUE;
476 }
477
478
479 /***********************************************************************
480  *           QUEUE_FindMsg
481  *
482  * Find a message matching the given parameters. Return -1 if none available.
483  */
484 int QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND32 hwnd, int first, int last )
485 {
486     int i, pos = msgQueue->nextMessage;
487
488     TRACE(msg,"hwnd=%04x pos=%d\n", hwnd, pos );
489
490     if (!msgQueue->msgCount) return -1;
491     if (!hwnd && !first && !last) return pos;
492         
493     for (i = 0; i < msgQueue->msgCount; i++)
494     {
495         MSG16 * msg = &msgQueue->messages[pos].msg;
496
497         if (!hwnd || (msg->hwnd == hwnd))
498         {
499             if (!first && !last) return pos;
500             if ((msg->message >= first) && (msg->message <= last)) return pos;
501         }
502         if (pos < msgQueue->queueSize-1) pos++;
503         else pos = 0;
504     }
505     return -1;
506 }
507
508
509 /***********************************************************************
510  *           QUEUE_RemoveMsg
511  *
512  * Remove a message from the queue (pos must be a valid position).
513  */
514 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
515 {
516     SIGNAL_MaskAsyncEvents( TRUE );
517
518     if (pos >= msgQueue->nextMessage)
519     {
520         for ( ; pos > msgQueue->nextMessage; pos--)
521             msgQueue->messages[pos] = msgQueue->messages[pos-1];
522         msgQueue->nextMessage++;
523         if (msgQueue->nextMessage >= msgQueue->queueSize)
524             msgQueue->nextMessage = 0;
525     }
526     else
527     {
528         for ( ; pos < msgQueue->nextFreeMessage; pos++)
529             msgQueue->messages[pos] = msgQueue->messages[pos+1];
530         if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
531         else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
532     }
533     msgQueue->msgCount--;
534     if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
535
536     SIGNAL_MaskAsyncEvents( FALSE );
537 }
538
539
540 /***********************************************************************
541  *           QUEUE_WakeSomeone
542  *
543  * Wake a queue upon reception of a hardware event.
544  */
545 static void QUEUE_WakeSomeone( UINT32 message )
546 {
547     WND*          wndPtr = NULL;
548     WORD          wakeBit;
549     HWND32 hwnd;
550     MESSAGEQUEUE *queue = pCursorQueue;
551
552     if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
553     {
554        wakeBit = QS_KEY;
555        if( pActiveQueue ) queue = pActiveQueue;
556     }
557     else 
558     {
559        wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
560        if( (hwnd = GetCapture32()) )
561          if( (wndPtr = WIN_FindWndPtr( hwnd )) ) 
562            queue = (MESSAGEQUEUE *)GlobalLock16( wndPtr->hmemTaskQ );
563     }
564
565     if( (hwnd = GetSysModalWindow16()) )
566       if( (wndPtr = WIN_FindWndPtr( hwnd )) )
567         queue = (MESSAGEQUEUE *)GlobalLock16( wndPtr->hmemTaskQ );
568
569     if( !queue ) 
570     {
571       queue = GlobalLock16( hFirstQueue );
572       while( queue )
573       {
574         if (queue->wakeMask & wakeBit) break;
575         queue = GlobalLock16( queue->next );
576       }
577       if( !queue )
578       { 
579         WARN(msg, "couldn't find queue\n"); 
580         return; 
581       }
582     }
583
584     QUEUE_SetWakeBit( queue, wakeBit );
585 }
586
587
588 /***********************************************************************
589  *           hardware_event
590  *
591  * Add an event to the system message queue.
592  * Note: the position is relative to the desktop window.
593  */
594 void hardware_event( WORD message, WORD wParam, LONG lParam,
595                      int xPos, int yPos, DWORD time, DWORD extraInfo )
596 {
597     MSG16 *msg;
598     int pos;
599
600     if (!sysMsgQueue) return;
601     pos = sysMsgQueue->nextFreeMessage;
602
603       /* Merge with previous event if possible */
604
605     if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
606     {
607         if (pos > 0) pos--;
608         else pos = sysMsgQueue->queueSize - 1;
609         msg = &sysMsgQueue->messages[pos].msg;
610         if ((msg->message == message) && (msg->wParam == wParam))
611             sysMsgQueue->msgCount--;  /* Merge events */
612         else
613             pos = sysMsgQueue->nextFreeMessage;  /* Don't merge */
614     }
615
616       /* Check if queue is full */
617
618     if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
619     {
620         /* Queue is full, beep (but not on every mouse motion...) */
621         if (message != WM_MOUSEMOVE) MessageBeep32(0);
622         return;
623     }
624
625       /* Store message */
626
627     msg = &sysMsgQueue->messages[pos].msg;
628     msg->hwnd    = 0;
629     msg->message = message;
630     msg->wParam  = wParam;
631     msg->lParam  = lParam;
632     msg->time    = time;
633     msg->pt.x    = xPos & 0xffff;
634     msg->pt.y    = yPos & 0xffff;
635     sysMsgQueue->messages[pos].extraInfo = extraInfo;
636     if (pos < sysMsgQueue->queueSize - 1) pos++;
637     else pos = 0;
638     sysMsgQueue->nextFreeMessage = pos;
639     sysMsgQueue->msgCount++;
640     QUEUE_WakeSomeone( message );
641 }
642
643                     
644 /***********************************************************************
645  *           QUEUE_GetQueueTask
646  */
647 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
648 {
649     MESSAGEQUEUE *queue = GlobalLock16( hQueue );
650     return (queue) ? queue->hTask : 0 ;
651 }
652
653
654 /***********************************************************************
655  *           QUEUE_IncPaintCount
656  */
657 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
658 {
659     MESSAGEQUEUE *queue;
660
661     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
662     queue->wPaintCount++;
663     QUEUE_SetWakeBit( queue, QS_PAINT );
664 }
665
666
667 /***********************************************************************
668  *           QUEUE_DecPaintCount
669  */
670 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
671 {
672     MESSAGEQUEUE *queue;
673
674     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
675     queue->wPaintCount--;
676     if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
677 }
678
679
680 /***********************************************************************
681  *           QUEUE_IncTimerCount
682  */
683 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
684 {
685     MESSAGEQUEUE *queue;
686
687     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
688     queue->wTimerCount++;
689     QUEUE_SetWakeBit( queue, QS_TIMER );
690 }
691
692
693 /***********************************************************************
694  *           QUEUE_DecTimerCount
695  */
696 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
697 {
698     MESSAGEQUEUE *queue;
699
700     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
701     queue->wTimerCount--;
702     if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
703 }
704
705
706 /***********************************************************************
707  *           PostQuitMessage16   (USER.6)
708  */
709 void WINAPI PostQuitMessage16( INT16 exitCode )
710 {
711     PostQuitMessage32( exitCode );
712 }
713
714
715 /***********************************************************************
716  *           PostQuitMessage32   (USER32.421)
717  *
718  * PostQuitMessage() posts a message to the system requesting an
719  * application to terminate execution. As a result of this function,
720  * the WM_QUIT message is posted to the application, and
721  * PostQuitMessage() returns immediately.  The exitCode parameter
722  * specifies an application-defined exit code, which appears in the
723  * _wParam_ parameter of the WM_QUIT message posted to the application.  
724  *
725  * CONFORMANCE
726  *
727  *  ECMA-234, Win32
728  */
729 void WINAPI PostQuitMessage32( INT32 exitCode )
730 {
731     MESSAGEQUEUE *queue;
732
733     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return;
734     queue->wPostQMsg = TRUE;
735     queue->wExitCode = (WORD)exitCode;
736 }
737
738
739 /***********************************************************************
740  *           GetWindowTask16   (USER.224)
741  */
742 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
743 {
744     WND *wndPtr = WIN_FindWndPtr( hwnd );
745
746     if (!wndPtr) return 0;
747     return QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
748 }
749
750 /***********************************************************************
751  *           GetWindowThreadProcessId   (USER32.313)
752  */
753 DWORD WINAPI GetWindowThreadProcessId( HWND32 hwnd, LPDWORD process )
754 {
755     HTASK16 htask;
756     TDB *tdb;
757
758     WND *wndPtr = WIN_FindWndPtr( hwnd );
759
760     if (!wndPtr) return 0;
761     htask=QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
762     tdb = (TDB*)GlobalLock16(htask);
763     if (!tdb || !tdb->thdb) return 0;
764     if (process) *process = PDB_TO_PROCESS_ID( tdb->thdb->process );
765     return THDB_TO_THREAD_ID( tdb->thdb );
766 }
767
768
769 /***********************************************************************
770  *           SetMessageQueue16   (USER.266)
771  */
772 BOOL16 WINAPI SetMessageQueue16( INT16 size )
773 {
774     return SetMessageQueue32( size );
775 }
776
777
778 /***********************************************************************
779  *           SetMessageQueue32   (USER32.494)
780  */
781 BOOL32 WINAPI SetMessageQueue32( INT32 size )
782 {
783     HQUEUE16 hQueue, hNewQueue;
784     MESSAGEQUEUE *queuePtr;
785
786     TRACE(msg,"task %04x size %i\n", GetCurrentTask(), size); 
787
788     if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return FALSE;
789
790     if( !(hNewQueue = QUEUE_CreateMsgQueue( size ))) 
791     {
792         WARN(msg, "failed!\n");
793         return FALSE;
794     }
795     queuePtr = (MESSAGEQUEUE *)GlobalLock16( hNewQueue );
796
797     SIGNAL_MaskAsyncEvents( TRUE );
798
799     /* Copy data and free the old message queue */
800     if ((hQueue = GetThreadQueue(0)) != 0) 
801     {
802        MESSAGEQUEUE *oldQ = (MESSAGEQUEUE *)GlobalLock16( hQueue );
803        memcpy( &queuePtr->wParamHigh, &oldQ->wParamHigh,
804                         (int)oldQ->messages - (int)(&oldQ->wParamHigh) );
805        HOOK_ResetQueueHooks( hNewQueue );
806        if( WIN_GetDesktop()->hmemTaskQ == hQueue )
807            WIN_GetDesktop()->hmemTaskQ = hNewQueue;
808        WIN_ResetQueueWindows( WIN_GetDesktop(), hQueue, hNewQueue );
809        CLIPBOARD_ResetLock( hQueue, hNewQueue );
810        QUEUE_DeleteMsgQueue( hQueue );
811     }
812
813     /* Link new queue into list */
814     queuePtr->hTask = GetCurrentTask();
815     queuePtr->next  = hFirstQueue;
816     hFirstQueue = hNewQueue;
817     
818     if( !queuePtr->next ) pCursorQueue = queuePtr;
819     SetThreadQueue( 0, hNewQueue );
820     
821     SIGNAL_MaskAsyncEvents( FALSE );
822     return TRUE;
823 }
824
825 /***********************************************************************
826  *           InitThreadInput   (USER.409)
827  */
828 HQUEUE16 WINAPI InitThreadInput( WORD unknown, WORD flags )
829 {
830     HQUEUE16 hQueue = GetTaskQueue( 0 );
831
832     FIXME( msg, "(%04X,%04X): should create thread-local message queue!\n",
833                 unknown, flags );
834
835     SetFastQueue( 0, hQueue );    
836     return hQueue;
837 }
838
839 /***********************************************************************
840  *           GetQueueStatus16   (USER.334)
841  */
842 DWORD WINAPI GetQueueStatus16( UINT16 flags )
843 {
844     MESSAGEQUEUE *queue;
845     DWORD ret;
846
847     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return 0;
848     ret = MAKELONG( queue->changeBits, queue->wakeBits );
849     queue->changeBits = 0;
850     return ret & MAKELONG( flags, flags );
851 }
852
853 /***********************************************************************
854  *           GetQueueStatus32   (USER32.283)
855  */
856 DWORD WINAPI GetQueueStatus32( UINT32 flags )
857 {
858     MESSAGEQUEUE *queue;
859     DWORD ret;
860
861     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return 0;
862     ret = MAKELONG( queue->changeBits, queue->wakeBits );
863     queue->changeBits = 0;
864     return ret & MAKELONG( flags, flags );
865 }
866
867
868 /***********************************************************************
869  *           GetInputState16   (USER.335)
870  */
871 BOOL16 WINAPI GetInputState16(void)
872 {
873     return GetInputState32();
874 }
875
876 /***********************************************************************
877  *           WaitForInputIdle   (USER32.577)
878  */
879 DWORD WINAPI WaitForInputIdle (HANDLE32 hProcess, DWORD dwTimeOut)
880 {
881   FIXME (msg, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
882
883   return WAIT_TIMEOUT;
884 }
885
886
887 /***********************************************************************
888  *           GetInputState32   (USER32.244)
889  */
890 BOOL32 WINAPI GetInputState32(void)
891 {
892     MESSAGEQUEUE *queue;
893
894     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() )))
895         return FALSE;
896     return queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
897 }
898
899 /***********************************************************************
900  *           UserYield  (USER.332)
901  */
902 void WINAPI UserYield(void)
903 {
904     TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
905     MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( pCurTask->hQueue );
906
907     if ( !THREAD_IsWin16( THREAD_Current() ) )
908     {
909         FIXME(task, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel);
910         return;
911     }
912
913     /* Handle sent messages */
914     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
915         QUEUE_ReceiveMessage( queue );
916
917     OldYield();
918
919     queue = (MESSAGEQUEUE *)GlobalLock16( pCurTask->hQueue );
920     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
921         QUEUE_ReceiveMessage( queue );
922 }
923
924 /***********************************************************************
925  *           GetMessagePos   (USER.119) (USER32.272)
926  * 
927  * The GetMessagePos() function returns a long value representing a
928  * cursor position, in screen coordinates, when the last message
929  * retrieved by the GetMessage() function occurs. The x-coordinate is
930  * in the low-order word of the return value, the y-coordinate is in
931  * the high-order word. The application can use the MAKEPOINT()
932  * macro to obtain a POINT structure from the return value. 
933  *
934  * For the current cursor position, use GetCursorPos().
935  *
936  * RETURNS
937  *
938  * Cursor position of last message on success, zero on failure.
939  *
940  * CONFORMANCE
941  *
942  * ECMA-234, Win32
943  *
944  */
945 DWORD WINAPI GetMessagePos(void)
946 {
947     MESSAGEQUEUE *queue;
948
949     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return 0;
950     return queue->GetMessagePosVal;
951 }
952
953
954 /***********************************************************************
955  *           GetMessageTime   (USER.120) (USER32.273)
956  *
957  * GetMessageTime() returns the message time for the last message
958  * retrieved by the function. The time is measured in milliseconds with
959  * the same offset as GetTickCount().
960  *
961  * Since the tick count wraps, this is only useful for moderately short
962  * relative time comparisons.
963  *
964  * RETURNS
965  *
966  * Time of last message on success, zero on failure.
967  *
968  * CONFORMANCE
969  *
970  * ECMA-234, Win32
971  *  
972  */
973 LONG WINAPI GetMessageTime(void)
974 {
975     MESSAGEQUEUE *queue;
976
977     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return 0;
978     return queue->GetMessageTimeVal;
979 }
980
981
982 /***********************************************************************
983  *           GetMessageExtraInfo   (USER.288) (USER32.271)
984  */
985 LONG WINAPI GetMessageExtraInfo(void)
986 {
987     MESSAGEQUEUE *queue;
988
989     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return 0;
990     return queue->GetMessageExtraInfoVal;
991 }