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