Release 980809
[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 "heap.h"
17 #include "thread.h"
18 #include "process.h"
19 #include "debug.h"
20
21 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
22
23 static HQUEUE16 hFirstQueue = 0;
24 static HQUEUE16 hExitingQueue = 0;
25 static HQUEUE16 hmemSysMsgQueue = 0;
26 static MESSAGEQUEUE *sysMsgQueue = NULL;
27
28 static MESSAGEQUEUE *pMouseQueue = NULL;  /* Queue for last mouse message */
29 static MESSAGEQUEUE *pKbdQueue = NULL;    /* Queue for last kbd message */
30
31 MESSAGEQUEUE *pCursorQueue = NULL; 
32 MESSAGEQUEUE *pActiveQueue = NULL;
33
34 /***********************************************************************
35  *           QUEUE_DumpQueue
36  */
37 void QUEUE_DumpQueue( HQUEUE16 hQueue )
38 {
39     MESSAGEQUEUE *pq; 
40
41     if (!(pq = (MESSAGEQUEUE*) GlobalLock16( hQueue )) ||
42         GlobalSize16(hQueue) < sizeof(MESSAGEQUEUE)+pq->queueSize*sizeof(QMSG))
43     {
44         WARN(msg, "%04x is not a queue handle\n", hQueue );
45         return;
46     }
47
48     DUMP(    "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     DUMP( "Queue Size Msgs Task\n" );
79     while (hQueue)
80     {
81         MESSAGEQUEUE *queue = (MESSAGEQUEUE *)GlobalLock16( hQueue );
82         if (!queue)
83         {
84             WARN( msg, "Bad queue handle %04x\n", hQueue );
85             return;
86         }
87         if (!GetModuleName( queue->hTask, module, sizeof(module )))
88             strcpy( module, "???" );
89         DUMP( "%04x %5d %4d %04x %s\n", hQueue, queue->msgSize,
90                  queue->msgCount, queue->hTask, module );
91         hQueue = queue->next;
92     }
93     DUMP( "\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         /* Wake up thread waiting for message */
241         /* NOTE: This should really wake up *the* thread that owns
242                  the queue. Since we dont't have thread-local message
243                  queues yet, we wake up all waiting threads ... */
244         SYSTEM_LOCK();
245         {
246             TDB *pTask = (TDB *)GlobalLock16( queue->hTask );
247             PDB32 *pdb = pTask? pTask->thdb->process : NULL;
248             THREAD_ENTRY *entry = pdb? pdb->thread_list->next : NULL;
249
250             if (entry)
251                 for (;;)
252                 {
253                     if (entry->thread->wait_struct.wait_msg)
254                         SYNC_MsgWakeUp( entry->thread );
255                     if (entry == pdb->thread_list) break;
256                     entry = entry->next;
257                 }
258         }
259         SYSTEM_UNLOCK();
260     }
261 }
262
263
264 /***********************************************************************
265  *           QUEUE_ClearWakeBit
266  */
267 void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
268 {
269     queue->changeBits &= ~bit;
270     queue->wakeBits   &= ~bit;
271 }
272
273
274 /***********************************************************************
275  *           QUEUE_WaitBits
276  *
277  * See "Windows Internals", p.447
278  */
279 void QUEUE_WaitBits( WORD bits )
280 {
281     MESSAGEQUEUE *queue;
282
283     TRACE(msg,"q %04x waiting for %04x\n", GetTaskQueue(0), bits);
284
285     for (;;)
286     {
287         if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return;
288
289         if (queue->changeBits & bits)
290         {
291             /* One of the bits is set; we can return */
292             queue->wakeMask = 0;
293             return;
294         }
295         if (queue->wakeBits & QS_SENDMESSAGE)
296         {
297             /* Process the sent message immediately */
298
299             queue->wakeMask = 0;
300             QUEUE_ReceiveMessage( queue );
301             continue;                           /* nested sm crux */
302         }
303
304         queue->wakeMask = bits | QS_SENDMESSAGE;
305         if(queue->changeBits & bits) continue;
306         
307         TRACE(msg,"%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
308
309         WaitEvent( 0 );
310     }
311 }
312
313
314 /***********************************************************************
315  *           QUEUE_ReceiveMessage
316  *
317  * This routine is called when a sent message is waiting for the queue.
318  */
319 void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
320 {
321     MESSAGEQUEUE *senderQ = NULL;
322     HQUEUE16      prevSender = 0;
323     QSMCTRL*      prevCtrlPtr = NULL;
324     LRESULT       result = 0;
325
326     TRACE(msg, "ReceiveMessage, queue %04x\n", queue->self );
327     if (!(queue->wakeBits & QS_SENDMESSAGE) ||
328         !(senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask))) 
329         { TRACE(msg,"\trcm: nothing to do\n"); return; }
330
331     if( !senderQ->hPrevSendingTask )
332     {
333       queue->wakeBits &= ~QS_SENDMESSAGE;       /* no more sent messages */
334       queue->changeBits &= ~QS_SENDMESSAGE;
335     }
336
337     /* Save current state on stack */
338     prevSender                 = queue->InSendMessageHandle;
339     prevCtrlPtr                = queue->smResultCurrent;
340
341     /* Remove sending queue from the list */
342     queue->InSendMessageHandle = queue->hSendingTask;
343     queue->smResultCurrent     = senderQ->smResultInit;
344     queue->hSendingTask        = senderQ->hPrevSendingTask;
345
346     TRACE(msg, "\trcm: smResultCurrent = %08x, prevCtrl = %08x\n", 
347                                 (unsigned)queue->smResultCurrent, (unsigned)prevCtrlPtr );
348     QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
349
350     TRACE(msg, "\trcm: calling wndproc - %04x %04x %04x%04x %08x\n",
351                 senderQ->hWnd, senderQ->msg, senderQ->wParamHigh,
352                 senderQ->wParam, (unsigned)senderQ->lParam );
353
354     if (IsWindow32( senderQ->hWnd ))
355     {
356         WND *wndPtr = WIN_FindWndPtr( senderQ->hWnd );
357         DWORD extraInfo = queue->GetMessageExtraInfoVal;
358         queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal;
359
360         if (senderQ->flags & QUEUE_SM_WIN32)
361         {
362             WPARAM32 wParam = MAKELONG( senderQ->wParam, senderQ->wParamHigh );
363             TRACE(msg, "\trcm: msg is Win32\n" );
364             if (senderQ->flags & QUEUE_SM_UNICODE)
365                 result = CallWindowProc32W( wndPtr->winproc,
366                                             senderQ->hWnd, senderQ->msg,
367                                             wParam, senderQ->lParam );
368             else
369                 result = CallWindowProc32A( wndPtr->winproc,
370                                             senderQ->hWnd, senderQ->msg,
371                                             wParam, senderQ->lParam );
372         }
373         else  /* Win16 message */
374             result = CallWindowProc16( (WNDPROC16)wndPtr->winproc,
375                                        senderQ->hWnd, senderQ->msg,
376                                        senderQ->wParam, senderQ->lParam );
377
378         queue->GetMessageExtraInfoVal = extraInfo;  /* Restore extra info */
379         TRACE(msg,"\trcm: result =  %08x\n", (unsigned)result );
380     }
381     else WARN(msg, "\trcm: bad hWnd\n");
382
383     /* Return the result to the sender task */
384     ReplyMessage16( result );
385
386     queue->InSendMessageHandle = prevSender;
387     queue->smResultCurrent     = prevCtrlPtr;
388
389     TRACE(msg,"done!\n");
390 }
391
392 /***********************************************************************
393  *           QUEUE_FlushMessage
394  * 
395  * Try to reply to all pending sent messages on exit.
396  */
397 void QUEUE_FlushMessages( HQUEUE16 hQueue )
398 {
399   MESSAGEQUEUE *queue = (MESSAGEQUEUE*)GlobalLock16( hQueue );
400
401   if( queue )
402   {
403     MESSAGEQUEUE *senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask);
404     QSMCTRL*      CtrlPtr = queue->smResultCurrent;
405
406     while( senderQ )
407     {
408       if( !(queue->hSendingTask = senderQ->hPrevSendingTask) )
409             queue->wakeBits &= ~QS_SENDMESSAGE;
410       QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE );
411       
412       queue->smResultCurrent = CtrlPtr;
413       while( senderQ->wakeBits & QS_SMRESULT ) OldYield();
414
415       senderQ->SendMessageReturn = 0;
416       senderQ->smResult = queue->smResultCurrent;
417       QUEUE_SetWakeBit( senderQ, QS_SMRESULT);
418
419       if( (senderQ = (MESSAGEQUEUE*)GlobalLock16( queue->hSendingTask)) )
420            CtrlPtr = senderQ->smResultInit;
421     }
422     queue->InSendMessageHandle = 0;
423   }  
424 }
425
426 /***********************************************************************
427  *           QUEUE_AddMsg
428  *
429  * Add a message to the queue. Return FALSE if queue is full.
430  */
431 BOOL32 QUEUE_AddMsg( HQUEUE16 hQueue, MSG16 * msg, DWORD extraInfo )
432 {
433     int pos;
434     MESSAGEQUEUE *msgQueue;
435
436     SIGNAL_MaskAsyncEvents( TRUE );
437
438     if (!(msgQueue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return FALSE;
439     pos = msgQueue->nextFreeMessage;
440
441       /* Check if queue is full */
442     if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0))
443     {
444         SIGNAL_MaskAsyncEvents( FALSE );
445         WARN( msg,"Queue is full!\n" );
446         return FALSE;
447     }
448
449       /* Store message */
450     msgQueue->messages[pos].msg = *msg;
451     msgQueue->messages[pos].extraInfo = extraInfo;
452     if (pos < msgQueue->queueSize-1) pos++;
453     else pos = 0;
454     msgQueue->nextFreeMessage = pos;
455     msgQueue->msgCount++;
456
457     SIGNAL_MaskAsyncEvents( FALSE );
458
459     QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE );
460     return TRUE;
461 }
462
463
464 /***********************************************************************
465  *           QUEUE_FindMsg
466  *
467  * Find a message matching the given parameters. Return -1 if none available.
468  */
469 int QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND32 hwnd, int first, int last )
470 {
471     int i, pos = msgQueue->nextMessage;
472
473     TRACE(msg,"hwnd=%04x pos=%d\n", hwnd, pos );
474
475     if (!msgQueue->msgCount) return -1;
476     if (!hwnd && !first && !last) return pos;
477         
478     for (i = 0; i < msgQueue->msgCount; i++)
479     {
480         MSG16 * msg = &msgQueue->messages[pos].msg;
481
482         if (!hwnd || (msg->hwnd == hwnd))
483         {
484             if (!first && !last) return pos;
485             if ((msg->message >= first) && (msg->message <= last)) return pos;
486         }
487         if (pos < msgQueue->queueSize-1) pos++;
488         else pos = 0;
489     }
490     return -1;
491 }
492
493
494 /***********************************************************************
495  *           QUEUE_RemoveMsg
496  *
497  * Remove a message from the queue (pos must be a valid position).
498  */
499 void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos )
500 {
501     SIGNAL_MaskAsyncEvents( TRUE );
502
503     if (pos >= msgQueue->nextMessage)
504     {
505         for ( ; pos > msgQueue->nextMessage; pos--)
506             msgQueue->messages[pos] = msgQueue->messages[pos-1];
507         msgQueue->nextMessage++;
508         if (msgQueue->nextMessage >= msgQueue->queueSize)
509             msgQueue->nextMessage = 0;
510     }
511     else
512     {
513         for ( ; pos < msgQueue->nextFreeMessage; pos++)
514             msgQueue->messages[pos] = msgQueue->messages[pos+1];
515         if (msgQueue->nextFreeMessage) msgQueue->nextFreeMessage--;
516         else msgQueue->nextFreeMessage = msgQueue->queueSize-1;
517     }
518     msgQueue->msgCount--;
519     if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE;
520
521     SIGNAL_MaskAsyncEvents( FALSE );
522 }
523
524
525 /***********************************************************************
526  *           QUEUE_WakeSomeone
527  *
528  * Wake a queue upon reception of a hardware event.
529  */
530 static void QUEUE_WakeSomeone( UINT32 message )
531 {
532     WND*          wndPtr = NULL;
533     WORD          wakeBit;
534     HWND32 hwnd;
535     MESSAGEQUEUE *queue = pCursorQueue;
536
537     if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) )
538     {
539        wakeBit = QS_KEY;
540        if( pActiveQueue ) queue = pActiveQueue;
541     }
542     else 
543     {
544        wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
545        if( (hwnd = GetCapture32()) )
546          if( (wndPtr = WIN_FindWndPtr( hwnd )) ) 
547            queue = (MESSAGEQUEUE *)GlobalLock16( wndPtr->hmemTaskQ );
548     }
549
550     if( (hwnd = GetSysModalWindow16()) )
551       if( (wndPtr = WIN_FindWndPtr( hwnd )) )
552         queue = (MESSAGEQUEUE *)GlobalLock16( wndPtr->hmemTaskQ );
553
554     if( !queue ) 
555     {
556       queue = GlobalLock16( hFirstQueue );
557       while( queue )
558       {
559         if (queue->wakeMask & wakeBit) break;
560         queue = GlobalLock16( queue->next );
561       }
562       if( !queue )
563       { 
564         WARN(msg, "couldn't find queue\n"); 
565         return; 
566       }
567     }
568
569     QUEUE_SetWakeBit( queue, wakeBit );
570 }
571
572
573 /***********************************************************************
574  *           hardware_event
575  *
576  * Add an event to the system message queue.
577  * Note: the position is relative to the desktop window.
578  */
579 void hardware_event( WORD message, WORD wParam, LONG lParam,
580                      int xPos, int yPos, DWORD time, DWORD extraInfo )
581 {
582     MSG16 *msg;
583     int pos;
584
585     if (!sysMsgQueue) return;
586     pos = sysMsgQueue->nextFreeMessage;
587
588       /* Merge with previous event if possible */
589
590     if ((message == WM_MOUSEMOVE) && sysMsgQueue->msgCount)
591     {
592         if (pos > 0) pos--;
593         else pos = sysMsgQueue->queueSize - 1;
594         msg = &sysMsgQueue->messages[pos].msg;
595         if ((msg->message == message) && (msg->wParam == wParam))
596             sysMsgQueue->msgCount--;  /* Merge events */
597         else
598             pos = sysMsgQueue->nextFreeMessage;  /* Don't merge */
599     }
600
601       /* Check if queue is full */
602
603     if ((pos == sysMsgQueue->nextMessage) && sysMsgQueue->msgCount)
604     {
605         /* Queue is full, beep (but not on every mouse motion...) */
606         if (message != WM_MOUSEMOVE) MessageBeep32(0);
607         return;
608     }
609
610       /* Store message */
611
612     msg = &sysMsgQueue->messages[pos].msg;
613     msg->hwnd    = 0;
614     msg->message = message;
615     msg->wParam  = wParam;
616     msg->lParam  = lParam;
617     msg->time    = time;
618     msg->pt.x    = xPos & 0xffff;
619     msg->pt.y    = yPos & 0xffff;
620     sysMsgQueue->messages[pos].extraInfo = extraInfo;
621     if (pos < sysMsgQueue->queueSize - 1) pos++;
622     else pos = 0;
623     sysMsgQueue->nextFreeMessage = pos;
624     sysMsgQueue->msgCount++;
625     QUEUE_WakeSomeone( message );
626 }
627
628                     
629 /***********************************************************************
630  *           QUEUE_GetQueueTask
631  */
632 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
633 {
634     MESSAGEQUEUE *queue = GlobalLock16( hQueue );
635     return (queue) ? queue->hTask : 0 ;
636 }
637
638
639 /***********************************************************************
640  *           QUEUE_IncPaintCount
641  */
642 void QUEUE_IncPaintCount( HQUEUE16 hQueue )
643 {
644     MESSAGEQUEUE *queue;
645
646     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
647     queue->wPaintCount++;
648     QUEUE_SetWakeBit( queue, QS_PAINT );
649 }
650
651
652 /***********************************************************************
653  *           QUEUE_DecPaintCount
654  */
655 void QUEUE_DecPaintCount( HQUEUE16 hQueue )
656 {
657     MESSAGEQUEUE *queue;
658
659     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
660     queue->wPaintCount--;
661     if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
662 }
663
664
665 /***********************************************************************
666  *           QUEUE_IncTimerCount
667  */
668 void QUEUE_IncTimerCount( HQUEUE16 hQueue )
669 {
670     MESSAGEQUEUE *queue;
671
672     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
673     queue->wTimerCount++;
674     QUEUE_SetWakeBit( queue, QS_TIMER );
675 }
676
677
678 /***********************************************************************
679  *           QUEUE_DecTimerCount
680  */
681 void QUEUE_DecTimerCount( HQUEUE16 hQueue )
682 {
683     MESSAGEQUEUE *queue;
684
685     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( hQueue ))) return;
686     queue->wTimerCount--;
687     if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
688 }
689
690
691 /***********************************************************************
692  *           PostQuitMessage16   (USER.6)
693  */
694 void WINAPI PostQuitMessage16( INT16 exitCode )
695 {
696     PostQuitMessage32( exitCode );
697 }
698
699
700 /***********************************************************************
701  *           PostQuitMessage32   (USER32.421)
702  */
703 void WINAPI PostQuitMessage32( INT32 exitCode )
704 {
705     MESSAGEQUEUE *queue;
706
707     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return;
708     queue->wPostQMsg = TRUE;
709     queue->wExitCode = (WORD)exitCode;
710 }
711
712
713 /***********************************************************************
714  *           GetWindowTask16   (USER.224)
715  */
716 HTASK16 WINAPI GetWindowTask16( HWND16 hwnd )
717 {
718     WND *wndPtr = WIN_FindWndPtr( hwnd );
719
720     if (!wndPtr) return 0;
721     return QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
722 }
723
724 /***********************************************************************
725  *           GetWindowThreadProcessId   (USER32.313)
726  */
727 DWORD WINAPI GetWindowThreadProcessId( HWND32 hwnd, LPDWORD process )
728 {
729     HTASK16 htask;
730     TDB *tdb;
731
732     WND *wndPtr = WIN_FindWndPtr( hwnd );
733
734     if (!wndPtr) return 0;
735     htask=QUEUE_GetQueueTask( wndPtr->hmemTaskQ );
736     tdb = (TDB*)GlobalLock16(htask);
737     if (!tdb || !tdb->thdb) return 0;
738     if (process) *process = PDB_TO_PROCESS_ID( tdb->thdb->process );
739     return THDB_TO_THREAD_ID( tdb->thdb );
740 }
741
742
743 /***********************************************************************
744  *           SetMessageQueue16   (USER.266)
745  */
746 BOOL16 WINAPI SetMessageQueue16( INT16 size )
747 {
748     return SetMessageQueue32( size );
749 }
750
751
752 /***********************************************************************
753  *           SetMessageQueue32   (USER32.494)
754  */
755 BOOL32 WINAPI SetMessageQueue32( INT32 size )
756 {
757     HQUEUE16 hQueue, hNewQueue;
758     MESSAGEQUEUE *queuePtr;
759
760     TRACE(msg,"task %04x size %i\n", GetCurrentTask(), size); 
761
762     if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE;
763
764     if( !(hNewQueue = QUEUE_CreateMsgQueue( size ))) 
765     {
766         WARN(msg, "failed!\n");
767         return FALSE;
768     }
769     queuePtr = (MESSAGEQUEUE *)GlobalLock16( hNewQueue );
770
771     SIGNAL_MaskAsyncEvents( TRUE );
772
773     /* Copy data and free the old message queue */
774     if ((hQueue = GetTaskQueue(0)) != 0) 
775     {
776        MESSAGEQUEUE *oldQ = (MESSAGEQUEUE *)GlobalLock16( hQueue );
777        memcpy( &queuePtr->wParamHigh, &oldQ->wParamHigh,
778                         (int)oldQ->messages - (int)(&oldQ->wParamHigh) );
779        HOOK_ResetQueueHooks( hNewQueue );
780        if( WIN_GetDesktop()->hmemTaskQ == hQueue )
781            WIN_GetDesktop()->hmemTaskQ = hNewQueue;
782        WIN_ResetQueueWindows( WIN_GetDesktop(), hQueue, hNewQueue );
783        CLIPBOARD_ResetLock( hQueue, hNewQueue );
784        QUEUE_DeleteMsgQueue( hQueue );
785     }
786
787     /* Link new queue into list */
788     queuePtr->hTask = GetCurrentTask();
789     queuePtr->next  = hFirstQueue;
790     hFirstQueue = hNewQueue;
791     
792     if( !queuePtr->next ) pCursorQueue = queuePtr;
793     SetTaskQueue( 0, hNewQueue );
794     
795     SIGNAL_MaskAsyncEvents( FALSE );
796     return TRUE;
797 }
798
799
800 /***********************************************************************
801  *           GetQueueStatus16   (USER.334)
802  */
803 DWORD WINAPI GetQueueStatus16( UINT16 flags )
804 {
805     MESSAGEQUEUE *queue;
806     DWORD ret;
807
808     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
809     ret = MAKELONG( queue->changeBits, queue->wakeBits );
810     queue->changeBits = 0;
811     return ret & MAKELONG( flags, flags );
812 }
813
814 /***********************************************************************
815  *           GetQueueStatus32   (USER32.283)
816  */
817 DWORD WINAPI GetQueueStatus32( UINT32 flags )
818 {
819     MESSAGEQUEUE *queue;
820     DWORD ret;
821
822     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
823     ret = MAKELONG( queue->changeBits, queue->wakeBits );
824     queue->changeBits = 0;
825     return ret & MAKELONG( flags, flags );
826 }
827
828
829 /***********************************************************************
830  *           GetInputState16   (USER.335)
831  */
832 BOOL16 WINAPI GetInputState16(void)
833 {
834     return GetInputState32();
835 }
836
837 /***********************************************************************
838  *           WaitForInputIdle   (USER32.577)
839  */
840 DWORD WINAPI WaitForInputIdle (HANDLE32 hProcess, DWORD dwTimeOut)
841 {
842   FIXME (msg, "(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut);
843
844   return WAIT_TIMEOUT;
845 }
846
847
848 /***********************************************************************
849  *           GetInputState32   (USER32.244)
850  */
851 BOOL32 WINAPI GetInputState32(void)
852 {
853     MESSAGEQUEUE *queue;
854
855     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) )))
856         return FALSE;
857     return queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
858 }
859
860
861 /***********************************************************************
862  *           GetMessagePos   (USER.119) (USER32.272)
863  */
864 DWORD WINAPI GetMessagePos(void)
865 {
866     MESSAGEQUEUE *queue;
867
868     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
869     return queue->GetMessagePosVal;
870 }
871
872
873 /***********************************************************************
874  *           GetMessageTime   (USER.120) (USER32.273)
875  */
876 LONG WINAPI GetMessageTime(void)
877 {
878     MESSAGEQUEUE *queue;
879
880     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
881     return queue->GetMessageTimeVal;
882 }
883
884
885 /***********************************************************************
886  *           GetMessageExtraInfo   (USER.288) (USER32.271)
887  */
888 LONG WINAPI GetMessageExtraInfo(void)
889 {
890     MESSAGEQUEUE *queue;
891
892     if (!(queue = (MESSAGEQUEUE *)GlobalLock16( GetTaskQueue(0) ))) return 0;
893     return queue->GetMessageExtraInfoVal;
894 }