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