Removed client-side wait functions; all waiting is now done through
[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     int wakeup = FALSE;
228
229     TDB *pTask = (TDB *)GlobalLock16( hTask );
230     if ( !pTask ) return;
231
232     TRACE(msg, "calling SYNC_MsgWakeUp\n");
233
234     /* Wake up thread waiting for message */
235     /* NOTE: This should really wake up *the* thread that owns
236              the queue. Since we dont't have thread-local message
237              queues yet, we wake up all waiting threads ... */
238 #if 0
239     /* FIXME: should be replaced by a server event */
240     SYSTEM_LOCK();
241     pdb = pTask->thdb->process;
242     entry = pdb? pdb->thread_list->next : NULL;
243
244     if (entry)
245         for (;;)
246         {
247             if (entry->thread->wait_struct.wait_msg)
248             {
249                 SYNC_MsgWakeUp( entry->thread );
250                 wakeup = TRUE;
251             }
252             if (entry == pdb->thread_list) break;
253             entry = entry->next;
254         }
255     SYSTEM_UNLOCK();
256 #endif
257
258 /*    if ( !wakeup )*/
259         PostEvent( hTask );
260 }
261
262 /***********************************************************************
263  *           QUEUE_Wait
264  */
265 void QUEUE_Wait( void )
266 {
267     if ( THREAD_IsWin16( THREAD_Current() ) )
268         WaitEvent( 0 );
269     else
270     {
271         TRACE(msg, "current task is 32-bit, calling SYNC_DoWait\n");
272         SYNC_DoWait( 0, NULL, FALSE, INFINITE32, FALSE, TRUE );
273     }
274 }
275
276
277 /***********************************************************************
278  *           QUEUE_SetWakeBit
279  *
280  * See "Windows Internals", p.449
281  */
282 void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
283 {
284     TRACE(msg,"queue = %04x (wm=%04x), bit = %04x\n", 
285                         queue->self, queue->wakeMask, bit );
286
287     if (bit & QS_MOUSE) pMouseQueue = queue;
288     if (bit & QS_KEY) pKbdQueue = queue;
289     queue->changeBits |= bit;
290     queue->wakeBits   |= bit;
291     if (queue->wakeMask & bit)
292     {
293         queue->wakeMask = 0;
294         QUEUE_Signal( queue->hTask );
295     }
296 }
297
298
299 /***********************************************************************
300  *           QUEUE_ClearWakeBit
301  */
302 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
303 {
304     queue->changeBits &= ~bit;
305     queue->wakeBits   &= ~bit;
306 }
307
308
309 /***********************************************************************
310  *           QUEUE_WaitBits
311  *
312  * See "Windows Internals", p.447
313  */
314 void QUEUE_WaitBits( WORD bits )
315 {
316     MESSAGEQUEUE *queue;
317
318     TRACE(msg,"q %04x waiting for %04x\n", GetFastQueue(), bits);
319
320     for (;;)
321     {
322         if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return;
323
324         if (queue->changeBits & bits)
325         {
326             /* One of the bits is set; we can return */
327             queue->wakeMask = 0;
328             return;
329         }
330         if (queue->wakeBits & QS_SENDMESSAGE)
331         {
332             /* Process the sent message immediately */
333
334             queue->wakeMask = 0;
335             QUEUE_ReceiveMessage( queue );
336             continue;                           /* nested sm crux */
337         }
338
339         queue->wakeMask = bits | QS_SENDMESSAGE;
340         if(queue->changeBits & bits) continue;
341         
342         TRACE(msg,"%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
343
344         QUEUE_Wait();
345     }
346 }
347
348
349 /***********************************************************************
350  *           QUEUE_ReceiveMessage
351  *
352  * This routine is called when a sent message is waiting for the queue.
353  */
354 void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
355 {
356     MESSAGEQUEUE *senderQ = NULL;
357     HQUEUE16      prevSender = 0;
358     QSMCTRL*      prevCtrlPtr = NULL;
359     LRESULT       result = 0;
360
361     TRACE(msg, "ReceiveMessage, queue %04x\n", queue->self );
362     if (!(queue->wakeBits & QS_SENDMESSAGE) ||
363         !(senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask))) 
364         { TRACE(msg,"\trcm: nothing to do\n"); return; }
365
366     if( !senderQ->hPrevSendingTask )
367         QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );   /* no more sent messages */
368
369     /* Save current state on stack */
370     prevSender                 = queue->InSendMessageHandle;
371     prevCtrlPtr                = queue->smResultCurrent;
372
373     /* Remove sending queue from the list */
374     queue->InSendMessageHandle = queue->hSendingTask;
375     queue->smResultCurrent     = senderQ->smResultInit;
376     queue->hSendingTask        = senderQ->hPrevSendingTask;
377
378     TRACE(msg, "\trcm: smResultCurrent = %08x, prevCtrl = %08x\n", 
379                                 (unsigned)queue->smResultCurrent, (unsigned)prevCtrlPtr );
380     QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
381
382     TRACE(msg, "\trcm: calling wndproc - %04x %04x %04x%04x %08x\n",
383                 senderQ->hWnd, senderQ->msg, senderQ->wParamHigh,
384                 senderQ->wParam, (unsigned)senderQ->lParam );
385
386     if (IsWindow32( senderQ->hWnd ))
387     {
388         WND *wndPtr = WIN_FindWndPtr( senderQ->hWnd );
389         DWORD extraInfo = queue->GetMessageExtraInfoVal;
390         queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
391
392         if (senderQ->flags & QUEUE_SM_WIN32)
393         {
394             WPARAM32 wParam = MAKELONG( senderQ->wParam, senderQ->wParamHigh );
395             TRACE(msg, "\trcm: msg is Win32\n" );
396             if (senderQ->flags & QUEUE_SM_UNICODE)
397                 result = CallWindowProc32W( wndPtr->winproc,
398                                             senderQ->hWnd, senderQ->msg,
399                                             wParam, senderQ->lParam );
400             else
401                 result = CallWindowProc32A( wndPtr->winproc,
402                                             senderQ->hWnd, senderQ->msg,
403                                             wParam, senderQ->lParam );
404         }
405         else  /* Win16 message */
406             result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
407                                        senderQ->hWnd, senderQ->msg,
408                                        senderQ->wParam, senderQ->lParam );
409
410         queue->GetMessageExtraInfoVal = extraInfo;  /* Restore extra info */
411         TRACE(msg,"\trcm: result =  %08x\n", (unsigned)result );
412     }
413     else WARN(msg, "\trcm: bad hWnd\n");
414
415     /* Return the result to the sender task */
416     ReplyMessage16( result );
417
418     queue->InSendMessageHandle = prevSender;
419     queue->smResultCurrent     = prevCtrlPtr;
420
421     TRACE(msg,"done!\n");
422 }
423
424 /***********************************************************************
425  *           QUEUE_FlushMessage
426  * 
427  * Try to reply to all pending sent messages on exit.
428  */
429 void QUEUE_FlushMessages( HQUEUE16 hQueue )
430 {
431   MESSAGEQUEUE *queue = (MESSAGEQUEUE*)GlobalLock16( hQueue );
432
433   if( queue )
434   {
435     MESSAGEQUEUE *senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask);
436     QSMCTRL*      CtrlPtr = queue->smResultCurrent;
437
438     TRACE(msg,"Flushing queue %04x:\n", hQueue );
439
440     while( senderQ )
441     {
442       if( !CtrlPtr )
443            CtrlPtr = senderQ->smResultInit;
444
445       TRACE(msg,"\tfrom queue %04x, smResult %08x\n", queue->hSendingTask, (unsigned)CtrlPtr );
446
447       if( !(queue->hSendingTask = senderQ->hPrevSendingTask) )
448         QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
449
450       QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
451       
452       queue->smResultCurrent = CtrlPtr;
453       while( senderQ->wakeBits & QS_SMRESULT ) OldYield();
454
455       senderQ->SendMessageReturn = 0;
456       senderQ->smResult = queue->smResultCurrent;
457       QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
458
459       senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask);
460       CtrlPtr = NULL;
461     }
462     queue->InSendMessageHandle = 0;
463   }  
464 }
465
466 /***********************************************************************
467  *           QUEUE_AddMsg
468  *
469  * Add a message to the queue. Return FALSE if queue is full.
470  */
471 BOOL32 QUEUE_AddMsg( HQUEUE16 hQueue, MSG16 * msg, DWORD extraInfo )
472 {
473     int pos;
474     MESSAGEQUEUE *msgQueue;
475
476     SIGNAL_MaskAsyncEvents( TRUE );
477
478     if (!(msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return FALSE;
479     pos = msgQueue->nextFreeMessage;
480
481       /* Check if queue is full */
482     if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0))
483     {
484         SIGNAL_MaskAsyncEvents( FALSE );
485         WARN( msg,"Queue is full!\n" );
486         return FALSE;
487     }
488
489       /* Store message */
490     msgQueue->messages[pos].msg = *msg;
491     msgQueue->messages[pos].extraInfo = extraInfo;
492     if (pos < msgQueue->queueSize-1) pos++;
493     else pos = 0;
494     msgQueue->nextFreeMessage = pos;
495     msgQueue->msgCount++;
496
497     SIGNAL_MaskAsyncEvents( FALSE );
498
499     QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
500     return TRUE;
501 }
502
503
504 /***********************************************************************
505  *           QUEUE_FindMsg
506  *
507  * Find a message matching the given parameters. Return -1 if none available.
508  */
509 int QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND32 hwnd, int first, int last )
510 {
511     int i, pos = msgQueue->nextMessage;
512
513     TRACE(msg,"hwnd=%04x pos=%d\n", hwnd, pos );
514
515     if (!msgQueue->msgCount) return -1;
516     if (!hwnd && !first && !last) return pos;
517         
518     for (i = 0; i < msgQueue->msgCount; i++)
519     {
520         MSG16 * msg = &msgQueue->messages[pos].msg;
521
522         if (!hwnd || (msg->hwnd == hwnd))
523         {
524             if (!first && !last) return pos;
525             if ((msg->message >= first) && (msg->message <= last)) return pos;
526         }
527         if (pos < msgQueue->queueSize-1) pos++;
528         else pos = 0;
529     }
530     return -1;
531 }
532
533
534 /***********************************************************************
535  *           QUEUE_RemoveMsg
536  *
537  * Remove a message from the queue (pos must be a valid position).
538  */
539 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
540 {
541     SIGNAL_MaskAsyncEvents( TRUE );
542
543     if (pos >= msgQueue->nextMessage)
544     {
545         for ( ; pos > msgQueue->nextMessage; pos--)
546             msgQueue->messages[pos] = msgQueue->messages[pos-1];
547         msgQueue->nextMessage++;
548         if (msgQueue->nextMessage >= msgQueue->queueSize)
549             msgQueue->nextMessage = 0;
550     }
551     else
552     {
553         for ( ; pos < msgQueue->nextFreeMessage; pos++)
554             msgQueue->messages[pos] = msgQueue->messages[pos+1];
555         if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
556         else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
557     }
558     msgQueue->msgCount--;
559     if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
560
561     SIGNAL_MaskAsyncEvents( FALSE );
562 }
563
564
565 /***********************************************************************
566  *           QUEUE_WakeSomeone
567  *
568  * Wake a queue upon reception of a hardware event.
569  */
570 static void QUEUE_WakeSomeone( UINT32 message )
571 {
572     WND*          wndPtr = NULL;
573     WORD          wakeBit;
574     HWND32 hwnd;
575     MESSAGEQUEUE *queue = pCursorQueue;
576
577     if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
578     {
579        wakeBit = QS_KEY;
580        if( pActiveQueue ) queue = pActiveQueue;
581     }
582     else 
583     {
584        wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
585        if( (hwnd = GetCapture32()) )
586          if( (wndPtr = WIN_FindWndPtr( hwnd )) ) 
587            queue = (MESSAGEQUEUE *)GlobalLock16( wndPtr->hmemTaskQ );
588     }
589
590     if( (hwnd = GetSysModalWindow16()) )
591       if( (wndPtr = WIN_FindWndPtr( hwnd )) )
592         queue = (MESSAGEQUEUE *)GlobalLock16( wndPtr->hmemTaskQ );
593
594     if( !queue ) 
595     {
596       queue = GlobalLock16( hFirstQueue );
597       while( queue )
598       {
599         if (queue->wakeMask & wakeBit) break;
600         queue = GlobalLock16( queue->next );
601       }
602       if( !queue )
603       { 
604         WARN(msg, "couldn't find queue\n"); 
605         return; 
606       }
607     }
608
609     QUEUE_SetWakeBit( queue, wakeBit );
610 }
611
612
613 /***********************************************************************
614  *           hardware_event
615  *
616  * Add an event to the system message queue.
617  * Note: the position is relative to the desktop window.
618  */
619 void hardware_event( WORD message, WORD wParam, LONG lParam,
620                      int xPos, int yPos, DWORD time, DWORD extraInfo )
621 {
622     MSG16 *msg;
623     int pos;
624
625     if (!sysMsgQueue) return;
626     pos = sysMsgQueue->nextFreeMessage;
627
628       /* Merge with previous event if possible */
629
630     if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
631     {
632         if (pos > 0) pos--;
633         else pos = sysMsgQueue->queueSize - 1;
634         msg = &sysMsgQueue->messages[pos].msg;
635         if ((msg->message == message) && (msg->wParam == wParam))
636             sysMsgQueue->msgCount--;  /* Merge events */
637         else
638             pos = sysMsgQueue->nextFreeMessage;  /* Don't merge */
639     }
640
641       /* Check if queue is full */
642
643     if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
644     {
645         /* Queue is full, beep (but not on every mouse motion...) */
646         if (message != WM_MOUSEMOVE) MessageBeep32(0);
647         return;
648     }
649
650       /* Store message */
651
652     msg = &sysMsgQueue->messages[pos].msg;
653     msg->hwnd    = 0;
654     msg->message = message;
655     msg->wParam  = wParam;
656     msg->lParam  = lParam;
657     msg->time    = time;
658     msg->pt.x    = xPos & 0xffff;
659     msg->pt.y    = yPos & 0xffff;
660     sysMsgQueue->messages[pos].extraInfo = extraInfo;
661     if (pos < sysMsgQueue->queueSize - 1) pos++;
662     else pos = 0;
663     sysMsgQueue->nextFreeMessage = pos;
664     sysMsgQueue->msgCount++;
665     QUEUE_WakeSomeone( message );
666 }
667
668                     
669 /***********************************************************************
670  *           QUEUE_GetQueueTask
671  */
672 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
673 {
674     MESSAGEQUEUE *queue = GlobalLock16( hQueue );
675     return (queue) ? queue->hTask : 0 ;
676 }
677
678
679 /***********************************************************************
680  *           QUEUE_IncPaintCount
681  */
682 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
683 {
684     MESSAGEQUEUE *queue;
685
686     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
687     queue->wPaintCount++;
688     QUEUE_SetWakeBit( queue, QS_PAINT );
689 }
690
691
692 /***********************************************************************
693  *           QUEUE_DecPaintCount
694  */
695 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
696 {
697     MESSAGEQUEUE *queue;
698
699     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
700     queue->wPaintCount--;
701     if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
702 }
703
704
705 /***********************************************************************
706  *           QUEUE_IncTimerCount
707  */
708 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
709 {
710     MESSAGEQUEUE *queue;
711
712     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
713     queue->wTimerCount++;
714     QUEUE_SetWakeBit( queue, QS_TIMER );
715 }
716
717
718 /***********************************************************************
719  *           QUEUE_DecTimerCount
720  */
721 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
722 {
723     MESSAGEQUEUE *queue;
724
725     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
726     queue->wTimerCount--;
727     if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
728 }
729
730
731 /***********************************************************************
732  *           PostQuitMessage16   (USER.6)
733  */
734 void WINAPI PostQuitMessage16( INT16 exitCode )
735 {
736     PostQuitMessage32( exitCode );
737 }
738
739
740 /***********************************************************************
741  *           PostQuitMessage32   (USER32.421)
742  *
743  * PostQuitMessage() posts a message to the system requesting an
744  * application to terminate execution. As a result of this function,
745  * the WM_QUIT message is posted to the application, and
746  * PostQuitMessage() returns immediately.  The exitCode parameter
747  * specifies an application-defined exit code, which appears in the
748  * _wParam_ parameter of the WM_QUIT message posted to the application.  
749  *
750  * CONFORMANCE
751  *
752  *  ECMA-234, Win32
753  */
754 void WINAPI PostQuitMessage32( INT32 exitCode )
755 {
756     MESSAGEQUEUE *queue;
757
758     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return;
759     queue->wPostQMsg = TRUE;
760     queue->wExitCode = (WORD)exitCode;
761 }
762
763
764 /***********************************************************************
765  *           GetWindowTask16   (USER.224)
766  */
767 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
768 {
769     WND *wndPtr = WIN_FindWndPtr( hwnd );
770
771     if (!wndPtr) return 0;
772     return QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
773 }
774
775 /***********************************************************************
776  *           GetWindowThreadProcessId   (USER32.313)
777  */
778 DWORD WINAPI GetWindowThreadProcessId( HWND32 hwnd, LPDWORD process )
779 {
780     HTASK16 htask;
781     TDB *tdb;
782
783     WND *wndPtr = WIN_FindWndPtr( hwnd );
784
785     if (!wndPtr) return 0;
786     htask=QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
787     tdb = (TDB*)GlobalLock16(htask);
788     if (!tdb || !tdb->thdb) return 0;
789     if (process) *process = PDB_TO_PROCESS_ID( tdb->thdb->process );
790     return THDB_TO_THREAD_ID( tdb->thdb );
791 }
792
793
794 /***********************************************************************
795  *           SetMessageQueue16   (USER.266)
796  */
797 BOOL16 WINAPI SetMessageQueue16( INT16 size )
798 {
799     return SetMessageQueue32( size );
800 }
801
802
803 /***********************************************************************
804  *           SetMessageQueue32   (USER32.494)
805  */
806 BOOL32 WINAPI SetMessageQueue32( INT32 size )
807 {
808     HQUEUE16 hQueue, hNewQueue;
809     MESSAGEQUEUE *queuePtr;
810
811     TRACE(msg,"task %04x size %i\n", GetCurrentTask(), size); 
812
813     if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return FALSE;
814
815     if( !(hNewQueue = QUEUE_CreateMsgQueue( size ))) 
816     {
817         WARN(msg, "failed!\n");
818         return FALSE;
819     }
820     queuePtr = (MESSAGEQUEUE *)GlobalLock16( hNewQueue );
821
822     SIGNAL_MaskAsyncEvents( TRUE );
823
824     /* Copy data and free the old message queue */
825     if ((hQueue = GetThreadQueue(0)) != 0) 
826     {
827        MESSAGEQUEUE *oldQ = (MESSAGEQUEUE *)GlobalLock16( hQueue );
828        memcpy( &queuePtr->wParamHigh, &oldQ->wParamHigh,
829                         (int)oldQ->messages - (int)(&oldQ->wParamHigh) );
830        HOOK_ResetQueueHooks( hNewQueue );
831        if( WIN_GetDesktop()->hmemTaskQ == hQueue )
832            WIN_GetDesktop()->hmemTaskQ = hNewQueue;
833        WIN_ResetQueueWindows( WIN_GetDesktop(), hQueue, hNewQueue );
834        CLIPBOARD_ResetLock( hQueue, hNewQueue );
835        QUEUE_DeleteMsgQueue( hQueue );
836     }
837
838     /* Link new queue into list */
839     queuePtr->hTask = GetCurrentTask();
840     queuePtr->next  = hFirstQueue;
841     hFirstQueue = hNewQueue;
842     
843     if( !queuePtr->next ) pCursorQueue = queuePtr;
844     SetThreadQueue( 0, hNewQueue );
845     
846     SIGNAL_MaskAsyncEvents( FALSE );
847     return TRUE;
848 }
849
850 /***********************************************************************
851  *           InitThreadInput   (USER.409)
852  */
853 HQUEUE16 WINAPI InitThreadInput( WORD unknown, WORD flags )
854 {
855     HQUEUE16 hQueue = GetTaskQueue( 0 );
856
857     FIXME( msg, "(%04X,%04X): should create thread-local message queue!\n",
858                 unknown, flags );
859
860     SetFastQueue( 0, hQueue );    
861     return hQueue;
862 }
863
864 /***********************************************************************
865  *           GetQueueStatus16   (USER.334)
866  */
867 DWORD WINAPI GetQueueStatus16( UINT16 flags )
868 {
869     MESSAGEQUEUE *queue;
870     DWORD ret;
871
872     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return 0;
873     ret = MAKELONG( queue->changeBits, queue->wakeBits );
874     queue->changeBits = 0;
875     return ret & MAKELONG( flags, flags );
876 }
877
878 /***********************************************************************
879  *           GetQueueStatus32   (USER32.283)
880  */
881 DWORD WINAPI GetQueueStatus32( UINT32 flags )
882 {
883     MESSAGEQUEUE *queue;
884     DWORD ret;
885
886     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return 0;
887     ret = MAKELONG( queue->changeBits, queue->wakeBits );
888     queue->changeBits = 0;
889     return ret & MAKELONG( flags, flags );
890 }
891
892
893 /***********************************************************************
894  *           GetInputState16   (USER.335)
895  */
896 BOOL16 WINAPI GetInputState16(void)
897 {
898     return GetInputState32();
899 }
900
901 /***********************************************************************
902  *           WaitForInputIdle   (USER32.577)
903  */
904 DWORD WINAPI WaitForInputIdle (HANDLE32 hProcess, DWORD dwTimeOut)
905 {
906   FIXME (msg, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
907
908   return WAIT_TIMEOUT;
909 }
910
911
912 /***********************************************************************
913  *           GetInputState32   (USER32.244)
914  */
915 BOOL32 WINAPI GetInputState32(void)
916 {
917     MESSAGEQUEUE *queue;
918
919     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() )))
920         return FALSE;
921     return queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
922 }
923
924 /***********************************************************************
925  *           UserYield  (USER.332)
926  */
927 void WINAPI UserYield(void)
928 {
929     TDB *pCurTask = (TDB *)GlobalLock16( GetCurrentTask() );
930     MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( pCurTask->hQueue );
931
932     if ( !THREAD_IsWin16( THREAD_Current() ) )
933     {
934         FIXME(task, "called for Win32 thread (%04x)!\n", THREAD_Current()->teb_sel);
935         return;
936     }
937
938     /* Handle sent messages */
939     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
940         QUEUE_ReceiveMessage( queue );
941
942     OldYield();
943
944     queue = (MESSAGEQUEUE *)GlobalLock16( pCurTask->hQueue );
945     while (queue && (queue->wakeBits & QS_SENDMESSAGE))
946         QUEUE_ReceiveMessage( queue );
947 }
948
949 /***********************************************************************
950  *           GetMessagePos   (USER.119) (USER32.272)
951  * 
952  * The GetMessagePos() function returns a long value representing a
953  * cursor position, in screen coordinates, when the last message
954  * retrieved by the GetMessage() function occurs. The x-coordinate is
955  * in the low-order word of the return value, the y-coordinate is in
956  * the high-order word. The application can use the MAKEPOINT()
957  * macro to obtain a POINT structure from the return value. 
958  *
959  * For the current cursor position, use GetCursorPos().
960  *
961  * RETURNS
962  *
963  * Cursor position of last message on success, zero on failure.
964  *
965  * CONFORMANCE
966  *
967  * ECMA-234, Win32
968  *
969  */
970 DWORD WINAPI GetMessagePos(void)
971 {
972     MESSAGEQUEUE *queue;
973
974     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return 0;
975     return queue->GetMessagePosVal;
976 }
977
978
979 /***********************************************************************
980  *           GetMessageTime   (USER.120) (USER32.273)
981  *
982  * GetMessageTime() returns the message time for the last message
983  * retrieved by the function. The time is measured in milliseconds with
984  * the same offset as GetTickCount().
985  *
986  * Since the tick count wraps, this is only useful for moderately short
987  * relative time comparisons.
988  *
989  * RETURNS
990  *
991  * Time of last message on success, zero on failure.
992  *
993  * CONFORMANCE
994  *
995  * ECMA-234, Win32
996  *  
997  */
998 LONG WINAPI GetMessageTime(void)
999 {
1000     MESSAGEQUEUE *queue;
1001
1002     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return 0;
1003     return queue->GetMessageTimeVal;
1004 }
1005
1006
1007 /***********************************************************************
1008  *           GetMessageExtraInfo   (USER.288) (USER32.271)
1009  */
1010 LONG WINAPI GetMessageExtraInfo(void)
1011 {
1012     MESSAGEQUEUE *queue;
1013
1014     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetFastQueue() ))) return 0;
1015     return queue->GetMessageExtraInfoVal;
1016 }