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