Moved queue paint count to the server. Removed a few no longer used
[wine] / windows / queue.c
1 /*
2  * Message queues related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6
7 #include <string.h>
8 #include <signal.h>
9 #include <assert.h>
10 #include "windef.h"
11 #include "wingdi.h"
12 #include "winerror.h"
13 #include "wine/winbase16.h"
14 #include "wine/winuser16.h"
15 #include "queue.h"
16 #include "win.h"
17 #include "user.h"
18 #include "hook.h"
19 #include "thread.h"
20 #include "debugtools.h"
21 #include "server.h"
22 #include "spy.h"
23
24 DEFAULT_DEBUG_CHANNEL(msg);
25
26 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
27
28 static HQUEUE16 hExitingQueue = 0;
29 static PERQUEUEDATA *pQDataWin16 = NULL;  /* Global perQData for Win16 tasks */
30
31 HQUEUE16 hActiveQueue = 0;
32
33
34 /***********************************************************************
35  *           PERQDATA_CreateInstance
36  *
37  * Creates an instance of a reference counted PERQUEUEDATA element
38  * for the message queue. perQData is stored globally for 16 bit tasks.
39  *
40  * Note: We don't implement perQdata exactly the same way Windows does.
41  * Each perQData element is reference counted since it may be potentially
42  * shared by multiple message Queues (via AttachThreadInput).
43  * We only store the current values for Active, Capture and focus windows
44  * currently.
45  */
46 PERQUEUEDATA * PERQDATA_CreateInstance( )
47 {
48     PERQUEUEDATA *pQData;
49     
50     BOOL16 bIsWin16 = 0;
51     
52     TRACE_(msg)("()\n");
53
54     /* Share a single instance of perQData for all 16 bit tasks */
55     if ( ( bIsWin16 = !(NtCurrentTeb()->tibflags & TEBF_WIN32) ) )
56     {
57         /* If previously allocated, just bump up ref count */
58         if ( pQDataWin16 )
59         {
60             PERQDATA_Addref( pQDataWin16 );
61             return pQDataWin16;
62         }
63     }
64
65     /* Allocate PERQUEUEDATA from the system heap */
66     if (!( pQData = (PERQUEUEDATA *) HeapAlloc( GetProcessHeap(), 0,
67                                                     sizeof(PERQUEUEDATA) ) ))
68         return 0;
69
70     /* Initialize */
71     pQData->hWndCapture = pQData->hWndFocus = pQData->hWndActive = 0;
72     pQData->ulRefCount = 1;
73     pQData->nCaptureHT = HTCLIENT;
74
75     /* Note: We have an independent critical section for the per queue data
76      * since this may be shared by different threads. see AttachThreadInput()
77      */
78     InitializeCriticalSection( &pQData->cSection );
79     /* FIXME: not all per queue data critical sections should be global */
80     MakeCriticalSectionGlobal( &pQData->cSection );
81
82     /* Save perQData globally for 16 bit tasks */
83     if ( bIsWin16 )
84         pQDataWin16 = pQData;
85         
86     return pQData;
87 }
88
89
90 /***********************************************************************
91  *           PERQDATA_Addref
92  *
93  * Increment reference count for the PERQUEUEDATA instance
94  * Returns reference count for debugging purposes
95  */
96 ULONG PERQDATA_Addref( PERQUEUEDATA *pQData )
97 {
98     assert(pQData != 0 );
99     TRACE_(msg)("(): current refcount %lu ...\n", pQData->ulRefCount);
100
101     EnterCriticalSection( &pQData->cSection );
102     ++pQData->ulRefCount;
103     LeaveCriticalSection( &pQData->cSection );
104
105     return pQData->ulRefCount;
106 }
107
108
109 /***********************************************************************
110  *           PERQDATA_Release
111  *
112  * Release a reference to a PERQUEUEDATA instance.
113  * Destroy the instance if no more references exist
114  * Returns reference count for debugging purposes
115  */
116 ULONG PERQDATA_Release( PERQUEUEDATA *pQData )
117 {
118     assert(pQData != 0 );
119     TRACE_(msg)("(): current refcount %lu ...\n",
120           (LONG)pQData->ulRefCount );
121
122     EnterCriticalSection( &pQData->cSection );
123     if ( --pQData->ulRefCount == 0 )
124     {
125         LeaveCriticalSection( &pQData->cSection );
126         DeleteCriticalSection( &pQData->cSection );
127
128         TRACE_(msg)("(): deleting PERQUEUEDATA instance ...\n" );
129
130         /* Deleting our global 16 bit perQData? */
131         if ( pQData == pQDataWin16 )
132             pQDataWin16 = 0;
133             
134         /* Free the PERQUEUEDATA instance */
135         HeapFree( GetProcessHeap(), 0, pQData );
136
137         return 0;
138     }
139     LeaveCriticalSection( &pQData->cSection );
140
141     return pQData->ulRefCount;
142 }
143
144
145 /***********************************************************************
146  *           PERQDATA_GetFocusWnd
147  *
148  * Get the focus hwnd member in a threadsafe manner
149  */
150 HWND PERQDATA_GetFocusWnd( PERQUEUEDATA *pQData )
151 {
152     HWND hWndFocus;
153     assert(pQData != 0 );
154
155     EnterCriticalSection( &pQData->cSection );
156     hWndFocus = pQData->hWndFocus;
157     LeaveCriticalSection( &pQData->cSection );
158
159     return hWndFocus;
160 }
161
162
163 /***********************************************************************
164  *           PERQDATA_SetFocusWnd
165  *
166  * Set the focus hwnd member in a threadsafe manner
167  */
168 HWND PERQDATA_SetFocusWnd( PERQUEUEDATA *pQData, HWND hWndFocus )
169 {
170     HWND hWndFocusPrv;
171     assert(pQData != 0 );
172
173     EnterCriticalSection( &pQData->cSection );
174     hWndFocusPrv = pQData->hWndFocus;
175     pQData->hWndFocus = hWndFocus;
176     LeaveCriticalSection( &pQData->cSection );
177
178     return hWndFocusPrv;
179 }
180
181
182 /***********************************************************************
183  *           PERQDATA_GetActiveWnd
184  *
185  * Get the active hwnd member in a threadsafe manner
186  */
187 HWND PERQDATA_GetActiveWnd( PERQUEUEDATA *pQData )
188 {
189     HWND hWndActive;
190     assert(pQData != 0 );
191
192     EnterCriticalSection( &pQData->cSection );
193     hWndActive = pQData->hWndActive;
194     LeaveCriticalSection( &pQData->cSection );
195
196     return hWndActive;
197 }
198
199
200 /***********************************************************************
201  *           PERQDATA_SetActiveWnd
202  *
203  * Set the active focus hwnd member in a threadsafe manner
204  */
205 HWND PERQDATA_SetActiveWnd( PERQUEUEDATA *pQData, HWND hWndActive )
206 {
207     HWND hWndActivePrv;
208     assert(pQData != 0 );
209
210     EnterCriticalSection( &pQData->cSection );
211     hWndActivePrv = pQData->hWndActive;
212     pQData->hWndActive = hWndActive;
213     LeaveCriticalSection( &pQData->cSection );
214
215     return hWndActivePrv;
216 }
217
218
219 /***********************************************************************
220  *           PERQDATA_GetCaptureWnd
221  *
222  * Get the capture hwnd member in a threadsafe manner
223  */
224 HWND PERQDATA_GetCaptureWnd( PERQUEUEDATA *pQData )
225 {
226     HWND hWndCapture;
227     assert(pQData != 0 );
228
229     EnterCriticalSection( &pQData->cSection );
230     hWndCapture = pQData->hWndCapture;
231     LeaveCriticalSection( &pQData->cSection );
232
233     return hWndCapture;
234 }
235
236
237 /***********************************************************************
238  *           PERQDATA_SetCaptureWnd
239  *
240  * Set the capture hwnd member in a threadsafe manner
241  */
242 HWND PERQDATA_SetCaptureWnd( PERQUEUEDATA *pQData, HWND hWndCapture )
243 {
244     HWND hWndCapturePrv;
245     assert(pQData != 0 );
246
247     EnterCriticalSection( &pQData->cSection );
248     hWndCapturePrv = pQData->hWndCapture;
249     pQData->hWndCapture = hWndCapture;
250     LeaveCriticalSection( &pQData->cSection );
251
252     return hWndCapturePrv;
253 }
254
255
256 /***********************************************************************
257  *           PERQDATA_GetCaptureInfo
258  *
259  * Get the capture info member in a threadsafe manner
260  */
261 INT16 PERQDATA_GetCaptureInfo( PERQUEUEDATA *pQData )
262 {
263     INT16 nCaptureHT;
264     assert(pQData != 0 );
265
266     EnterCriticalSection( &pQData->cSection );
267     nCaptureHT = pQData->nCaptureHT;
268     LeaveCriticalSection( &pQData->cSection );
269
270     return nCaptureHT;
271 }
272
273
274 /***********************************************************************
275  *           PERQDATA_SetCaptureInfo
276  *
277  * Set the capture info member in a threadsafe manner
278  */
279 INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT )
280 {
281     INT16 nCaptureHTPrv;
282     assert(pQData != 0 );
283
284     EnterCriticalSection( &pQData->cSection );
285     nCaptureHTPrv = pQData->nCaptureHT;
286     pQData->nCaptureHT = nCaptureHT;
287     LeaveCriticalSection( &pQData->cSection );
288
289     return nCaptureHTPrv;
290 }
291
292
293 /***********************************************************************
294  *           QUEUE_Lock
295  *
296  * Function for getting a 32 bit pointer on queue structure. For thread
297  * safeness programmers should use this function instead of GlobalLock to
298  * retrieve a pointer on the structure. QUEUE_Unlock should also be called
299  * when access to the queue structure is not required anymore.
300  */
301 MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue )
302 {
303     MESSAGEQUEUE *queue;
304
305     HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
306     queue = GlobalLock16( hQueue );
307     if ( !queue || (queue->magic != QUEUE_MAGIC) )
308     {
309         HeapUnlock( GetProcessHeap() );
310         return NULL;
311     }
312
313     queue->lockCount++;
314     HeapUnlock( GetProcessHeap() );
315     return queue;
316 }
317
318
319 /***********************************************************************
320  *           QUEUE_Unlock
321  *
322  * Use with QUEUE_Lock to get a thread safe access to message queue
323  * structure
324  */
325 void QUEUE_Unlock( MESSAGEQUEUE *queue )
326 {
327     if (queue)
328     {
329         HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
330
331         if ( --queue->lockCount == 0 )
332         {
333             DeleteCriticalSection ( &queue->cSection );
334             if (queue->server_queue)
335                 CloseHandle( queue->server_queue );
336             GlobalFree16( queue->self );
337         }
338     
339         HeapUnlock( GetProcessHeap() );
340     }
341 }
342
343
344 /***********************************************************************
345  *           QUEUE_DumpQueue
346  */
347 void QUEUE_DumpQueue( HQUEUE16 hQueue )
348 {
349     MESSAGEQUEUE *pq; 
350
351     if (!(pq = QUEUE_Lock( hQueue )) )
352     {
353         WARN_(msg)("%04x is not a queue handle\n", hQueue );
354         return;
355     }
356
357     EnterCriticalSection( &pq->cSection );
358
359     DPRINTF( "thread: %10p  Intertask SendMessage:\n"
360              "firstMsg: %8p   lastMsg:  %8p\n"
361              "lockCount: %7.4x\n"
362              "paints: %10.4x\n"
363              "hCurHook: %8.4x\n",
364              pq->teb, pq->firstMsg, pq->lastMsg,
365              (unsigned)pq->lockCount, pq->wPaintCount,
366              pq->hCurHook);
367
368     LeaveCriticalSection( &pq->cSection );
369
370     QUEUE_Unlock( pq );
371 }
372
373
374 /***********************************************************************
375  *           QUEUE_IsExitingQueue
376  */
377 BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue )
378 {
379     return (hExitingQueue && (hQueue == hExitingQueue));
380 }
381
382
383 /***********************************************************************
384  *           QUEUE_SetExitingQueue
385  */
386 void QUEUE_SetExitingQueue( HQUEUE16 hQueue )
387 {
388     hExitingQueue = hQueue;
389 }
390
391
392 /***********************************************************************
393  *           QUEUE_CreateMsgQueue
394  *
395  * Creates a message queue. Doesn't link it into queue list!
396  */
397 static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData )
398 {
399     HQUEUE16 hQueue;
400     HANDLE handle;
401     MESSAGEQUEUE * msgQueue;
402
403     TRACE_(msg)("(): Creating message queue...\n");
404
405     if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT,
406                                   sizeof(MESSAGEQUEUE) )))
407         return 0;
408
409     msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
410     if ( !msgQueue )
411         return 0;
412
413     if (bCreatePerQData)
414     {
415         SERVER_START_REQ( get_msg_queue )
416         {
417             SERVER_CALL_ERR();
418             handle = req->handle;
419         }
420         SERVER_END_REQ;
421         if (!handle)
422         {
423             ERR_(msg)("Cannot get thread queue");
424             GlobalFree16( hQueue );
425             return 0;
426         }
427         msgQueue->server_queue = handle;
428     }
429
430     msgQueue->self = hQueue;
431
432     InitializeCriticalSection( &msgQueue->cSection );
433     MakeCriticalSectionGlobal( &msgQueue->cSection );
434
435     msgQueue->lockCount = 1;
436     msgQueue->magic = QUEUE_MAGIC;
437     
438     /* Create and initialize our per queue data */
439     msgQueue->pQData = bCreatePerQData ? PERQDATA_CreateInstance() : NULL;
440     
441     return hQueue;
442 }
443
444
445 /***********************************************************************
446  *           QUEUE_DeleteMsgQueue
447  *
448  * Unlinks and deletes a message queue.
449  *
450  * Note: We need to mask asynchronous events to make sure PostMessage works
451  * even in the signal handler.
452  */
453 BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
454 {
455     MESSAGEQUEUE * msgQueue = QUEUE_Lock(hQueue);
456
457     TRACE_(msg)("(): Deleting message queue %04x\n", hQueue);
458
459     if (!hQueue || !msgQueue)
460     {
461         ERR_(msg)("invalid argument.\n");
462         return 0;
463     }
464
465     msgQueue->magic = 0;
466
467     if( hActiveQueue == hQueue ) hActiveQueue = 0;
468
469     HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
470
471     /* Release per queue data if present */
472     if ( msgQueue->pQData )
473     {
474         PERQDATA_Release( msgQueue->pQData );
475         msgQueue->pQData = 0;
476     }
477
478     msgQueue->self = 0;
479
480     HeapUnlock( GetProcessHeap() );
481
482     /* free up resource used by MESSAGEQUEUE structure */
483     msgQueue->lockCount--;
484     QUEUE_Unlock( msgQueue );
485     
486     return 1;
487 }
488
489
490 /***********************************************************************
491  *           handle_sent_message
492  *
493  * Handle the reception of a sent message by calling the corresponding window proc
494  */
495 static void handle_sent_message( QMSG *msg )
496 {
497     LRESULT result = 0;
498     MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
499     DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */
500     WND *wndPtr = WIN_FindWndPtr( msg->msg.hwnd );
501
502     TRACE( "got hwnd %x msg %x (%s) wp %x lp %lx\n",
503            msg->msg.hwnd, msg->msg.message, SPY_GetMsgName(msg->msg.message),
504            msg->msg.wParam, msg->msg.lParam );
505
506     queue->GetMessageExtraInfoVal = msg->extraInfo;
507
508     /* call the right version of CallWindowProcXX */
509     switch(msg->type)
510     {
511     case QMSG_WIN16:
512         result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
513                                    (HWND16) msg->msg.hwnd,
514                                    (UINT16) msg->msg.message,
515                                    LOWORD(msg->msg.wParam),
516                                    msg->msg.lParam );
517         break;
518     case QMSG_WIN32A:
519         result = CallWindowProcA( wndPtr->winproc, msg->msg.hwnd, msg->msg.message,
520                                   msg->msg.wParam, msg->msg.lParam );
521         break;
522     case QMSG_WIN32W:
523         result = CallWindowProcW( wndPtr->winproc, msg->msg.hwnd, msg->msg.message,
524                                   msg->msg.wParam, msg->msg.lParam );
525         break;
526     }
527
528     queue->GetMessageExtraInfoVal = extraInfo;  /* Restore extra info */
529     WIN_ReleaseWndPtr(wndPtr);
530     QUEUE_Unlock( queue );
531
532     SERVER_START_REQ( reply_message )
533     {
534         req->result = result;
535         req->remove = 1;
536         SERVER_CALL();
537     }
538     SERVER_END_REQ;
539 }
540
541
542 /***********************************************************************
543  *           process_sent_messages
544  *
545  * Process all pending sent messages
546  */
547 static void process_sent_messages(void)
548 {
549     QMSG msg;
550     unsigned int res;
551
552     for (;;)
553     {
554         SERVER_START_REQ( get_message )
555         {
556             req->flags = GET_MSG_REMOVE | GET_MSG_SENT_ONLY;
557             req->get_win   = 0;
558             req->get_first = 0;
559             req->get_last  = ~0;
560             if (!(res = SERVER_CALL()))
561             {
562                 msg.type        = req->type;
563                 msg.msg.hwnd    = req->win;
564                 msg.msg.message = req->msg;
565                 msg.msg.wParam  = req->wparam;
566                 msg.msg.lParam  = req->lparam;
567                 msg.msg.time    = req->time;
568                 msg.msg.pt.x    = req->x;
569                 msg.msg.pt.y    = req->y;
570                 msg.extraInfo   = req->info;
571             }
572         }
573         SERVER_END_REQ;
574
575         if (res) break;
576         handle_sent_message( &msg );
577     }
578 }
579
580
581
582 /***********************************************************************
583  *           QUEUE_WaitBits
584  *
585  * See "Windows Internals", p.447
586  *
587  * return values:
588  *    0 if exit with timeout
589  *    1 otherwise
590  */
591 int QUEUE_WaitBits( WORD bits, DWORD timeout )
592 {
593     MESSAGEQUEUE *queue;
594     HQUEUE16 hQueue;
595
596     TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits);
597
598     hQueue = GetFastQueue16();
599     if (!(queue = QUEUE_Lock( hQueue ))) return 0;
600     
601     for (;;)
602     {
603         unsigned int wake_bits = 0, changed_bits = 0;
604         DWORD dwlc;
605
606         SERVER_START_REQ( set_queue_mask )
607         {
608             req->wake_mask    = QS_SENDMESSAGE;
609             req->changed_mask = bits | QS_SENDMESSAGE;
610             req->skip_wait    = 1;
611             if (!SERVER_CALL())
612             {
613                 wake_bits    = req->wake_bits;
614                 changed_bits = req->changed_bits;
615             }
616         }
617         SERVER_END_REQ;
618
619         if (changed_bits & bits)
620         {
621             /* One of the bits is set; we can return */
622             QUEUE_Unlock( queue );
623             return 1;
624         }
625         if (wake_bits & QS_SENDMESSAGE)
626         {
627             /* Process the sent message immediately */
628             process_sent_messages();
629             continue;  /* nested sm crux */
630         }
631
632         TRACE_(msg)("(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n",
633                     queue->self, bits, wake_bits, changed_bits );
634
635         ReleaseThunkLock( &dwlc );
636         if (dwlc) TRACE_(msg)("had win16 lock\n");
637
638         if (USER_Driver.pMsgWaitForMultipleObjectsEx)
639             USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, timeout, 0, 0 );
640         else
641             WaitForSingleObject( queue->server_queue, timeout );
642         if (dwlc) RestoreThunkLock( dwlc );
643     }
644 }
645
646
647 /***********************************************************************
648  *           QUEUE_FindMsg
649  *
650  * Find a message matching the given parameters. Return FALSE if none available.
651  */
652 BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove, QMSG *msg )
653 {
654     BOOL ret = FALSE;
655
656     if (!first && !last) last = ~0;
657
658     for (;;)
659     {
660         SERVER_START_REQ( get_message )
661         {
662             req->flags     = remove ? GET_MSG_REMOVE : 0;
663             req->get_win   = hwnd;
664             req->get_first = first;
665             req->get_last  = last;
666             if ((ret = !SERVER_CALL()))
667             {
668                 msg->kind        = req->kind;
669                 msg->type        = req->type;
670                 msg->msg.hwnd    = req->win;
671                 msg->msg.message = req->msg;
672                 msg->msg.wParam  = req->wparam;
673                 msg->msg.lParam  = req->lparam;
674                 msg->msg.time    = req->time;
675                 msg->msg.pt.x    = req->x;
676                 msg->msg.pt.y    = req->y;
677                 msg->extraInfo   = req->info;
678             }
679         }
680         SERVER_END_REQ;
681
682         if (!ret || (msg->kind != SEND_MESSAGE)) break;
683         handle_sent_message( msg );
684     }
685
686     if (ret) TRACE( "got hwnd %x msg %x (%s) wp %x lp %lx\n",
687                     msg->msg.hwnd, msg->msg.message, SPY_GetMsgName(msg->msg.message),
688                     msg->msg.wParam, msg->msg.lParam );
689     return ret;
690 }
691
692
693
694 /***********************************************************************
695  *           QUEUE_CleanupWindow
696  *
697  * Cleanup the queue to account for a window being deleted.
698  */
699 void QUEUE_CleanupWindow( HWND hwnd )
700 {
701     SERVER_START_REQ( cleanup_window_queue )
702     {
703         req->win = hwnd;
704         SERVER_CALL();
705     }
706     SERVER_END_REQ;
707 }
708
709
710 /***********************************************************************
711  *           QUEUE_GetQueueTask
712  */
713 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
714 {
715     HTASK16 hTask = 0;
716     
717     MESSAGEQUEUE *queue = QUEUE_Lock( hQueue );
718
719     if (queue)
720     {
721         hTask = queue->teb->htask16;
722         QUEUE_Unlock( queue );
723     }
724
725     return hTask;
726 }
727
728
729 /***********************************************************************
730  *              PostQuitMessage (USER.6)
731  */
732 void WINAPI PostQuitMessage16( INT16 exitCode )
733 {
734     PostQuitMessage( exitCode );
735 }
736
737
738 /***********************************************************************
739  *              PostQuitMessage (USER32.@)
740  *
741  * PostQuitMessage() posts a message to the system requesting an
742  * application to terminate execution. As a result of this function,
743  * the WM_QUIT message is posted to the application, and
744  * PostQuitMessage() returns immediately.  The exitCode parameter
745  * specifies an application-defined exit code, which appears in the
746  * _wParam_ parameter of the WM_QUIT message posted to the application.  
747  *
748  * CONFORMANCE
749  *
750  *  ECMA-234, Win32
751  */
752 void WINAPI PostQuitMessage( INT exitCode )
753 {
754     PostThreadMessageW( GetCurrentThreadId(), WM_QUIT, exitCode, 0 );
755 }
756
757
758 /***********************************************************************
759  *              GetWindowTask (USER.224)
760  */
761 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
762 {
763     HTASK16 retvalue;
764     WND *wndPtr = WIN_FindWndPtr( hwnd );
765
766     if (!wndPtr) return 0;
767     retvalue = QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
768     WIN_ReleaseWndPtr(wndPtr);
769     return retvalue;
770 }
771
772 /***********************************************************************
773  *              GetWindowThreadProcessId (USER32.@)
774  */
775 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
776 {
777     DWORD retvalue;
778     MESSAGEQUEUE *queue;
779
780     WND *wndPtr = WIN_FindWndPtr( hwnd );
781     if (!wndPtr) return 0;
782
783     queue = QUEUE_Lock( wndPtr->hmemTaskQ );
784     WIN_ReleaseWndPtr(wndPtr);
785
786     if (!queue) return 0;
787
788     if ( process ) *process = (DWORD)queue->teb->pid;
789     retvalue = (DWORD)queue->teb->tid;
790
791     QUEUE_Unlock( queue );
792     return retvalue;
793 }
794
795
796 /***********************************************************************
797  *              SetMessageQueue (USER.266)
798  */
799 BOOL16 WINAPI SetMessageQueue16( INT16 size )
800 {
801     return SetMessageQueue( size );
802 }
803
804
805 /***********************************************************************
806  *              SetMessageQueue (USER32.@)
807  */
808 BOOL WINAPI SetMessageQueue( INT size )
809 {
810     /* now obsolete the message queue will be expanded dynamically
811      as necessary */
812
813     /* access the queue to create it if it's not existing */
814     GetFastQueue16();
815
816     return TRUE;
817 }
818
819 /***********************************************************************
820  *              InitThreadInput (USER.409)
821  */
822 HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags )
823 {
824     HQUEUE16 hQueue;
825     MESSAGEQUEUE *queuePtr;
826
827     TEB *teb = NtCurrentTeb();
828
829     if (!teb)
830         return 0;
831
832     hQueue = teb->queue;
833     
834     if ( !hQueue )
835     {
836         /* Create thread message queue */
837         if( !(hQueue = QUEUE_CreateMsgQueue( TRUE )))
838         {
839             ERR_(msg)("failed!\n");
840             return FALSE;
841         }
842         
843         /* Link new queue into list */
844         queuePtr = QUEUE_Lock( hQueue );
845         queuePtr->teb = NtCurrentTeb();
846
847         HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
848         SetThreadQueue16( 0, hQueue );
849         teb->queue = hQueue;
850         HeapUnlock( GetProcessHeap() );
851         
852         QUEUE_Unlock( queuePtr );
853     }
854
855     return hQueue;
856 }
857
858 /***********************************************************************
859  *              GetQueueStatus (USER.334)
860  */
861 DWORD WINAPI GetQueueStatus16( UINT16 flags )
862 {
863     return GetQueueStatus( flags );
864 }
865
866 /***********************************************************************
867  *              GetQueueStatus (USER32.@)
868  */
869 DWORD WINAPI GetQueueStatus( UINT flags )
870 {
871     DWORD ret = 0;
872
873     SERVER_START_REQ( get_queue_status )
874     {
875         req->clear = 1;
876         SERVER_CALL();
877         ret = MAKELONG( req->changed_bits & flags, req->wake_bits & flags );
878     }
879     SERVER_END_REQ;
880     return ret;
881 }
882
883
884 /***********************************************************************
885  *              GetInputState (USER.335)
886  */
887 BOOL16 WINAPI GetInputState16(void)
888 {
889     return GetInputState();
890 }
891
892 /***********************************************************************
893  *              GetInputState   (USER32.@)
894  */
895 BOOL WINAPI GetInputState(void)
896 {
897     DWORD ret = 0;
898
899     SERVER_START_REQ( get_queue_status )
900     {
901         req->clear = 0;
902         SERVER_CALL();
903         ret = req->wake_bits & (QS_KEY | QS_MOUSEBUTTON);
904     }
905     SERVER_END_REQ;
906     return ret;
907 }
908
909 /***********************************************************************
910  *              WaitForInputIdle (USER32.@)
911  */
912 DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
913 {
914     DWORD cur_time, ret;
915     HANDLE idle_event = -1;
916
917     SERVER_START_REQ( wait_input_idle )
918     {
919         req->handle = hProcess;
920         req->timeout = dwTimeOut;
921         if (!(ret = SERVER_CALL_ERR())) idle_event = req->event;
922     }
923     SERVER_END_REQ;
924     if (ret) return 0xffffffff;  /* error */
925     if (!idle_event) return 0;  /* no event to wait on */
926
927     cur_time = GetTickCount();
928
929     TRACE_(msg)("waiting for %x\n", idle_event );
930     while ( dwTimeOut > GetTickCount() - cur_time || dwTimeOut == INFINITE ) 
931     {
932         ret = MsgWaitForMultipleObjects ( 1, &idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE );
933         if ( ret == ( WAIT_OBJECT_0 + 1 )) 
934         {
935             process_sent_messages();
936             continue;
937         }
938         if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF ) 
939         {
940             TRACE_(msg)("timeout or error\n");
941             return ret;
942         }
943         else 
944         {
945             TRACE_(msg)("finished\n");
946             return 0;
947         }
948     }
949
950     return WAIT_TIMEOUT;
951 }
952
953 /***********************************************************************
954  *              UserYield (USER.332)
955  *              UserYield16 (USER32.@)
956  */
957 void WINAPI UserYield16(void)
958 {
959     /* Handle sent messages */
960     process_sent_messages();
961
962     /* Yield */
963     OldYield16();
964
965     /* Handle sent messages again */
966     process_sent_messages();
967 }
968
969 /***********************************************************************
970  *              GetMessagePos (USER.119) (USER32.@)
971  * 
972  * The GetMessagePos() function returns a long value representing a
973  * cursor position, in screen coordinates, when the last message
974  * retrieved by the GetMessage() function occurs. The x-coordinate is
975  * in the low-order word of the return value, the y-coordinate is in
976  * the high-order word. The application can use the MAKEPOINT()
977  * macro to obtain a POINT structure from the return value. 
978  *
979  * For the current cursor position, use GetCursorPos().
980  *
981  * RETURNS
982  *
983  * Cursor position of last message on success, zero on failure.
984  *
985  * CONFORMANCE
986  *
987  * ECMA-234, Win32
988  *
989  */
990 DWORD WINAPI GetMessagePos(void)
991 {
992     MESSAGEQUEUE *queue;
993     DWORD ret;
994
995     if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0;
996     ret = queue->GetMessagePosVal;
997     QUEUE_Unlock( queue );
998
999     return ret;
1000 }
1001
1002
1003 /***********************************************************************
1004  *              GetMessageTime (USER.120) (USER32.@)
1005  *
1006  * GetMessageTime() returns the message time for the last message
1007  * retrieved by the function. The time is measured in milliseconds with
1008  * the same offset as GetTickCount().
1009  *
1010  * Since the tick count wraps, this is only useful for moderately short
1011  * relative time comparisons.
1012  *
1013  * RETURNS
1014  *
1015  * Time of last message on success, zero on failure.
1016  *
1017  * CONFORMANCE
1018  *
1019  * ECMA-234, Win32
1020  *  
1021  */
1022 LONG WINAPI GetMessageTime(void)
1023 {
1024     MESSAGEQUEUE *queue;
1025     LONG ret;
1026
1027     if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0;
1028     ret = queue->GetMessageTimeVal;
1029     QUEUE_Unlock( queue );
1030     
1031     return ret;
1032 }
1033
1034
1035 /***********************************************************************
1036  *              GetMessageExtraInfo (USER.288) (USER32.@)
1037  */
1038 LONG WINAPI GetMessageExtraInfo(void)
1039 {
1040     MESSAGEQUEUE *queue;
1041     LONG ret;
1042
1043     if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0;
1044     ret = queue->GetMessageExtraInfoVal;
1045     QUEUE_Unlock( queue );
1046
1047     return ret;
1048 }
1049
1050
1051 /**********************************************************************
1052  *              AttachThreadInput (USER32.@) Attaches input of 1 thread to other
1053  *
1054  * Attaches the input processing mechanism of one thread to that of
1055  * another thread.
1056  *
1057  * RETURNS
1058  *    Success: TRUE
1059  *    Failure: FALSE
1060  *
1061  * TODO:
1062  *    1. Reset the Key State (currenly per thread key state is not maintained)
1063  */
1064 BOOL WINAPI AttachThreadInput( 
1065     DWORD idAttach,   /* [in] Thread to attach */
1066     DWORD idAttachTo, /* [in] Thread to attach to */
1067     BOOL fAttach)   /* [in] Attach or detach */
1068 {
1069     MESSAGEQUEUE *pSrcMsgQ = 0, *pTgtMsgQ = 0;
1070     BOOL16 bRet = 0;
1071
1072     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1073
1074     /* A thread cannot attach to itself */
1075     if ( idAttach == idAttachTo )
1076         goto CLEANUP;
1077
1078     /* According to the docs this method should fail if a
1079      * "Journal record" hook is installed. (attaches all input queues together)
1080      */
1081     if ( HOOK_IsHooked( WH_JOURNALRECORD ) )
1082         goto CLEANUP;
1083         
1084     /* Retrieve message queues corresponding to the thread id's */
1085     pTgtMsgQ = QUEUE_Lock( GetThreadQueue16( idAttach ) );
1086     pSrcMsgQ = QUEUE_Lock( GetThreadQueue16( idAttachTo ) );
1087
1088     /* Ensure we have message queues and that Src and Tgt threads
1089      * are not system threads.
1090      */
1091     if ( !pSrcMsgQ || !pTgtMsgQ || !pSrcMsgQ->pQData || !pTgtMsgQ->pQData )
1092         goto CLEANUP;
1093
1094     if (fAttach)   /* Attach threads */
1095     {
1096         /* Only attach if currently detached  */
1097         if ( pTgtMsgQ->pQData != pSrcMsgQ->pQData )
1098         {
1099             /* First release the target threads perQData */
1100             PERQDATA_Release( pTgtMsgQ->pQData );
1101         
1102             /* Share a reference to the source threads perQDATA */
1103             PERQDATA_Addref( pSrcMsgQ->pQData );
1104             pTgtMsgQ->pQData = pSrcMsgQ->pQData;
1105         }
1106     }
1107     else    /* Detach threads */
1108     {
1109         /* Only detach if currently attached */
1110         if ( pTgtMsgQ->pQData == pSrcMsgQ->pQData )
1111         {
1112             /* First release the target threads perQData */
1113             PERQDATA_Release( pTgtMsgQ->pQData );
1114         
1115             /* Give the target thread its own private perQDATA once more */
1116             pTgtMsgQ->pQData = PERQDATA_CreateInstance();
1117         }
1118     }
1119
1120     /* TODO: Reset the Key State */
1121
1122     bRet = 1;      /* Success */
1123     
1124 CLEANUP:
1125
1126     /* Unlock the queues before returning */
1127     if ( pSrcMsgQ )
1128         QUEUE_Unlock( pSrcMsgQ );
1129     if ( pTgtMsgQ )
1130         QUEUE_Unlock( pTgtMsgQ );
1131     
1132     return bRet;
1133 }