Create an X connection for each thread, and process X events in the
[wine] / windows / queue.c
1 /* * Message queues related functions
2  *
3  * Copyright 1993, 1994 Alexandre Julliard
4  */
5
6 #include <string.h>
7 #include <signal.h>
8 #include <assert.h>
9 #include "windef.h"
10 #include "wingdi.h"
11 #include "winerror.h"
12 #include "wine/winbase16.h"
13 #include "wine/winuser16.h"
14 #include "queue.h"
15 #include "win.h"
16 #include "user.h"
17 #include "hook.h"
18 #include "thread.h"
19 #include "debugtools.h"
20 #include "server.h"
21 #include "spy.h"
22
23 DECLARE_DEBUG_CHANNEL(msg);
24 DECLARE_DEBUG_CHANNEL(sendmsg);
25
26 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
27
28 static HQUEUE16 hFirstQueue = 0;
29 static HQUEUE16 hExitingQueue = 0;
30 static HQUEUE16 hmemSysMsgQueue = 0;
31 static MESSAGEQUEUE *sysMsgQueue = NULL;
32 static PERQUEUEDATA *pQDataWin16 = NULL;  /* Global perQData for Win16 tasks */
33
34 static MESSAGEQUEUE *pMouseQueue = NULL;  /* Queue for last mouse message */
35 static MESSAGEQUEUE *pKbdQueue = NULL;    /* Queue for last kbd message */
36
37 HQUEUE16 hCursorQueue = 0;
38 HQUEUE16 hActiveQueue = 0;
39
40
41 /***********************************************************************
42  *           PERQDATA_CreateInstance
43  *
44  * Creates an instance of a reference counted PERQUEUEDATA element
45  * for the message queue. perQData is stored globally for 16 bit tasks.
46  *
47  * Note: We don't implement perQdata exactly the same way Windows does.
48  * Each perQData element is reference counted since it may be potentially
49  * shared by multiple message Queues (via AttachThreadInput).
50  * We only store the current values for Active, Capture and focus windows
51  * currently.
52  */
53 PERQUEUEDATA * PERQDATA_CreateInstance( )
54 {
55     PERQUEUEDATA *pQData;
56     
57     BOOL16 bIsWin16 = 0;
58     
59     TRACE_(msg)("()\n");
60
61     /* Share a single instance of perQData for all 16 bit tasks */
62     if ( ( bIsWin16 = THREAD_IsWin16( NtCurrentTeb() ) ) )
63     {
64         /* If previously allocated, just bump up ref count */
65         if ( pQDataWin16 )
66         {
67             PERQDATA_Addref( pQDataWin16 );
68             return pQDataWin16;
69         }
70     }
71
72     /* Allocate PERQUEUEDATA from the system heap */
73     if (!( pQData = (PERQUEUEDATA *) HeapAlloc( GetProcessHeap(), 0,
74                                                     sizeof(PERQUEUEDATA) ) ))
75         return 0;
76
77     /* Initialize */
78     pQData->hWndCapture = pQData->hWndFocus = pQData->hWndActive = 0;
79     pQData->ulRefCount = 1;
80     pQData->nCaptureHT = HTCLIENT;
81
82     /* Note: We have an independent critical section for the per queue data
83      * since this may be shared by different threads. see AttachThreadInput()
84      */
85     InitializeCriticalSection( &pQData->cSection );
86     /* FIXME: not all per queue data critical sections should be global */
87     MakeCriticalSectionGlobal( &pQData->cSection );
88
89     /* Save perQData globally for 16 bit tasks */
90     if ( bIsWin16 )
91         pQDataWin16 = pQData;
92         
93     return pQData;
94 }
95
96
97 /***********************************************************************
98  *           PERQDATA_Addref
99  *
100  * Increment reference count for the PERQUEUEDATA instance
101  * Returns reference count for debugging purposes
102  */
103 ULONG PERQDATA_Addref( PERQUEUEDATA *pQData )
104 {
105     assert(pQData != 0 );
106     TRACE_(msg)("(): current refcount %lu ...\n", pQData->ulRefCount);
107
108     EnterCriticalSection( &pQData->cSection );
109     ++pQData->ulRefCount;
110     LeaveCriticalSection( &pQData->cSection );
111
112     return pQData->ulRefCount;
113 }
114
115
116 /***********************************************************************
117  *           PERQDATA_Release
118  *
119  * Release a reference to a PERQUEUEDATA instance.
120  * Destroy the instance if no more references exist
121  * Returns reference count for debugging purposes
122  */
123 ULONG PERQDATA_Release( PERQUEUEDATA *pQData )
124 {
125     assert(pQData != 0 );
126     TRACE_(msg)("(): current refcount %lu ...\n",
127           (LONG)pQData->ulRefCount );
128
129     EnterCriticalSection( &pQData->cSection );
130     if ( --pQData->ulRefCount == 0 )
131     {
132         LeaveCriticalSection( &pQData->cSection );
133         DeleteCriticalSection( &pQData->cSection );
134
135         TRACE_(msg)("(): deleting PERQUEUEDATA instance ...\n" );
136
137         /* Deleting our global 16 bit perQData? */
138         if ( pQData == pQDataWin16 )
139             pQDataWin16 = 0;
140             
141         /* Free the PERQUEUEDATA instance */
142         HeapFree( GetProcessHeap(), 0, pQData );
143
144         return 0;
145     }
146     LeaveCriticalSection( &pQData->cSection );
147
148     return pQData->ulRefCount;
149 }
150
151
152 /***********************************************************************
153  *           PERQDATA_GetFocusWnd
154  *
155  * Get the focus hwnd member in a threadsafe manner
156  */
157 HWND PERQDATA_GetFocusWnd( PERQUEUEDATA *pQData )
158 {
159     HWND hWndFocus;
160     assert(pQData != 0 );
161
162     EnterCriticalSection( &pQData->cSection );
163     hWndFocus = pQData->hWndFocus;
164     LeaveCriticalSection( &pQData->cSection );
165
166     return hWndFocus;
167 }
168
169
170 /***********************************************************************
171  *           PERQDATA_SetFocusWnd
172  *
173  * Set the focus hwnd member in a threadsafe manner
174  */
175 HWND PERQDATA_SetFocusWnd( PERQUEUEDATA *pQData, HWND hWndFocus )
176 {
177     HWND hWndFocusPrv;
178     assert(pQData != 0 );
179
180     EnterCriticalSection( &pQData->cSection );
181     hWndFocusPrv = pQData->hWndFocus;
182     pQData->hWndFocus = hWndFocus;
183     LeaveCriticalSection( &pQData->cSection );
184
185     return hWndFocusPrv;
186 }
187
188
189 /***********************************************************************
190  *           PERQDATA_GetActiveWnd
191  *
192  * Get the active hwnd member in a threadsafe manner
193  */
194 HWND PERQDATA_GetActiveWnd( PERQUEUEDATA *pQData )
195 {
196     HWND hWndActive;
197     assert(pQData != 0 );
198
199     EnterCriticalSection( &pQData->cSection );
200     hWndActive = pQData->hWndActive;
201     LeaveCriticalSection( &pQData->cSection );
202
203     return hWndActive;
204 }
205
206
207 /***********************************************************************
208  *           PERQDATA_SetActiveWnd
209  *
210  * Set the active focus hwnd member in a threadsafe manner
211  */
212 HWND PERQDATA_SetActiveWnd( PERQUEUEDATA *pQData, HWND hWndActive )
213 {
214     HWND hWndActivePrv;
215     assert(pQData != 0 );
216
217     EnterCriticalSection( &pQData->cSection );
218     hWndActivePrv = pQData->hWndActive;
219     pQData->hWndActive = hWndActive;
220     LeaveCriticalSection( &pQData->cSection );
221
222     return hWndActivePrv;
223 }
224
225
226 /***********************************************************************
227  *           PERQDATA_GetCaptureWnd
228  *
229  * Get the capture hwnd member in a threadsafe manner
230  */
231 HWND PERQDATA_GetCaptureWnd( PERQUEUEDATA *pQData )
232 {
233     HWND hWndCapture;
234     assert(pQData != 0 );
235
236     EnterCriticalSection( &pQData->cSection );
237     hWndCapture = pQData->hWndCapture;
238     LeaveCriticalSection( &pQData->cSection );
239
240     return hWndCapture;
241 }
242
243
244 /***********************************************************************
245  *           PERQDATA_SetCaptureWnd
246  *
247  * Set the capture hwnd member in a threadsafe manner
248  */
249 HWND PERQDATA_SetCaptureWnd( PERQUEUEDATA *pQData, HWND hWndCapture )
250 {
251     HWND hWndCapturePrv;
252     assert(pQData != 0 );
253
254     EnterCriticalSection( &pQData->cSection );
255     hWndCapturePrv = pQData->hWndCapture;
256     pQData->hWndCapture = hWndCapture;
257     LeaveCriticalSection( &pQData->cSection );
258
259     return hWndCapturePrv;
260 }
261
262
263 /***********************************************************************
264  *           PERQDATA_GetCaptureInfo
265  *
266  * Get the capture info member in a threadsafe manner
267  */
268 INT16 PERQDATA_GetCaptureInfo( PERQUEUEDATA *pQData )
269 {
270     INT16 nCaptureHT;
271     assert(pQData != 0 );
272
273     EnterCriticalSection( &pQData->cSection );
274     nCaptureHT = pQData->nCaptureHT;
275     LeaveCriticalSection( &pQData->cSection );
276
277     return nCaptureHT;
278 }
279
280
281 /***********************************************************************
282  *           PERQDATA_SetCaptureInfo
283  *
284  * Set the capture info member in a threadsafe manner
285  */
286 INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT )
287 {
288     INT16 nCaptureHTPrv;
289     assert(pQData != 0 );
290
291     EnterCriticalSection( &pQData->cSection );
292     nCaptureHTPrv = pQData->nCaptureHT;
293     pQData->nCaptureHT = nCaptureHT;
294     LeaveCriticalSection( &pQData->cSection );
295
296     return nCaptureHTPrv;
297 }
298
299
300 /***********************************************************************
301  *           QUEUE_Lock
302  *
303  * Function for getting a 32 bit pointer on queue structure. For thread
304  * safeness programmers should use this function instead of GlobalLock to
305  * retrieve a pointer on the structure. QUEUE_Unlock should also be called
306  * when access to the queue structure is not required anymore.
307  */
308 MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue )
309 {
310     MESSAGEQUEUE *queue;
311
312     HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
313     queue = GlobalLock16( hQueue );
314     if ( !queue || (queue->magic != QUEUE_MAGIC) )
315     {
316         HeapUnlock( GetProcessHeap() );
317         return NULL;
318     }
319
320     queue->lockCount++;
321     HeapUnlock( GetProcessHeap() );
322     return queue;
323 }
324
325
326 /***********************************************************************
327  *           QUEUE_Unlock
328  *
329  * Use with QUEUE_Lock to get a thread safe access to message queue
330  * structure
331  */
332 void QUEUE_Unlock( MESSAGEQUEUE *queue )
333 {
334     if (queue)
335     {
336         HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
337
338         if ( --queue->lockCount == 0 )
339         {
340             DeleteCriticalSection ( &queue->cSection );
341             if (queue->server_queue)
342                 CloseHandle( queue->server_queue );
343             GlobalFree16( queue->self );
344         }
345     
346         HeapUnlock( GetProcessHeap() );
347     }
348 }
349
350
351 /***********************************************************************
352  *           QUEUE_DumpQueue
353  */
354 void QUEUE_DumpQueue( HQUEUE16 hQueue )
355 {
356     MESSAGEQUEUE *pq; 
357
358     if (!(pq = QUEUE_Lock( hQueue )) )
359     {
360         WARN_(msg)("%04x is not a queue handle\n", hQueue );
361         return;
362     }
363
364     EnterCriticalSection( &pq->cSection );
365
366     DPRINTF( "next: %12.4x  Intertask SendMessage:\n"
367              "thread: %10p  ----------------------\n"
368              "firstMsg: %8p   smWaiting:     %10p\n"
369              "lastMsg:  %8p   smPending:     %10p\n"
370              "msgCount: %8.4x   smProcessing:  %10p\n"
371              "lockCount: %7.4x\n"
372              "paints: %10.4x\n"
373              "timers: %10.4x\n"
374              "wakeBits: %8.4x\n"
375              "wakeMask: %8.4x\n"
376              "hCurHook: %8.4x\n",
377              pq->next, pq->teb, pq->firstMsg, pq->smWaiting, pq->lastMsg,
378              pq->smPending, pq->msgCount, pq->smProcessing,
379              (unsigned)pq->lockCount, pq->wPaintCount, pq->wTimerCount,
380              pq->wakeBits, pq->wakeMask, pq->hCurHook);
381
382     LeaveCriticalSection( &pq->cSection );
383
384     QUEUE_Unlock( pq );
385 }
386
387
388 /***********************************************************************
389  *           QUEUE_WalkQueues
390  */
391 void QUEUE_WalkQueues(void)
392 {
393     char module[10];
394     HQUEUE16 hQueue = hFirstQueue;
395
396     DPRINTF( "Queue Msgs Thread   Task Module\n" );
397     while (hQueue)
398     {
399         MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
400         if (!queue)
401         {
402             WARN_(msg)("Bad queue handle %04x\n", hQueue );
403             return;
404         }
405         if (!GetModuleName16( queue->teb->htask16, module, sizeof(module )))
406             strcpy( module, "???" );
407         DPRINTF( "%04x %4d %p %04x %s\n", hQueue,queue->msgCount,
408                  queue->teb, queue->teb->htask16, module );
409         hQueue = queue->next;
410         QUEUE_Unlock( queue );
411     }
412     DPRINTF( "\n" );
413 }
414
415
416 /***********************************************************************
417  *           QUEUE_IsExitingQueue
418  */
419 BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue )
420 {
421     return (hExitingQueue && (hQueue == hExitingQueue));
422 }
423
424
425 /***********************************************************************
426  *           QUEUE_SetExitingQueue
427  */
428 void QUEUE_SetExitingQueue( HQUEUE16 hQueue )
429 {
430     hExitingQueue = hQueue;
431 }
432
433
434 /***********************************************************************
435  *           QUEUE_CreateMsgQueue
436  *
437  * Creates a message queue. Doesn't link it into queue list!
438  */
439 static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
440 {
441     HQUEUE16 hQueue;
442     HANDLE handle;
443     MESSAGEQUEUE * msgQueue;
444
445     TRACE_(msg)("(): Creating message queue...\n");
446
447     if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT,
448                                   sizeof(MESSAGEQUEUE) )))
449         return 0;
450
451     msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
452     if ( !msgQueue )
453         return 0;
454
455     SERVER_START_REQ( get_msg_queue )
456     {
457         SERVER_CALL_ERR();
458         handle = req->handle;
459     }
460     SERVER_END_REQ;
461     if (!handle)
462     {
463         ERR_(msg)("Cannot get thread queue");
464         GlobalFree16( hQueue );
465         return 0;
466     }
467     msgQueue->server_queue = handle;
468     msgQueue->server_queue = ConvertToGlobalHandle( msgQueue->server_queue );
469
470     msgQueue->self        = hQueue;
471     msgQueue->wakeBits    = msgQueue->changeBits = 0;
472     
473     InitializeCriticalSection( &msgQueue->cSection );
474     MakeCriticalSectionGlobal( &msgQueue->cSection );
475
476     msgQueue->lockCount = 1;
477     msgQueue->magic = QUEUE_MAGIC;
478     
479     /* Create and initialize our per queue data */
480     msgQueue->pQData = bCreatePerQData ? PERQDATA_CreateInstance() : NULL;
481     
482     return hQueue;
483 }
484
485
486 /***********************************************************************
487  *           QUEUE_FlushMessage
488  * 
489  * Try to reply to all pending sent messages on exit.
490  */
491 static void QUEUE_FlushMessages( MESSAGEQUEUE *queue )
492 {
493     SMSG *smsg;
494     MESSAGEQUEUE *senderQ = 0;
495
496     if( queue )
497     {
498         EnterCriticalSection( &queue->cSection );
499
500         /* empty the list of pending SendMessage waiting to be received */
501         while (queue->smPending)
502         {
503             smsg = QUEUE_RemoveSMSG( queue, SM_PENDING_LIST, 0);
504
505             senderQ = QUEUE_Lock( smsg->hSrcQueue );
506             if ( !senderQ )
507                 continue;
508
509             /* return 0, to unblock other thread */
510             smsg->lResult = 0;
511             smsg->flags |= SMSG_HAVE_RESULT;
512             QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
513             
514             QUEUE_Unlock( senderQ );
515         }
516
517         QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
518         
519         LeaveCriticalSection( &queue->cSection );
520     }
521 }
522
523
524 /***********************************************************************
525  *           QUEUE_DeleteMsgQueue
526  *
527  * Unlinks and deletes a message queue.
528  *
529  * Note: We need to mask asynchronous events to make sure PostMessage works
530  * even in the signal handler.
531  */
532 BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
533 {
534     MESSAGEQUEUE * msgQueue = QUEUE_Lock(hQueue);
535     HQUEUE16 *pPrev;
536
537     TRACE_(msg)("(): Deleting message queue %04x\n", hQueue);
538
539     if (!hQueue || !msgQueue)
540     {
541         ERR_(msg)("invalid argument.\n");
542         return 0;
543     }
544
545     msgQueue->magic = 0;
546     
547     if( hCursorQueue == hQueue ) hCursorQueue = 0;
548     if( hActiveQueue == hQueue ) hActiveQueue = 0;
549
550     /* flush sent messages */
551     QUEUE_FlushMessages( msgQueue );
552
553     HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
554
555     /* Release per queue data if present */
556     if ( msgQueue->pQData )
557     {
558         PERQDATA_Release( msgQueue->pQData );
559         msgQueue->pQData = 0;
560     }
561     
562     /* remove the message queue from the global link list */
563     pPrev = &hFirstQueue;
564     while (*pPrev && (*pPrev != hQueue))
565     {
566         MESSAGEQUEUE *msgQ = (MESSAGEQUEUE*)GlobalLock16(*pPrev);
567
568         /* sanity check */
569         if ( !msgQ || (msgQ->magic != QUEUE_MAGIC) )
570         {
571             /* HQUEUE link list is corrupted, try to exit gracefully */
572             ERR_(msg)("HQUEUE link list corrupted!\n");
573             pPrev = 0;
574             break;
575         }
576         pPrev = &msgQ->next;
577     }
578     if (pPrev && *pPrev) *pPrev = msgQueue->next;
579     msgQueue->self = 0;
580
581     HeapUnlock( GetProcessHeap() );
582
583     /* free up resource used by MESSAGEQUEUE structure */
584     msgQueue->lockCount--;
585     QUEUE_Unlock( msgQueue );
586     
587     return 1;
588 }
589
590
591 /***********************************************************************
592  *           QUEUE_CreateSysMsgQueue
593  *
594  * Create the system message queue, and set the double-click speed.
595  * Must be called only once.
596  */
597 BOOL QUEUE_CreateSysMsgQueue( int size )
598 {
599     /* Note: We dont need perQ data for the system message queue */
600     if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( FALSE )))
601         return FALSE;
602     FarSetOwner16( hmemSysMsgQueue, 0 );
603     sysMsgQueue = (MESSAGEQUEUE *) GlobalLock16( hmemSysMsgQueue );
604     return TRUE;
605 }
606
607
608 /***********************************************************************
609  *           QUEUE_GetSysQueue
610  */
611 MESSAGEQUEUE *QUEUE_GetSysQueue(void)
612 {
613     return sysMsgQueue;
614 }
615
616
617 /***********************************************************************
618  *           QUEUE_SetWakeBit
619  *
620  * See "Windows Internals", p.449
621  */
622 static BOOL QUEUE_TrySetWakeBit( MESSAGEQUEUE *queue, WORD bit, BOOL always )
623 {
624     BOOL wake = FALSE;
625
626     EnterCriticalSection( &queue->cSection );
627
628     TRACE_(msg)("queue = %04x (wm=%04x), bit = %04x, always = %d\n", 
629                         queue->self, queue->wakeMask, bit, always );
630
631     if ((queue->wakeMask & bit) || always)
632     {
633         if (bit & QS_MOUSE) pMouseQueue = queue;
634         if (bit & QS_KEY) pKbdQueue = queue;
635         queue->changeBits |= bit;
636         queue->wakeBits   |= bit;
637     }
638     if (queue->wakeMask & bit)
639     {
640         queue->wakeMask = 0;
641         wake = TRUE;
642     }
643
644     LeaveCriticalSection( &queue->cSection );
645
646     if ( wake )
647     {
648         /* Wake up thread waiting for message */
649         SERVER_START_REQ( wake_queue )
650         {
651             req->handle = queue->server_queue;
652             req->bits   = bit;
653             SERVER_CALL();
654         }
655         SERVER_END_REQ;
656     }
657
658     return wake;
659 }
660 void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
661 {
662     QUEUE_TrySetWakeBit( queue, bit, TRUE );
663 }
664
665
666 /***********************************************************************
667  *           QUEUE_ClearWakeBit
668  */
669 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
670 {
671     EnterCriticalSection( &queue->cSection );
672     queue->changeBits &= ~bit;
673     queue->wakeBits   &= ~bit;
674     LeaveCriticalSection( &queue->cSection );
675 }
676
677 /***********************************************************************
678  *           QUEUE_TestWakeBit
679  */
680 WORD QUEUE_TestWakeBit( MESSAGEQUEUE *queue, WORD bit )
681 {
682     WORD ret;
683     EnterCriticalSection( &queue->cSection );
684     ret = queue->wakeBits & bit;
685     LeaveCriticalSection( &queue->cSection );
686     return ret;
687 }
688
689
690 /***********************************************************************
691  *           QUEUE_WaitBits
692  *
693  * See "Windows Internals", p.447
694  *
695  * return values:
696  *    0 if exit with timeout
697  *    1 otherwise
698  */
699 int QUEUE_WaitBits( WORD bits, DWORD timeout )
700 {
701     MESSAGEQUEUE *queue;
702     HQUEUE16 hQueue;
703
704     TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits);
705
706     hQueue = GetFastQueue16();
707     if (!(queue = QUEUE_Lock( hQueue ))) return 0;
708     
709     for (;;)
710     {
711         DWORD dwlc;
712
713         EnterCriticalSection( &queue->cSection );
714
715         if (queue->changeBits & bits)
716         {
717             /* One of the bits is set; we can return */
718             queue->wakeMask = 0;
719
720             LeaveCriticalSection( &queue->cSection );
721             QUEUE_Unlock( queue );
722             return 1;
723         }
724         if (queue->wakeBits & QS_SENDMESSAGE)
725         {
726             /* Process the sent message immediately */
727             queue->wakeMask = 0;
728
729             LeaveCriticalSection( &queue->cSection );
730             QUEUE_ReceiveMessage( queue );
731             continue;                           /* nested sm crux */
732         }
733
734         queue->wakeMask = bits | QS_SENDMESSAGE;
735         TRACE_(msg)("%04x: wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
736         LeaveCriticalSection( &queue->cSection );
737
738         ReleaseThunkLock( &dwlc );
739         if (dwlc) TRACE_(msg)("had win16 lock\n");
740
741         if (USER_Driver.pMsgWaitForMultipleObjects)
742             USER_Driver.pMsgWaitForMultipleObjects( 1, &queue->server_queue, FALSE, timeout );
743         else
744             WaitForSingleObject( queue->server_queue, timeout );
745         if (dwlc) RestoreThunkLock( dwlc );
746     }
747 }
748
749
750 /***********************************************************************
751  *           QUEUE_AddSMSG
752  *
753  * This routine is called when a SMSG need to be added to one of the three
754  * SM list.  (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST)
755  */
756 BOOL QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
757 {
758     TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
759           smsg, SPY_GetMsgName(smsg->msg));
760     
761     switch (list)
762     {
763         case SM_PROCESSING_LIST:
764             /* don't need to be thread safe, only accessed by the
765              thread associated with the sender queue */
766             smsg->nextProcessing = queue->smProcessing;
767             queue->smProcessing = smsg;
768             break;
769             
770         case SM_WAITING_LIST:
771             /* don't need to be thread safe, only accessed by the
772              thread associated with the receiver queue */
773             smsg->nextWaiting = queue->smWaiting;
774             queue->smWaiting = smsg;
775             break;
776             
777         case SM_PENDING_LIST:
778         {
779             /* make it thread safe, could be accessed by the sender and
780              receiver thread */
781             SMSG **prev;
782
783             EnterCriticalSection( &queue->cSection );
784             smsg->nextPending = NULL;
785             prev = &queue->smPending;
786             while ( *prev )
787                 prev = &(*prev)->nextPending;
788             *prev = smsg;
789             LeaveCriticalSection( &queue->cSection );
790
791             QUEUE_SetWakeBit( queue, QS_SENDMESSAGE );
792             break;
793         }
794
795         default:
796             ERR_(sendmsg)("Invalid list: %d", list);
797             break;
798     }
799
800     return TRUE;
801 }
802
803
804 /***********************************************************************
805  *           QUEUE_RemoveSMSG
806  *
807  * This routine is called when a SMSG needs to be removed from one of the three
808  * SM lists (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST).
809  * If smsg == 0, remove the first smsg from the specified list
810  */
811 SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg )
812 {
813
814     switch (list)
815     {
816         case SM_PROCESSING_LIST:
817             /* don't need to be thread safe, only accessed by the
818              thread associated with the sender queue */
819
820             /* if smsg is equal to null, it means the first in the list */
821             if (!smsg)
822                 smsg = queue->smProcessing;
823
824             TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
825                   smsg, SPY_GetMsgName(smsg->msg));
826             /* In fact SM_PROCESSING_LIST is a stack, and smsg
827              should be always at the top of the list */
828             if ( (smsg != queue->smProcessing) || !queue->smProcessing )
829             {
830                 ERR_(sendmsg)("smsg not at the top of Processing list, smsg=0x%p queue=0x%p\n", smsg, queue);
831                 return 0;
832             }
833             else
834             {
835                 queue->smProcessing = smsg->nextProcessing;
836                 smsg->nextProcessing = 0;
837             }
838             return smsg;
839
840         case SM_WAITING_LIST:
841             /* don't need to be thread safe, only accessed by the
842              thread associated with the receiver queue */
843
844             /* if smsg is equal to null, it means the first in the list */
845             if (!smsg)
846                 smsg = queue->smWaiting;
847             
848             TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
849                   smsg, SPY_GetMsgName(smsg->msg));
850             /* In fact SM_WAITING_LIST is a stack, and smsg
851              should be always at the top of the list */
852             if ( (smsg != queue->smWaiting) || !queue->smWaiting )
853             {
854                 ERR_(sendmsg)("smsg not at the top of Waiting list, smsg=0x%p queue=0x%p\n", smsg, queue);
855                 return 0;
856             }
857             else
858             {
859                 queue->smWaiting = smsg->nextWaiting;
860                 smsg->nextWaiting = 0;
861             }
862             return smsg;
863
864         case SM_PENDING_LIST:
865             /* make it thread safe, could be accessed by the sender and
866              receiver thread */
867             EnterCriticalSection( &queue->cSection );
868     
869             if (!smsg)
870                 smsg = queue->smPending;
871             if ( (smsg != queue->smPending) || !queue->smPending )
872             {
873                 ERR_(sendmsg)("should always remove the top one in Pending list, smsg=0x%p queue=0x%p\n", smsg, queue);
874                 LeaveCriticalSection( &queue->cSection );
875                 return 0;
876             }
877             
878             TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list,
879                   smsg, SPY_GetMsgName(smsg->msg));
880
881             queue->smPending = smsg->nextPending;
882             smsg->nextPending = 0;
883
884             /* if no more SMSG in Pending list, clear QS_SENDMESSAGE flag */
885             if (!queue->smPending)
886                 QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE );
887             
888             LeaveCriticalSection( &queue->cSection );
889             return smsg;
890
891         default:
892             ERR_(sendmsg)("Invalid list: %d\n", list);
893             break;
894     }
895
896     return 0;
897 }
898
899
900 /***********************************************************************
901  *           QUEUE_ReceiveMessage
902  * 
903  * This routine is called to check whether a sent message is waiting 
904  * for the queue.  If so, it is received and processed.
905  */
906 BOOL QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
907 {
908     LRESULT       result = 0;
909     SMSG          *smsg;
910     MESSAGEQUEUE  *senderQ;
911
912     EnterCriticalSection( &queue->cSection );
913     if ( !((queue->wakeBits & QS_SENDMESSAGE) && queue->smPending) )
914     {
915         LeaveCriticalSection( &queue->cSection );
916         return FALSE;
917     }
918     LeaveCriticalSection( &queue->cSection );
919
920     TRACE_(sendmsg)("queue %04x\n", queue->self );
921
922     /* remove smsg on the top of the pending list and put it in the processing list */
923     smsg = QUEUE_RemoveSMSG(queue, SM_PENDING_LIST, 0);
924     QUEUE_AddSMSG(queue, SM_WAITING_LIST, smsg);
925
926     TRACE_(sendmsg)("RM: %s [%04x] (%04x -> %04x)\n",
927             SPY_GetMsgName(smsg->msg), smsg->msg, smsg->hSrcQueue, smsg->hDstQueue );
928
929     if (IsWindow( smsg->hWnd ))
930     {
931         WND *wndPtr = WIN_FindWndPtr( smsg->hWnd );
932         DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
933
934         /* use sender queue extra info value while calling the window proc */
935         senderQ = QUEUE_Lock( smsg->hSrcQueue );
936         if (senderQ)
937         {
938             queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
939             QUEUE_Unlock( senderQ );
940         }
941
942         /* call the right version of CallWindowProcXX */
943         if (smsg->flags & SMSG_WIN32)
944         {
945             TRACE_(sendmsg)("\trcm: msg is Win32\n" );
946             if (smsg->flags & SMSG_UNICODE)
947                 result = CallWindowProcW( wndPtr->winproc,
948                                             smsg->hWnd, smsg->msg,
949                                             smsg->wParam, smsg->lParam );
950             else
951                 result = CallWindowProcA( wndPtr->winproc,
952                                             smsg->hWnd, smsg->msg,
953                                             smsg->wParam, smsg->lParam );
954         }
955         else  /* Win16 message */
956             result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
957                                        (HWND16) smsg->hWnd,
958                                        (UINT16) smsg->msg,
959                                        LOWORD (smsg->wParam),
960                                        smsg->lParam );
961
962         queue->GetMessageExtraInfoVal = extraInfo;  /* Restore extra info */
963         WIN_ReleaseWndPtr(wndPtr);
964         TRACE_(sendmsg)("result =  %08x\n", (unsigned)result );
965     }
966     else WARN_(sendmsg)("\trcm: bad hWnd\n");
967
968     
969     /* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not
970        an early reply */
971     smsg->flags |= SMSG_SENDING_REPLY;
972     ReplyMessage( result );
973
974     TRACE_(sendmsg)("done!\n" );
975     return TRUE;
976 }
977
978
979
980 /***********************************************************************
981  *           QUEUE_AddMsg
982  *
983  * Add a message to the queue. Return FALSE if queue is full.
984  */
985 BOOL QUEUE_AddMsg( HQUEUE16 hQueue, int type, MSG *msg, DWORD extraInfo )
986 {
987     MESSAGEQUEUE *msgQueue;
988     QMSG         *qmsg;
989
990
991     if (!(msgQueue = QUEUE_Lock( hQueue ))) return FALSE;
992
993     /* allocate new message in global heap for now */
994     if (!(qmsg = (QMSG *) HeapAlloc( GetProcessHeap(), 0, sizeof(QMSG) ) ))
995     {
996         QUEUE_Unlock( msgQueue );
997         return 0;
998     }
999
1000     EnterCriticalSection( &msgQueue->cSection );
1001
1002       /* Store message */
1003     qmsg->type = type;
1004     qmsg->msg = *msg;
1005     qmsg->extraInfo = extraInfo;
1006
1007     /* insert the message in the link list */
1008     qmsg->nextMsg = 0;
1009     qmsg->prevMsg = msgQueue->lastMsg;
1010
1011     if (msgQueue->lastMsg)
1012         msgQueue->lastMsg->nextMsg = qmsg;
1013
1014     /* update first and last anchor in message queue */
1015     msgQueue->lastMsg = qmsg;
1016     if (!msgQueue->firstMsg)
1017         msgQueue->firstMsg = qmsg;
1018     
1019     msgQueue->msgCount++;
1020
1021     LeaveCriticalSection( &msgQueue->cSection );
1022
1023     QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
1024     QUEUE_Unlock( msgQueue );
1025     
1026     return TRUE;
1027 }
1028
1029
1030
1031 /***********************************************************************
1032  *           QUEUE_FindMsg
1033  *
1034  * Find a message matching the given parameters. Return -1 if none available.
1035  */
1036 QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last )
1037 {
1038     QMSG* qmsg;
1039
1040     EnterCriticalSection( &msgQueue->cSection );
1041
1042     if (!msgQueue->msgCount)
1043         qmsg = 0;
1044     else if (!hwnd && !first && !last)
1045         qmsg = msgQueue->firstMsg;
1046     else
1047     {
1048         /* look in linked list for message matching first and last criteria */
1049         for (qmsg = msgQueue->firstMsg; qmsg; qmsg = qmsg->nextMsg)
1050         {
1051             MSG *msg = &(qmsg->msg);
1052
1053             if (!hwnd || (msg->hwnd == hwnd))
1054             {
1055                 if (!first && !last)
1056                     break;   /* found it */
1057                 
1058                 if ((msg->message >= first) && (!last || (msg->message <= last)))
1059                     break;   /* found it */
1060             }
1061         }
1062     }
1063     
1064     LeaveCriticalSection( &msgQueue->cSection );
1065
1066     return qmsg;
1067 }
1068
1069
1070
1071 /***********************************************************************
1072  *           QUEUE_RemoveMsg
1073  *
1074  * Remove a message from the queue (pos must be a valid position).
1075  */
1076 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg )
1077 {
1078     EnterCriticalSection( &msgQueue->cSection );
1079
1080     /* set the linked list */
1081     if (qmsg->prevMsg)
1082         qmsg->prevMsg->nextMsg = qmsg->nextMsg;
1083
1084     if (qmsg->nextMsg)
1085         qmsg->nextMsg->prevMsg = qmsg->prevMsg;
1086
1087     if (msgQueue->firstMsg == qmsg)
1088         msgQueue->firstMsg = qmsg->nextMsg;
1089
1090     if (msgQueue->lastMsg == qmsg)
1091         msgQueue->lastMsg = qmsg->prevMsg;
1092
1093     /* deallocate the memory for the message */
1094     HeapFree( GetProcessHeap(), 0, qmsg );
1095     
1096     msgQueue->msgCount--;
1097     if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
1098
1099     LeaveCriticalSection( &msgQueue->cSection );
1100 }
1101
1102
1103 #if 0
1104 /***********************************************************************
1105  *           QUEUE_WakeSomeone
1106  *
1107  * Wake a queue upon reception of a hardware event.
1108  */
1109 static void QUEUE_WakeSomeone( UINT message )
1110 {
1111     WND*          wndPtr = NULL;
1112     WORD          wakeBit;
1113     HWND hwnd;
1114     HQUEUE16     hQueue = 0;
1115     MESSAGEQUEUE *queue = NULL;
1116
1117     if (hCursorQueue)
1118         hQueue = hCursorQueue;
1119
1120     if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
1121     {
1122        wakeBit = QS_KEY;
1123        if( hActiveQueue )
1124            hQueue = hActiveQueue;
1125     }
1126     else 
1127     {
1128        wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
1129        if( (hwnd = GetCapture()) )
1130          if( (wndPtr = WIN_FindWndPtr( hwnd )) ) 
1131            {
1132                hQueue = wndPtr->hmemTaskQ;
1133                WIN_ReleaseWndPtr(wndPtr);
1134            }
1135     }
1136
1137     if( (hwnd = GetSysModalWindow16()) )
1138     {
1139       if( (wndPtr = WIN_FindWndPtr( hwnd )) )
1140         {
1141             hQueue = wndPtr->hmemTaskQ;
1142             WIN_ReleaseWndPtr(wndPtr);
1143         }
1144     }
1145
1146     if (hQueue)
1147     {
1148         queue = QUEUE_Lock( hQueue );
1149         QUEUE_SetWakeBit( queue, wakeBit );
1150         QUEUE_Unlock( queue );
1151         return;
1152     }
1153
1154     /* Search for someone to wake */
1155     hQueue = hFirstQueue;
1156     while ( (queue = QUEUE_Lock( hQueue )) )
1157     {
1158         if (QUEUE_TrySetWakeBit( queue, wakeBit, FALSE )) 
1159         {
1160             QUEUE_Unlock( queue );
1161             return;
1162         }
1163         
1164         hQueue = queue->next; 
1165         QUEUE_Unlock( queue );
1166     }
1167
1168     WARN_(msg)("couldn't find queue\n"); 
1169 }
1170 #endif
1171
1172
1173 /***********************************************************************
1174  *           hardware_event
1175  *
1176  * Add an event to the system message queue.
1177  * Note: the position is relative to the desktop window.
1178  */
1179 void hardware_event( UINT message, WPARAM wParam, LPARAM lParam,
1180                      int xPos, int yPos, DWORD time, DWORD extraInfo )
1181 {
1182     MSG *msg;
1183     QMSG  *qmsg;
1184     MESSAGEQUEUE *queue;
1185     int  mergeMsg = 0;
1186
1187     if (!sysMsgQueue) return;
1188
1189     EnterCriticalSection( &sysMsgQueue->cSection );
1190
1191     /* Merge with previous event if possible */
1192     qmsg = sysMsgQueue->lastMsg;
1193
1194     if ((message == WM_MOUSEMOVE) && sysMsgQueue->lastMsg)
1195     {
1196         msg = &(sysMsgQueue->lastMsg->msg);
1197         
1198         if ((msg->message == message) && (msg->wParam == wParam))
1199         {
1200             /* Merge events */
1201             qmsg = sysMsgQueue->lastMsg;
1202             mergeMsg = 1;
1203         }
1204     }
1205
1206     if (!mergeMsg)
1207     {
1208         /* Should I limit the number of messages in
1209           the system message queue??? */
1210
1211         /* Don't merge allocate a new msg in the global heap */
1212         
1213         if (!(qmsg = (QMSG *) HeapAlloc( GetProcessHeap(), 0, sizeof(QMSG) ) ))
1214         {
1215             LeaveCriticalSection( &sysMsgQueue->cSection );
1216             return;
1217         }
1218         
1219         /* put message at the end of the linked list */
1220         qmsg->nextMsg = 0;
1221         qmsg->prevMsg = sysMsgQueue->lastMsg;
1222
1223         if (sysMsgQueue->lastMsg)
1224             sysMsgQueue->lastMsg->nextMsg = qmsg;
1225
1226         /* set last and first anchor index in system message queue */
1227         sysMsgQueue->lastMsg = qmsg;
1228         if (!sysMsgQueue->firstMsg)
1229             sysMsgQueue->firstMsg = qmsg;
1230         
1231         sysMsgQueue->msgCount++;
1232     }
1233
1234       /* Store message */
1235     msg = &(qmsg->msg);
1236     msg->hwnd    = 0;
1237     msg->message = message;
1238     msg->wParam  = wParam;
1239     msg->lParam  = lParam;
1240     msg->time    = time;
1241     msg->pt.x    = xPos;
1242     msg->pt.y    = yPos;
1243     qmsg->extraInfo = extraInfo;
1244     qmsg->type      = QMSG_HARDWARE;
1245
1246     LeaveCriticalSection( &sysMsgQueue->cSection );
1247
1248     if ((queue = QUEUE_Lock( GetFastQueue16() )))
1249     {
1250         WORD wakeBit;
1251
1252         if ((message >= WM_KEYFIRST) && (message <= WM_KEYLAST)) wakeBit = QS_KEY;
1253         else wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
1254
1255         QUEUE_SetWakeBit( queue, wakeBit );
1256         QUEUE_Unlock( queue );
1257     }
1258 }
1259
1260
1261 /***********************************************************************
1262  *           QUEUE_GetQueueTask
1263  */
1264 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
1265 {
1266     HTASK16 hTask = 0;
1267     
1268     MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
1269
1270     if (queue)
1271     {
1272         hTask = queue->teb->htask16;
1273         QUEUE_Unlock( queue );
1274     }
1275
1276     return hTask;
1277 }
1278
1279
1280
1281 /***********************************************************************
1282  *           QUEUE_IncPaintCount
1283  */
1284 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
1285 {
1286     MESSAGEQUEUE *queue;
1287
1288     if (!(queue = QUEUE_Lock( hQueue ))) return;
1289     EnterCriticalSection( &queue->cSection );
1290     queue->wPaintCount++;
1291     LeaveCriticalSection( &queue->cSection );
1292     QUEUE_SetWakeBit( queue, QS_PAINT );
1293     QUEUE_Unlock( queue );
1294 }
1295
1296
1297 /***********************************************************************
1298  *           QUEUE_DecPaintCount
1299  */
1300 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
1301 {
1302     MESSAGEQUEUE *queue;
1303
1304     if (!(queue = QUEUE_Lock( hQueue ))) return;
1305     EnterCriticalSection( &queue->cSection );
1306     queue->wPaintCount--;
1307     if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
1308     LeaveCriticalSection( &queue->cSection );
1309     QUEUE_Unlock( queue );
1310 }
1311
1312
1313 /***********************************************************************
1314  *           QUEUE_IncTimerCount
1315  */
1316 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
1317 {
1318     MESSAGEQUEUE *queue;
1319
1320     if (!(queue = QUEUE_Lock( hQueue ))) return;
1321     EnterCriticalSection( &queue->cSection );
1322     queue->wTimerCount++;
1323     LeaveCriticalSection( &queue->cSection );
1324     QUEUE_SetWakeBit( queue, QS_TIMER );
1325     QUEUE_Unlock( queue );
1326 }
1327
1328
1329 /***********************************************************************
1330  *           QUEUE_DecTimerCount
1331  */
1332 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
1333 {
1334     MESSAGEQUEUE *queue;
1335
1336     if (!(queue = QUEUE_Lock( hQueue ))) return;
1337     EnterCriticalSection( &queue->cSection );
1338     queue->wTimerCount--;
1339     if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
1340     LeaveCriticalSection( &queue->cSection );
1341     QUEUE_Unlock( queue );
1342 }
1343
1344
1345 /***********************************************************************
1346  *              PostQuitMessage (USER.6)
1347  */
1348 void WINAPI PostQuitMessage16( INT16 exitCode )
1349 {
1350     PostQuitMessage( exitCode );
1351 }
1352
1353
1354 /***********************************************************************
1355  *              PostQuitMessage (USER32.@)
1356  *
1357  * PostQuitMessage() posts a message to the system requesting an
1358  * application to terminate execution. As a result of this function,
1359  * the WM_QUIT message is posted to the application, and
1360  * PostQuitMessage() returns immediately.  The exitCode parameter
1361  * specifies an application-defined exit code, which appears in the
1362  * _wParam_ parameter of the WM_QUIT message posted to the application.  
1363  *
1364  * CONFORMANCE
1365  *
1366  *  ECMA-234, Win32
1367  */
1368 void WINAPI PostQuitMessage( INT exitCode )
1369 {
1370     MESSAGEQUEUE *queue;
1371
1372     if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return;
1373     EnterCriticalSection( &queue->cSection );
1374     queue->wPostQMsg = TRUE;
1375     queue->wExitCode = (WORD)exitCode;
1376     LeaveCriticalSection( &queue->cSection );
1377     QUEUE_Unlock( queue );
1378 }
1379
1380
1381 /***********************************************************************
1382  *              GetWindowTask (USER.224)
1383  */
1384 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
1385 {
1386     HTASK16 retvalue;
1387     WND *wndPtr = WIN_FindWndPtr( hwnd );
1388
1389     if (!wndPtr) return 0;
1390     retvalue = QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
1391     WIN_ReleaseWndPtr(wndPtr);
1392     return retvalue;
1393 }
1394
1395 /***********************************************************************
1396  *              GetWindowThreadProcessId (USER32.@)
1397  */
1398 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
1399 {
1400     DWORD retvalue;
1401     MESSAGEQUEUE *queue;
1402
1403     WND *wndPtr = WIN_FindWndPtr( hwnd );
1404     if (!wndPtr) return 0;
1405
1406     queue = QUEUE_Lock( wndPtr->hmemTaskQ );
1407     WIN_ReleaseWndPtr(wndPtr);
1408
1409     if (!queue) return 0;
1410
1411     if ( process ) *process = (DWORD)queue->teb->pid;
1412     retvalue = (DWORD)queue->teb->tid;
1413
1414     QUEUE_Unlock( queue );
1415     return retvalue;
1416 }
1417
1418
1419 /***********************************************************************
1420  *              SetMessageQueue (USER.266)
1421  */
1422 BOOL16 WINAPI SetMessageQueue16( INT16 size )
1423 {
1424     return SetMessageQueue( size );
1425 }
1426
1427
1428 /***********************************************************************
1429  *              SetMessageQueue (USER32.@)
1430  */
1431 BOOL WINAPI SetMessageQueue( INT size )
1432 {
1433     /* now obsolete the message queue will be expanded dynamically
1434      as necessary */
1435
1436     /* access the queue to create it if it's not existing */
1437     GetFastQueue16();
1438
1439     return TRUE;
1440 }
1441
1442 /***********************************************************************
1443  *              InitThreadInput (USER.409)
1444  */
1445 HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
1446 {
1447     HQUEUE16 hQueue;
1448     MESSAGEQUEUE *queuePtr;
1449
1450     TEB *teb = NtCurrentTeb();
1451
1452     if (!teb)
1453         return 0;
1454
1455     hQueue = teb->queue;
1456     
1457     if ( !hQueue )
1458     {
1459         /* Create thread message queue */
1460         if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
1461         {
1462             ERR_(msg)("failed!\n");
1463             return FALSE;
1464         }
1465         
1466         /* Link new queue into list */
1467         queuePtr = QUEUE_Lock( hQueue );
1468         queuePtr->teb = NtCurrentTeb();
1469
1470         HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
1471         SetThreadQueue16( 0, hQueue );
1472         teb->queue = hQueue;
1473             
1474         queuePtr->next  = hFirstQueue;
1475         hFirstQueue = hQueue;
1476         HeapUnlock( GetProcessHeap() );
1477         
1478         QUEUE_Unlock( queuePtr );
1479     }
1480
1481     return hQueue;
1482 }
1483
1484 /***********************************************************************
1485  *              GetQueueStatus (USER.334)
1486  */
1487 DWORD WINAPI GetQueueStatus16( UINT16 flags )
1488 {
1489     MESSAGEQUEUE *queue;
1490     DWORD ret;
1491
1492     if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0;
1493     EnterCriticalSection( &queue->cSection );
1494     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1495     queue->changeBits = 0;
1496     LeaveCriticalSection( &queue->cSection );
1497     QUEUE_Unlock( queue );
1498     
1499     return ret & MAKELONG( flags, flags );
1500 }
1501
1502 /***********************************************************************
1503  *              GetQueueStatus (USER32.@)
1504  */
1505 DWORD WINAPI GetQueueStatus( UINT flags )
1506 {
1507     MESSAGEQUEUE *queue;
1508     DWORD ret;
1509
1510     if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0;
1511     EnterCriticalSection( &queue->cSection );
1512     ret = MAKELONG( queue->changeBits, queue->wakeBits );
1513     queue->changeBits = 0;
1514     LeaveCriticalSection( &queue->cSection );
1515     QUEUE_Unlock( queue );
1516     
1517     return ret & MAKELONG( flags, flags );
1518 }
1519
1520
1521 /***********************************************************************
1522  *              GetInputState (USER.335)
1523  */
1524 BOOL16 WINAPI GetInputState16(void)
1525 {
1526     return GetInputState();
1527 }
1528
1529 /***********************************************************************
1530  *              WaitForInputIdle (USER32.@)
1531  */
1532 DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
1533 {
1534     DWORD cur_time, ret;
1535     HANDLE idle_event = -1;
1536
1537     SERVER_START_REQ( wait_input_idle )
1538     {
1539         req->handle = hProcess;
1540         req->timeout = dwTimeOut;
1541         if (!(ret = SERVER_CALL_ERR())) idle_event = req->event;
1542     }
1543     SERVER_END_REQ;
1544     if (ret) return 0xffffffff;  /* error */
1545     if (!idle_event) return 0;  /* no event to wait on */
1546
1547     cur_time = GetTickCount();
1548
1549     TRACE_(msg)("waiting for %x\n", idle_event );
1550     while ( dwTimeOut > GetTickCount() - cur_time || dwTimeOut == INFINITE ) 
1551     {
1552         ret = MsgWaitForMultipleObjects ( 1, &idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE );
1553         if ( ret == ( WAIT_OBJECT_0 + 1 )) 
1554         {
1555             MESSAGEQUEUE * queue;
1556             if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0xFFFFFFFF;
1557             QUEUE_ReceiveMessage ( queue );
1558             QUEUE_Unlock ( queue );
1559             continue; 
1560         }
1561         if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF ) 
1562         {
1563             TRACE_(msg)("timeout or error\n");
1564             return ret;
1565         }
1566         else 
1567         {
1568             TRACE_(msg)("finished\n");
1569             return 0;
1570         }
1571     }
1572
1573     return WAIT_TIMEOUT;
1574 }
1575
1576 /***********************************************************************
1577  *              GetInputState (USER32.@)
1578  */
1579 BOOL WINAPI GetInputState(void)
1580 {
1581     MESSAGEQUEUE *queue;
1582     BOOL ret;
1583
1584     if (!(queue = QUEUE_Lock( GetFastQueue16() )))
1585         return FALSE;
1586     EnterCriticalSection( &queue->cSection );
1587     ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
1588     LeaveCriticalSection( &queue->cSection );
1589     QUEUE_Unlock( queue );
1590
1591     return ret;
1592 }
1593
1594 /***********************************************************************
1595  *              UserYield (USER.332)
1596  *              UserYield16 (USER32.@)
1597  */
1598 void WINAPI UserYield16(void)
1599 {
1600     MESSAGEQUEUE *queue;
1601
1602     /* Handle sent messages */
1603     queue = QUEUE_Lock( GetFastQueue16() );
1604
1605     while ( queue && QUEUE_ReceiveMessage( queue ) )
1606         ;
1607
1608     QUEUE_Unlock( queue );
1609
1610     /* Yield */
1611     OldYield16();
1612
1613     /* Handle sent messages again */
1614     queue = QUEUE_Lock( GetFastQueue16() );
1615
1616     while ( queue && QUEUE_ReceiveMessage( queue ) )
1617         ;
1618
1619     QUEUE_Unlock( queue );
1620 }
1621
1622 /***********************************************************************
1623  *              GetMessagePos (USER.119) (USER32.@)
1624  * 
1625  * The GetMessagePos() function returns a long value representing a
1626  * cursor position, in screen coordinates, when the last message
1627  * retrieved by the GetMessage() function occurs. The x-coordinate is
1628  * in the low-order word of the return value, the y-coordinate is in
1629  * the high-order word. The application can use the MAKEPOINT()
1630  * macro to obtain a POINT structure from the return value. 
1631  *
1632  * For the current cursor position, use GetCursorPos().
1633  *
1634  * RETURNS
1635  *
1636  * Cursor position of last message on success, zero on failure.
1637  *
1638  * CONFORMANCE
1639  *
1640  * ECMA-234, Win32
1641  *
1642  */
1643 DWORD WINAPI GetMessagePos(void)
1644 {
1645     MESSAGEQUEUE *queue;
1646     DWORD ret;
1647
1648     if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0;
1649     ret = queue->GetMessagePosVal;
1650     QUEUE_Unlock( queue );
1651
1652     return ret;
1653 }
1654
1655
1656 /***********************************************************************
1657  *              GetMessageTime (USER.120) (USER32.@)
1658  *
1659  * GetMessageTime() returns the message time for the last message
1660  * retrieved by the function. The time is measured in milliseconds with
1661  * the same offset as GetTickCount().
1662  *
1663  * Since the tick count wraps, this is only useful for moderately short
1664  * relative time comparisons.
1665  *
1666  * RETURNS
1667  *
1668  * Time of last message on success, zero on failure.
1669  *
1670  * CONFORMANCE
1671  *
1672  * ECMA-234, Win32
1673  *  
1674  */
1675 LONG WINAPI GetMessageTime(void)
1676 {
1677     MESSAGEQUEUE *queue;
1678     LONG ret;
1679
1680     if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0;
1681     ret = queue->GetMessageTimeVal;
1682     QUEUE_Unlock( queue );
1683     
1684     return ret;
1685 }
1686
1687
1688 /***********************************************************************
1689  *              GetMessageExtraInfo (USER.288) (USER32.@)
1690  */
1691 LONG WINAPI GetMessageExtraInfo(void)
1692 {
1693     MESSAGEQUEUE *queue;
1694     LONG ret;
1695
1696     if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0;
1697     ret = queue->GetMessageExtraInfoVal;
1698     QUEUE_Unlock( queue );
1699
1700     return ret;
1701 }
1702
1703
1704 /**********************************************************************
1705  *              AttachThreadInput (USER32.@) Attaches input of 1 thread to other
1706  *
1707  * Attaches the input processing mechanism of one thread to that of
1708  * another thread.
1709  *
1710  * RETURNS
1711  *    Success: TRUE
1712  *    Failure: FALSE
1713  *
1714  * TODO:
1715  *    1. Reset the Key State (currenly per thread key state is not maintained)
1716  */
1717 BOOL WINAPI AttachThreadInput( 
1718     DWORD idAttach,   /* [in] Thread to attach */
1719     DWORD idAttachTo, /* [in] Thread to attach to */
1720     BOOL fAttach)   /* [in] Attach or detach */
1721 {
1722     MESSAGEQUEUE *pSrcMsgQ = 0, *pTgtMsgQ = 0;
1723     BOOL16 bRet = 0;
1724
1725     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1726
1727     /* A thread cannot attach to itself */
1728     if ( idAttach == idAttachTo )
1729         goto CLEANUP;
1730
1731     /* According to the docs this method should fail if a
1732      * "Journal record" hook is installed. (attaches all input queues together)
1733      */
1734     if ( HOOK_IsHooked( WH_JOURNALRECORD ) )
1735         goto CLEANUP;
1736         
1737     /* Retrieve message queues corresponding to the thread id's */
1738     pTgtMsgQ = QUEUE_Lock( GetThreadQueue16( idAttach ) );
1739     pSrcMsgQ = QUEUE_Lock( GetThreadQueue16( idAttachTo ) );
1740
1741     /* Ensure we have message queues and that Src and Tgt threads
1742      * are not system threads.
1743      */
1744     if ( !pSrcMsgQ || !pTgtMsgQ || !pSrcMsgQ->pQData || !pTgtMsgQ->pQData )
1745         goto CLEANUP;
1746
1747     if (fAttach)   /* Attach threads */
1748     {
1749         /* Only attach if currently detached  */
1750         if ( pTgtMsgQ->pQData != pSrcMsgQ->pQData )
1751         {
1752             /* First release the target threads perQData */
1753             PERQDATA_Release( pTgtMsgQ->pQData );
1754         
1755             /* Share a reference to the source threads perQDATA */
1756             PERQDATA_Addref( pSrcMsgQ->pQData );
1757             pTgtMsgQ->pQData = pSrcMsgQ->pQData;
1758         }
1759     }
1760     else    /* Detach threads */
1761     {
1762         /* Only detach if currently attached */
1763         if ( pTgtMsgQ->pQData == pSrcMsgQ->pQData )
1764         {
1765             /* First release the target threads perQData */
1766             PERQDATA_Release( pTgtMsgQ->pQData );
1767         
1768             /* Give the target thread its own private perQDATA once more */
1769             pTgtMsgQ->pQData = PERQDATA_CreateInstance();
1770         }
1771     }
1772
1773     /* TODO: Reset the Key State */
1774
1775     bRet = 1;      /* Success */
1776     
1777 CLEANUP:
1778
1779     /* Unlock the queues before returning */
1780     if ( pSrcMsgQ )
1781         QUEUE_Unlock( pSrcMsgQ );
1782     if ( pTgtMsgQ )
1783         QUEUE_Unlock( pTgtMsgQ );
1784     
1785     return bRet;
1786 }