Release 980517
[wine] / windows / queue.c
1 /*
2  * Message queues related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include <signal.h>
9 #include "miscemu.h"
10 #include "module.h"
11 #include "queue.h"
12 #include "task.h"
13 #include "win.h"
14 #include "clipboard.h"
15 #include "hook.h"
16 #include "thread.h"
17 #include "process.h"
18 #include "debug.h"
19
20 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
21
22 static HQUEUE16 hFirstQueue = 0;
23 static HQUEUE16 hExitingQueue = 0;
24 static HQUEUE16 hmemSysMsgQueue = 0;
25 static MESSAGEQUEUE *sysMsgQueue = NULL;
26
27 static MESSAGEQUEUE *pMouseQueue = NULL;  /* Queue for last mouse message */
28 static MESSAGEQUEUE *pKbdQueue = NULL;    /* Queue for last kbd message */
29
30 MESSAGEQUEUE *pCursorQueue = NULL; 
31 MESSAGEQUEUE *pActiveQueue = NULL;
32
33 /***********************************************************************
34  *           QUEUE_DumpQueue
35  */
36 void QUEUE_DumpQueue( HQUEUE16 hQueue )
37 {
38     MESSAGEQUEUE *pq; 
39
40     if (!(pq = (MESSAGEQUEUE*) GlobalLock16( hQueue )) ||
41         GlobalSize16(hQueue) < sizeof(MESSAGEQUEUE)+pq->queueSize*sizeof(QMSG))
42     {
43         fprintf( stderr, "%04x is not a queue handle\n", hQueue );
44         return;
45     }
46
47     fprintf( stderr,
48              "next: %12.4x  Intertask SendMessage:\n"
49              "hTask: %11.4x  ----------------------\n"
50              "msgSize: %9.4x  hWnd: %10.4x\n"
51              "msgCount: %8.4x  msg: %11.4x\n"
52              "msgNext: %9.4x  wParam: %8.4x\n"
53              "msgFree: %9.4x  lParam: %8.8x\n"
54              "qSize: %11.4x  lRet: %10.8x\n"
55              "wWinVer: %9.4x  ISMH: %10.4x\n"
56              "paints: %10.4x  hSendTask: %5.4x\n"
57              "timers: %10.4x  hPrevSend: %5.4x\n"
58              "wakeBits: %8.4x\n"
59              "wakeMask: %8.4x\n"
60              "hCurHook: %8.4x\n",
61              pq->next, pq->hTask, pq->msgSize, pq->hWnd, 
62              pq->msgCount, pq->msg, pq->nextMessage, pq->wParam,
63              pq->nextFreeMessage, (unsigned)pq->lParam, pq->queueSize,
64              (unsigned)pq->SendMessageReturn, pq->wWinVersion, pq->InSendMessageHandle,
65              pq->wPaintCount, pq->hSendingTask, pq->wTimerCount,
66              pq->hPrevSendingTask, pq->wakeBits, pq->wakeMask, pq->hCurHook);
67 }
68
69
70 /***********************************************************************
71  *           QUEUE_WalkQueues
72  */
73 void QUEUE_WalkQueues(void)
74 {
75     char module[10];
76     HQUEUE16 hQueue = hFirstQueue;
77
78     fprintf( stderr, "Queue Size Msgs Task\n" );
79     while (hQueue)
80     {
81         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
82         if (!queue)
83         {
84             fprintf( stderr, "*** Bad queue handle %04x\n", hQueue );
85             return;
86         }
87         if (!GetModuleName( queue->hTask, module, sizeof(module )))
88             strcpy( module, "???" );
89         fprintf( stderr, "%04x %5d %4d %04x %s\n", hQueue, queue->msgSize,
90                  queue->msgCount, queue->hTask, module );
91         hQueue = queue->next;
92     }
93     fprintf( stderr, "\n" );
94 }
95
96
97 /***********************************************************************
98  *           QUEUE_IsExitingQueue
99  */
100 BOOL32 QUEUE_IsExitingQueue( HQUEUE16 hQueue )
101 {
102     return (hExitingQueue && (hQueue == hExitingQueue));
103 }
104
105
106 /***********************************************************************
107  *           QUEUE_SetExitingQueue
108  */
109 void QUEUE_SetExitingQueue( HQUEUE16 hQueue )
110 {
111     hExitingQueue = hQueue;
112 }
113
114
115 /***********************************************************************
116  *           QUEUE_CreateMsgQueue
117  *
118  * Creates a message queue. Doesn't link it into queue list!
119  */
120 static HQUEUE16 QUEUE_CreateMsgQueue( int size )
121 {
122     HQUEUE16 hQueue;
123     MESSAGEQUEUE * msgQueue;
124     int queueSize;
125     TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
126
127     TRACE(msg,"Creating message queue...\n");
128
129     queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG);
130     if (!(hQueue = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, queueSize )))
131         return 0;
132     msgQueue = (MESSAGEQUEUE *) GlobalLock16( hQueue );
133     msgQueue->self        = hQueue;
134     msgQueue->msgSize     = sizeof(QMSG);
135     msgQueue->queueSize   = size;
136     msgQueue->wakeBits    = msgQueue->changeBits = QS_SMPARAMSFREE;
137     msgQueue->wWinVersion = pTask ? pTask->version : 0;
138     GlobalUnlock16( hQueue );
139     return hQueue;
140 }
141
142
143 /***********************************************************************
144  *           QUEUE_DeleteMsgQueue
145  *
146  * Unlinks and deletes a message queue.
147  *
148  * Note: We need to mask asynchronous events to make sure PostMessage works
149  * even in the signal handler.
150  */
151 BOOL32 QUEUE_DeleteMsgQueue( HQUEUE16 hQueue )
152 {
153     MESSAGEQUEUE * msgQueue = (MESSAGEQUEUE*)GlobalLock16(hQueue);
154     HQUEUE16  senderQ;
155     HQUEUE16 *pPrev;
156
157     TRACE(msg,"Deleting message queue %04x\n", hQueue);
158
159     if (!hQueue || !msgQueue)
160     {
161         WARN(msg, "invalid argument.\n");
162         return 0;
163     }
164     if( pCursorQueue == msgQueue ) pCursorQueue = NULL;
165     if( pActiveQueue == msgQueue ) pActiveQueue = NULL;
166
167     /* flush sent messages */
168     senderQ = msgQueue->hSendingTask;
169     while( senderQ )
170     {
171       MESSAGEQUEUE* sq = (MESSAGEQUEUE*)GlobalLock16(senderQ);
172       if( !sq ) break;
173       sq->SendMessageReturn = 0L;
174       QUEUE_SetWakeBit( sq, QS_SMRESULT );
175       senderQ = sq->hPrevSendingTask;
176     }
177
178     SIGNAL_MaskAsyncEvents( TRUE );
179
180     pPrev = &hFirstQueue;
181     while (*pPrev && (*pPrev != hQueue))
182     {
183         MESSAGEQUEUE *msgQ = (MESSAGEQUEUE*)GlobalLock16(*pPrev);
184         pPrev = &msgQ->next;
185     }
186     if (*pPrev) *pPrev = msgQueue->next;
187     msgQueue->self = 0;
188
189     SIGNAL_MaskAsyncEvents( FALSE );
190
191     GlobalFree16( hQueue );
192     return 1;
193 }
194
195
196 /***********************************************************************
197  *           QUEUE_CreateSysMsgQueue
198  *
199  * Create the system message queue, and set the double-click speed.
200  * Must be called only once.
201  */
202 BOOL32 QUEUE_CreateSysMsgQueue( int size )
203 {
204     if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE;
205     else if (size <= 0) size = 1;
206     if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( size ))) return FALSE;
207     sysMsgQueue = (MESSAGEQUEUE *) GlobalLock16( hmemSysMsgQueue );
208     return TRUE;
209 }
210
211
212 /***********************************************************************
213  *           QUEUE_GetSysQueue
214  */
215 MESSAGEQUEUE *QUEUE_GetSysQueue(void)
216 {
217     return sysMsgQueue;
218 }
219
220
221 /***********************************************************************
222  *           QUEUE_SetWakeBit
223  *
224  * See "Windows Internals", p.449
225  */
226 void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
227 {
228     TRACE(msg,"queue = %04x (wm=%04x), bit = %04x\n", 
229                         queue->self, queue->wakeMask, bit );
230
231     if (bit & QS_MOUSE) pMouseQueue = queue;
232     if (bit & QS_KEY) pKbdQueue = queue;
233     queue->changeBits |= bit;
234     queue->wakeBits   |= bit;
235     if (queue->wakeMask & bit)
236     {
237         queue->wakeMask = 0;
238         PostEvent( queue->hTask );
239     }
240 }
241
242
243 /***********************************************************************
244  *           QUEUE_ClearWakeBit
245  */
246 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
247 {
248     queue->changeBits &= ~bit;
249     queue->wakeBits   &= ~bit;
250 }
251
252
253 /***********************************************************************
254  *           QUEUE_WaitBits
255  *
256  * See "Windows Internals", p.447
257  */
258 void QUEUE_WaitBits( WORD bits )
259 {
260     MESSAGEQUEUE *queue;
261
262     TRACE(msg,"q %04x waiting for %04x\n", GetTaskQueue(0), bits);
263
264     for (;;)
265     {
266         if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return;
267
268         if (queue->changeBits & bits)
269         {
270             /* One of the bits is set; we can return */
271             queue->wakeMask = 0;
272             return;
273         }
274         if (queue->wakeBits & QS_SENDMESSAGE)
275         {
276             /* Process the sent message immediately */
277
278             queue->wakeMask = 0;
279             QUEUE_ReceiveMessage( queue );
280             continue;                           /* nested sm crux */
281         }
282
283         queue->wakeMask = bits | QS_SENDMESSAGE;
284         if(queue->changeBits & bits) continue;
285         
286         TRACE(msg,"%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
287
288         WaitEvent( 0 );
289     }
290 }
291
292
293 /***********************************************************************
294  *           QUEUE_ReceiveMessage
295  *
296  * This routine is called when a sent message is waiting for the queue.
297  */
298 void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
299 {
300     MESSAGEQUEUE *senderQ = NULL;
301     HQUEUE16      prevSender = 0;
302     QSMCTRL*      prevCtrlPtr = NULL;
303     LRESULT       result = 0;
304
305     TRACE(msg, "ReceiveMessage, queue %04x\n", queue->self );
306     if (!(queue->wakeBits & QS_SENDMESSAGE) ||
307         !(senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask))) 
308         { TRACE(msg,"\trcm: nothing to do\n"); return; }
309
310     if( !senderQ->hPrevSendingTask )
311     {
312       queue->wakeBits &= ~QS_SENDMESSAGE;       /* no more sent messages */
313       queue->changeBits &= ~QS_SENDMESSAGE;
314     }
315
316     /* Save current state on stack */
317     prevSender                 = queue->InSendMessageHandle;
318     prevCtrlPtr                = queue->smResultCurrent;
319
320     /* Remove sending queue from the list */
321     queue->InSendMessageHandle = queue->hSendingTask;
322     queue->smResultCurrent     = senderQ->smResultInit;
323     queue->hSendingTask        = senderQ->hPrevSendingTask;
324
325     TRACE(msg, "\trcm: smResultCurrent = %08x, prevCtrl = %08x\n", 
326                                 (unsigned)queue->smResultCurrent, (unsigned)prevCtrlPtr );
327     QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
328
329     TRACE(msg, "\trcm: calling wndproc - %04x %04x %04x%04x %08x\n",
330                 senderQ->hWnd, senderQ->msg, senderQ->wParamHigh,
331                 senderQ->wParam, (unsigned)senderQ->lParam );
332
333     if (IsWindow32( senderQ->hWnd ))
334     {
335         WND *wndPtr = WIN_FindWndPtr( senderQ->hWnd );
336         DWORD extraInfo = queue->GetMessageExtraInfoVal;
337         queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
338
339         if (senderQ->flags & QUEUE_SM_WIN32)
340         {
341             WPARAM32 wParam = MAKELONG( senderQ->wParam, senderQ->wParamHigh );
342             TRACE(msg, "\trcm: msg is Win32\n" );
343             if (senderQ->flags & QUEUE_SM_UNICODE)
344                 result = CallWindowProc32W( wndPtr->winproc,
345                                             senderQ->hWnd, senderQ->msg,
346                                             wParam, senderQ->lParam );
347             else
348                 result = CallWindowProc32A( wndPtr->winproc,
349                                             senderQ->hWnd, senderQ->msg,
350                                             wParam, senderQ->lParam );
351         }
352         else  /* Win16 message */
353             result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
354                                        senderQ->hWnd, senderQ->msg,
355                                        senderQ->wParam, senderQ->lParam );
356
357         queue->GetMessageExtraInfoVal = extraInfo;  /* Restore extra info */
358         TRACE(msg,"\trcm: result =  %08x\n", (unsigned)result );
359     }
360     else WARN(msg, "\trcm: bad hWnd\n");
361
362     /* Return the result to the sender task */
363     ReplyMessage16( result );
364
365     queue->InSendMessageHandle = prevSender;
366     queue->smResultCurrent     = prevCtrlPtr;
367
368     TRACE(msg,"done!\n");
369 }
370
371 /***********************************************************************
372  *           QUEUE_FlushMessage
373  * 
374  * Try to reply to all pending sent messages on exit.
375  */
376 void QUEUE_FlushMessages( HQUEUE16 hQueue )
377 {
378   MESSAGEQUEUE *queue = (MESSAGEQUEUE*)GlobalLock16( hQueue );
379
380   if( queue )
381   {
382     MESSAGEQUEUE *senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask);
383     QSMCTRL*      CtrlPtr = queue->smResultCurrent;
384
385     while( senderQ )
386     {
387       if( !(queue->hSendingTask = senderQ->hPrevSendingTask) )
388             queue->wakeBits &= ~QS_SENDMESSAGE;
389       QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
390       
391       queue->smResultCurrent = CtrlPtr;
392       while( senderQ->wakeBits & QS_SMRESULT ) OldYield();
393
394       senderQ->SendMessageReturn = 0;
395       senderQ->smResult = queue->smResultCurrent;
396       QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
397
398       if( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask)) )
399            CtrlPtr = senderQ->smResultInit;
400     }
401     queue->InSendMessageHandle = 0;
402   }  
403 }
404
405 /***********************************************************************
406  *           QUEUE_AddMsg
407  *
408  * Add a message to the queue. Return FALSE if queue is full.
409  */
410 BOOL32 QUEUE_AddMsg( HQUEUE16 hQueue, MSG16 * msg, DWORD extraInfo )
411 {
412     int pos;
413     MESSAGEQUEUE *msgQueue;
414
415     SIGNAL_MaskAsyncEvents( TRUE );
416
417     if (!(msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return FALSE;
418     pos = msgQueue->nextFreeMessage;
419
420       /* Check if queue is full */
421     if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0))
422     {
423         SIGNAL_MaskAsyncEvents( FALSE );
424         fprintf(stderr,"MSG_AddMsg // queue is full !\n");
425         return FALSE;
426     }
427
428       /* Store message */
429     msgQueue->messages[pos].msg = *msg;
430     msgQueue->messages[pos].extraInfo = extraInfo;
431     if (pos < msgQueue->queueSize-1) pos++;
432     else pos = 0;
433     msgQueue->nextFreeMessage = pos;
434     msgQueue->msgCount++;
435
436     SIGNAL_MaskAsyncEvents( FALSE );
437
438     QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
439     return TRUE;
440 }
441
442
443 /***********************************************************************
444  *           QUEUE_FindMsg
445  *
446  * Find a message matching the given parameters. Return -1 if none available.
447  */
448 int QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND32 hwnd, int first, int last )
449 {
450     int i, pos = msgQueue->nextMessage;
451
452     TRACE(msg,"hwnd=%04x pos=%d\n", hwnd, pos );
453
454     if (!msgQueue->msgCount) return -1;
455     if (!hwnd && !first && !last) return pos;
456         
457     for (i = 0; i < msgQueue->msgCount; i++)
458     {
459         MSG16 * msg = &msgQueue->messages[pos].msg;
460
461         if (!hwnd || (msg->hwnd == hwnd))
462         {
463             if (!first && !last) return pos;
464             if ((msg->message >= first) && (msg->message <= last)) return pos;
465         }
466         if (pos < msgQueue->queueSize-1) pos++;
467         else pos = 0;
468     }
469     return -1;
470 }
471
472
473 /***********************************************************************
474  *           QUEUE_RemoveMsg
475  *
476  * Remove a message from the queue (pos must be a valid position).
477  */
478 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
479 {
480     SIGNAL_MaskAsyncEvents( TRUE );
481
482     if (pos >= msgQueue->nextMessage)
483     {
484         for ( ; pos > msgQueue->nextMessage; pos--)
485             msgQueue->messages[pos] = msgQueue->messages[pos-1];
486         msgQueue->nextMessage++;
487         if (msgQueue->nextMessage >= msgQueue->queueSize)
488             msgQueue->nextMessage = 0;
489     }
490     else
491     {
492         for ( ; pos < msgQueue->nextFreeMessage; pos++)
493             msgQueue->messages[pos] = msgQueue->messages[pos+1];
494         if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
495         else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
496     }
497     msgQueue->msgCount--;
498     if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
499
500     SIGNAL_MaskAsyncEvents( FALSE );
501 }
502
503
504 /***********************************************************************
505  *           QUEUE_WakeSomeone
506  *
507  * Wake a queue upon reception of a hardware event.
508  */
509 static void QUEUE_WakeSomeone( UINT32 message )
510 {
511     WND*          wndPtr = NULL;
512     WORD          wakeBit;
513     HWND32 hwnd;
514     MESSAGEQUEUE *queue = pCursorQueue;
515
516     if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
517     {
518        wakeBit = QS_KEY;
519        if( pActiveQueue ) queue = pActiveQueue;
520     }
521     else 
522     {
523        wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
524        if( (hwnd = GetCapture32()) )
525          if( (wndPtr = WIN_FindWndPtr( hwnd )) ) 
526            queue = (MESSAGEQUEUE *)GlobalLock16( wndPtr->hmemTaskQ );
527     }
528
529     if( (hwnd = GetSysModalWindow16()) )
530       if( (wndPtr = WIN_FindWndPtr( hwnd )) )
531         queue = (MESSAGEQUEUE *)GlobalLock16( wndPtr->hmemTaskQ );
532
533     if( !queue ) 
534     {
535       queue = GlobalLock16( hFirstQueue );
536       while( queue )
537       {
538         if (queue->wakeMask & wakeBit) break;
539         queue = GlobalLock16( queue->next );
540       }
541       if( !queue )
542       { 
543         WARN(msg, "couldn't find queue\n"); 
544         return; 
545       }
546     }
547
548     QUEUE_SetWakeBit( queue, wakeBit );
549 }
550
551
552 /***********************************************************************
553  *           hardware_event
554  *
555  * Add an event to the system message queue.
556  * Note: the position is relative to the desktop window.
557  */
558 void hardware_event( WORD message, WORD wParam, LONG lParam,
559                      int xPos, int yPos, DWORD time, DWORD extraInfo )
560 {
561     MSG16 *msg;
562     int pos;
563
564     if (!sysMsgQueue) return;
565     pos = sysMsgQueue->nextFreeMessage;
566
567       /* Merge with previous event if possible */
568
569     if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
570     {
571         if (pos > 0) pos--;
572         else pos = sysMsgQueue->queueSize - 1;
573         msg = &sysMsgQueue->messages[pos].msg;
574         if ((msg->message == message) && (msg->wParam == wParam))
575             sysMsgQueue->msgCount--;  /* Merge events */
576         else
577             pos = sysMsgQueue->nextFreeMessage;  /* Don't merge */
578     }
579
580       /* Check if queue is full */
581
582     if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
583     {
584         /* Queue is full, beep (but not on every mouse motion...) */
585         if (message != WM_MOUSEMOVE) MessageBeep32(0);
586         return;
587     }
588
589       /* Store message */
590
591     msg = &sysMsgQueue->messages[pos].msg;
592     msg->hwnd    = 0;
593     msg->message = message;
594     msg->wParam  = wParam;
595     msg->lParam  = lParam;
596     msg->time    = time;
597     msg->pt.x    = xPos & 0xffff;
598     msg->pt.y    = yPos & 0xffff;
599     sysMsgQueue->messages[pos].extraInfo = extraInfo;
600     if (pos < sysMsgQueue->queueSize - 1) pos++;
601     else pos = 0;
602     sysMsgQueue->nextFreeMessage = pos;
603     sysMsgQueue->msgCount++;
604     QUEUE_WakeSomeone( message );
605 }
606
607                     
608 /***********************************************************************
609  *           QUEUE_GetQueueTask
610  */
611 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
612 {
613     MESSAGEQUEUE *queue = GlobalLock16( hQueue );
614     return (queue) ? queue->hTask : 0 ;
615 }
616
617
618 /***********************************************************************
619  *           QUEUE_IncPaintCount
620  */
621 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
622 {
623     MESSAGEQUEUE *queue;
624
625     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
626     queue->wPaintCount++;
627     QUEUE_SetWakeBit( queue, QS_PAINT );
628 }
629
630
631 /***********************************************************************
632  *           QUEUE_DecPaintCount
633  */
634 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
635 {
636     MESSAGEQUEUE *queue;
637
638     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
639     queue->wPaintCount--;
640     if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
641 }
642
643
644 /***********************************************************************
645  *           QUEUE_IncTimerCount
646  */
647 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
648 {
649     MESSAGEQUEUE *queue;
650
651     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
652     queue->wTimerCount++;
653     QUEUE_SetWakeBit( queue, QS_TIMER );
654 }
655
656
657 /***********************************************************************
658  *           QUEUE_DecTimerCount
659  */
660 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
661 {
662     MESSAGEQUEUE *queue;
663
664     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
665     queue->wTimerCount--;
666     if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
667 }
668
669
670 /***********************************************************************
671  *           PostQuitMessage16   (USER.6)
672  */
673 void WINAPI PostQuitMessage16( INT16 exitCode )
674 {
675     PostQuitMessage32( exitCode );
676 }
677
678
679 /***********************************************************************
680  *           PostQuitMessage32   (USER32.421)
681  */
682 void WINAPI PostQuitMessage32( INT32 exitCode )
683 {
684     MESSAGEQUEUE *queue;
685
686     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return;
687     queue->wPostQMsg = TRUE;
688     queue->wExitCode = (WORD)exitCode;
689 }
690
691
692 /***********************************************************************
693  *           GetWindowTask16   (USER.224)
694  */
695 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
696 {
697     WND *wndPtr = WIN_FindWndPtr( hwnd );
698
699     if (!wndPtr) return 0;
700     return QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
701 }
702
703 /***********************************************************************
704  *           GetWindowThreadProcessId   (USER32.313)
705  */
706 DWORD WINAPI GetWindowThreadProcessId( HWND32 hwnd, LPDWORD process )
707 {
708     HTASK16 htask;
709     TDB *tdb;
710
711     WND *wndPtr = WIN_FindWndPtr( hwnd );
712
713     if (!wndPtr) return 0;
714     htask=QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
715     tdb = (TDB*)GlobalLock16(htask);
716     if (!tdb || !tdb->thdb) return 0;
717     if (process) *process = PDB_TO_PROCESS_ID( tdb->thdb->process );
718     return THDB_TO_THREAD_ID( tdb->thdb );
719 }
720
721
722 /***********************************************************************
723  *           SetMessageQueue16   (USER.266)
724  */
725 BOOL16 WINAPI SetMessageQueue16( INT16 size )
726 {
727     return SetMessageQueue32( size );
728 }
729
730
731 /***********************************************************************
732  *           SetMessageQueue32   (USER32.494)
733  */
734 BOOL32 WINAPI SetMessageQueue32( INT32 size )
735 {
736     HQUEUE16 hQueue, hNewQueue;
737     MESSAGEQUEUE *queuePtr;
738
739     TRACE(msg,"task %04x size %i\n", GetCurrentTask(), size); 
740
741     if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
742
743     if( !(hNewQueue = QUEUE_CreateMsgQueue( size ))) 
744     {
745         WARN(msg, "failed!\n");
746         return FALSE;
747     }
748     queuePtr = (MESSAGEQUEUE *)GlobalLock16( hNewQueue );
749
750     SIGNAL_MaskAsyncEvents( TRUE );
751
752     /* Copy data and free the old message queue */
753     if ((hQueue = GetTaskQueue(0)) != 0) 
754     {
755        MESSAGEQUEUE *oldQ = (MESSAGEQUEUE *)GlobalLock16( hQueue );
756        memcpy( &queuePtr->wParamHigh, &oldQ->wParamHigh,
757                         (int)oldQ->messages - (int)(&oldQ->wParamHigh) );
758        HOOK_ResetQueueHooks( hNewQueue );
759        if( WIN_GetDesktop()->hmemTaskQ == hQueue )
760            WIN_GetDesktop()->hmemTaskQ = hNewQueue;
761        WIN_ResetQueueWindows( WIN_GetDesktop(), hQueue, hNewQueue );
762        CLIPBOARD_ResetLock( hQueue, hNewQueue );
763        QUEUE_DeleteMsgQueue( hQueue );
764     }
765
766     /* Link new queue into list */
767     queuePtr->hTask = GetCurrentTask();
768     queuePtr->next  = hFirstQueue;
769     hFirstQueue = hNewQueue;
770     
771     if( !queuePtr->next ) pCursorQueue = queuePtr;
772     SetTaskQueue( 0, hNewQueue );
773     
774     SIGNAL_MaskAsyncEvents( FALSE );
775     return TRUE;
776 }
777
778
779 /***********************************************************************
780  *           GetQueueStatus16   (USER.334)
781  */
782 DWORD WINAPI GetQueueStatus16( UINT16 flags )
783 {
784     MESSAGEQUEUE *queue;
785     DWORD ret;
786
787     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
788     ret = MAKELONG( queue->changeBits, queue->wakeBits );
789     queue->changeBits = 0;
790     return ret & MAKELONG( flags, flags );
791 }
792
793 /***********************************************************************
794  *           GetQueueStatus32   (USER32.283)
795  */
796 DWORD WINAPI GetQueueStatus32( UINT32 flags )
797 {
798     MESSAGEQUEUE *queue;
799     DWORD ret;
800
801     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
802     ret = MAKELONG( queue->changeBits, queue->wakeBits );
803     queue->changeBits = 0;
804     return ret & MAKELONG( flags, flags );
805 }
806
807
808 /***********************************************************************
809  *           GetInputState16   (USER.335)
810  */
811 BOOL16 WINAPI GetInputState16(void)
812 {
813     return GetInputState32();
814 }
815
816 /***********************************************************************
817  *           WaitForInputIdle   (USER32.577)
818  */
819 DWORD WINAPI WaitForInputIdle (HANDLE32 hProcess, DWORD dwTimeOut)
820 {
821   FIXME (msg, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
822
823   return WAIT_TIMEOUT;
824 }
825
826
827 /***********************************************************************
828  *           GetInputState32   (USER32.244)
829  */
830 BOOL32 WINAPI GetInputState32(void)
831 {
832     MESSAGEQUEUE *queue;
833
834     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
835         return FALSE;
836     return queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
837 }
838
839
840 /***********************************************************************
841  *           GetMessagePos   (USER.119) (USER32.272)
842  */
843 DWORD WINAPI GetMessagePos(void)
844 {
845     MESSAGEQUEUE *queue;
846
847     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
848     return queue->GetMessagePosVal;
849 }
850
851
852 /***********************************************************************
853  *           GetMessageTime   (USER.120) (USER32.273)
854  */
855 LONG WINAPI GetMessageTime(void)
856 {
857     MESSAGEQUEUE *queue;
858
859     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
860     return queue->GetMessageTimeVal;
861 }
862
863
864 /***********************************************************************
865  *           GetMessageExtraInfo   (USER.288) (USER32.271)
866  */
867 LONG WINAPI GetMessageExtraInfo(void)
868 {
869     MESSAGEQUEUE *queue;
870
871     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
872     return queue->GetMessageExtraInfoVal;
873 }