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