2 * Message queues related functions
4 * Copyright 1993, 1994 Alexandre Julliard
15 #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */
17 static HQUEUE16 hFirstQueue
= 0;
18 static HQUEUE16 hDoomedQueue
= 0;
19 static HQUEUE16 hmemSysMsgQueue
= 0;
20 static MESSAGEQUEUE
*sysMsgQueue
= NULL
;
22 static MESSAGEQUEUE
*pMouseQueue
= NULL
; /* Queue for last mouse message */
23 static MESSAGEQUEUE
*pKbdQueue
= NULL
; /* Queue for last kbd message */
25 MESSAGEQUEUE
*pCursorQueue
= NULL
;
26 MESSAGEQUEUE
*pActiveQueue
= NULL
;
28 /***********************************************************************
31 void QUEUE_DumpQueue( HQUEUE16 hQueue
)
35 if (!(pq
= (MESSAGEQUEUE
*) GlobalLock16( hQueue
)) ||
36 GlobalSize16(hQueue
) < sizeof(MESSAGEQUEUE
)+pq
->queueSize
*sizeof(QMSG
))
38 fprintf( stderr
, "%04x is not a queue handle\n", hQueue
);
43 "next: %12.4x Intertask SendMessage:\n"
44 "hTask: %11.4x ----------------------\n"
45 "msgSize: %9.4x hWnd: %10.4x\n"
46 "msgCount: %8.4x msg: %11.4x\n"
47 "msgNext: %9.4x wParam: %8.4x\n"
48 "msgFree: %9.4x lParam: %8.8x\n"
49 "qSize: %11.4x lRet: %10.8x\n"
50 "wWinVer: %9.4x ISMH: %10.4x\n"
51 "paints: %10.4x hSendTask: %5.4x\n"
52 "timers: %10.4x hPrevSend: %5.4x\n"
56 pq
->next
, pq
->hTask
, pq
->msgSize
, pq
->hWnd
,
57 pq
->msgCount
, pq
->msg
, pq
->nextMessage
, pq
->wParam
,
58 pq
->nextFreeMessage
, (unsigned)pq
->lParam
, pq
->queueSize
,
59 (unsigned)pq
->SendMessageReturn
, pq
->wWinVersion
, pq
->InSendMessageHandle
,
60 pq
->wPaintCount
, pq
->hSendingTask
, pq
->wTimerCount
,
61 pq
->hPrevSendingTask
, pq
->wakeBits
, pq
->wakeMask
, pq
->hCurHook
);
65 /***********************************************************************
68 void QUEUE_WalkQueues(void)
70 HQUEUE16 hQueue
= hFirstQueue
;
72 fprintf( stderr
, "Queue Size Msgs Task\n" );
75 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
78 fprintf( stderr
, "*** Bad queue handle %04x\n", hQueue
);
81 fprintf( stderr
, "%04x %5d %4d %04x %s\n",
82 hQueue
, queue
->msgSize
, queue
->msgCount
, queue
->hTask
,
83 MODULE_GetModuleName( GetExePtr(queue
->hTask
) ) );
86 fprintf( stderr
, "\n" );
90 /***********************************************************************
93 BOOL32
QUEUE_IsDoomedQueue( HQUEUE16 hQueue
)
95 return (hDoomedQueue
&& (hQueue
== hDoomedQueue
));
99 /***********************************************************************
100 * QUEUE_SetDoomedQueue
102 void QUEUE_SetDoomedQueue( HQUEUE16 hQueue
)
104 hDoomedQueue
= hQueue
;
108 /***********************************************************************
109 * QUEUE_CreateMsgQueue
111 * Creates a message queue. Doesn't link it into queue list!
113 static HQUEUE16
QUEUE_CreateMsgQueue( int size
)
116 MESSAGEQUEUE
* msgQueue
;
118 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
120 dprintf_msg(stddeb
,"Creating message queue...\n");
122 queueSize
= sizeof(MESSAGEQUEUE
) + size
* sizeof(QMSG
);
123 if (!(hQueue
= GlobalAlloc16( GMEM_FIXED
| GMEM_ZEROINIT
, queueSize
)))
125 msgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hQueue
);
126 msgQueue
->self
= hQueue
;
127 msgQueue
->msgSize
= sizeof(QMSG
);
128 msgQueue
->queueSize
= size
;
129 msgQueue
->wakeBits
= msgQueue
->changeBits
= QS_SMPARAMSFREE
;
130 msgQueue
->wWinVersion
= pTask
? pTask
->version
: 0;
131 GlobalUnlock16( hQueue
);
136 /***********************************************************************
137 * QUEUE_DeleteMsgQueue
139 * Unlinks and deletes a message queue.
141 BOOL32
QUEUE_DeleteMsgQueue( HQUEUE16 hQueue
)
143 MESSAGEQUEUE
* msgQueue
= (MESSAGEQUEUE
*)GlobalLock16(hQueue
);
147 dprintf_msg(stddeb
,"Deleting message queue %04x\n", hQueue
);
149 if (!hQueue
|| !msgQueue
)
151 dprintf_msg(stddeb
,"DeleteMsgQueue: invalid argument.\n");
154 if( pCursorQueue
== msgQueue
) pCursorQueue
= NULL
;
155 if( pActiveQueue
== msgQueue
) pActiveQueue
= NULL
;
157 /* flush sent messages */
158 senderQ
= msgQueue
->hSendingTask
;
161 MESSAGEQUEUE
* sq
= (MESSAGEQUEUE
*)GlobalLock16(senderQ
);
163 sq
->SendMessageReturn
= 0L;
164 QUEUE_SetWakeBit( sq
, QS_SMRESULT
);
165 senderQ
= sq
->hPrevSendingTask
;
168 pPrev
= &hFirstQueue
;
169 while (*pPrev
&& (*pPrev
!= hQueue
))
171 MESSAGEQUEUE
*msgQ
= (MESSAGEQUEUE
*)GlobalLock16(*pPrev
);
174 if (*pPrev
) *pPrev
= msgQueue
->next
;
176 GlobalFree16( hQueue
);
181 /***********************************************************************
182 * QUEUE_CreateSysMsgQueue
184 * Create the system message queue, and set the double-click speed.
185 * Must be called only once.
187 BOOL32
QUEUE_CreateSysMsgQueue( int size
)
189 if (size
> MAX_QUEUE_SIZE
) size
= MAX_QUEUE_SIZE
;
190 else if (size
<= 0) size
= 1;
191 if (!(hmemSysMsgQueue
= QUEUE_CreateMsgQueue( size
))) return FALSE
;
192 sysMsgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hmemSysMsgQueue
);
197 /***********************************************************************
200 MESSAGEQUEUE
*QUEUE_GetSysQueue(void)
206 /***********************************************************************
209 * See "Windows Internals", p.449
211 void QUEUE_SetWakeBit( MESSAGEQUEUE
*queue
, WORD bit
)
213 dprintf_msg(stddeb
,"SetWakeBit: queue = %04x (wm=%04x), bit = %04x\n",
214 queue
->self
, queue
->wakeMask
, bit
);
216 if (bit
& QS_MOUSE
) pMouseQueue
= queue
;
217 if (bit
& QS_KEY
) pKbdQueue
= queue
;
218 queue
->changeBits
|= bit
;
219 queue
->wakeBits
|= bit
;
220 if (queue
->wakeMask
& bit
)
223 PostEvent( queue
->hTask
);
228 /***********************************************************************
231 void QUEUE_ClearWakeBit( MESSAGEQUEUE
*queue
, WORD bit
)
233 queue
->changeBits
&= ~bit
;
234 queue
->wakeBits
&= ~bit
;
238 /***********************************************************************
241 * See "Windows Internals", p.447
243 void QUEUE_WaitBits( WORD bits
)
247 dprintf_msg(stddeb
,"WaitBits: q %04x waiting for %04x\n", GetTaskQueue(0), bits
);
251 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return;
253 if (queue
->changeBits
& bits
)
255 /* One of the bits is set; we can return */
259 if (queue
->wakeBits
& QS_SENDMESSAGE
)
261 /* Process the sent message immediately */
264 QUEUE_ReceiveMessage( queue
);
265 continue; /* nested sm crux */
268 queue
->wakeMask
= bits
| QS_SENDMESSAGE
;
269 if(queue
->changeBits
& bits
) continue;
271 dprintf_msg(stddeb
,"wb: (%04x) wakeMask is %04x, waiting\n", queue
->self
, queue
->wakeMask
);
278 /***********************************************************************
279 * QUEUE_ReceiveMessage
281 * This routine is called when a sent message is waiting for the queue.
283 void QUEUE_ReceiveMessage( MESSAGEQUEUE
*queue
)
285 MESSAGEQUEUE
*senderQ
= NULL
;
286 HQUEUE16 prevSender
= 0;
287 QSMCTRL
* prevCtrlPtr
= NULL
;
290 dprintf_msg(stddeb
, "ReceiveMessage, queue %04x\n", queue
->self
);
291 if (!(queue
->wakeBits
& QS_SENDMESSAGE
) ||
292 !(senderQ
= (MESSAGEQUEUE
*)GlobalLock16( queue
->hSendingTask
)))
293 { dprintf_msg(stddeb
,"\trcm: nothing to do\n"); return; }
295 queue
->InSendMessageHandle
= queue
->hSendingTask
;
296 if( !(queue
->hSendingTask
= senderQ
->hPrevSendingTask
) )
298 queue
->wakeBits
&= ~QS_SENDMESSAGE
; /* no more sent messages */
299 queue
->changeBits
&= ~QS_SENDMESSAGE
;
302 /* Remove sending queue from the list */
303 prevSender
= queue
->InSendMessageHandle
;
304 prevCtrlPtr
= queue
->smResultCurrent
;
305 queue
->smResultCurrent
= senderQ
->smResultInit
;
307 dprintf_msg(stddeb
, "\trcm: smResultCurrent = %08x, prevCtrl = %08x\n",
308 (unsigned)queue
->smResultCurrent
, (unsigned)prevCtrlPtr
);
309 QUEUE_SetWakeBit( senderQ
, QS_SMPARAMSFREE
);
311 dprintf_msg(stddeb
, "\trcm: calling wndproc - %04x %04x %04x %08x\n",
312 senderQ
->hWnd
, senderQ
->msg
, senderQ
->wParam
, (unsigned)senderQ
->lParam
);
314 if (IsWindow( senderQ
->hWnd
))
316 DWORD extraInfo
= queue
->GetMessageExtraInfoVal
;
317 queue
->GetMessageExtraInfoVal
= senderQ
->GetMessageExtraInfoVal
;
319 result
= CallWindowProc16( (WNDPROC16
)GetWindowLong16(senderQ
->hWnd
, GWL_WNDPROC
),
320 senderQ
->hWnd
, senderQ
->msg
, senderQ
->wParam
, senderQ
->lParam
);
322 queue
->GetMessageExtraInfoVal
= extraInfo
; /* Restore extra info */
323 dprintf_msg(stddeb
,"\trcm: result = %08x\n", (unsigned)result
);
325 else dprintf_msg(stddeb
,"\trcm: bad hWnd\n");
327 /* Return the result to the sender task */
328 ReplyMessage( result
);
330 queue
->InSendMessageHandle
= prevSender
;
331 queue
->smResultCurrent
= prevCtrlPtr
;
333 dprintf_msg(stddeb
,"ReceiveMessage: done!\n");
337 /***********************************************************************
340 * Add a message to the queue. Return FALSE if queue is full.
342 BOOL32
QUEUE_AddMsg( HQUEUE16 hQueue
, MSG16
* msg
, DWORD extraInfo
)
345 MESSAGEQUEUE
*msgQueue
;
347 if (!(msgQueue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return FALSE
;
348 pos
= msgQueue
->nextFreeMessage
;
350 /* Check if queue is full */
351 if ((pos
== msgQueue
->nextMessage
) && (msgQueue
->msgCount
> 0))
353 fprintf(stderr
,"MSG_AddMsg // queue is full !\n");
358 msgQueue
->messages
[pos
].msg
= *msg
;
359 msgQueue
->messages
[pos
].extraInfo
= extraInfo
;
360 if (pos
< msgQueue
->queueSize
-1) pos
++;
362 msgQueue
->nextFreeMessage
= pos
;
363 msgQueue
->msgCount
++;
364 QUEUE_SetWakeBit( msgQueue
, QS_POSTMESSAGE
);
369 /***********************************************************************
372 * Find a message matching the given parameters. Return -1 if none available.
374 int QUEUE_FindMsg( MESSAGEQUEUE
* msgQueue
, HWND32 hwnd
, int first
, int last
)
376 int i
, pos
= msgQueue
->nextMessage
;
378 dprintf_msg(stddeb
,"QUEUE_FindMsg: hwnd=%04x pos=%d\n", hwnd
, pos
);
380 if (!msgQueue
->msgCount
) return -1;
381 if (!hwnd
&& !first
&& !last
) return pos
;
383 for (i
= 0; i
< msgQueue
->msgCount
; i
++)
385 MSG16
* msg
= &msgQueue
->messages
[pos
].msg
;
387 if (!hwnd
|| (msg
->hwnd
== hwnd
))
389 if (!first
&& !last
) return pos
;
390 if ((msg
->message
>= first
) && (msg
->message
<= last
)) return pos
;
392 if (pos
< msgQueue
->queueSize
-1) pos
++;
399 /***********************************************************************
402 * Remove a message from the queue (pos must be a valid position).
404 void QUEUE_RemoveMsg( MESSAGEQUEUE
* msgQueue
, int pos
)
406 if (pos
>= msgQueue
->nextMessage
)
408 for ( ; pos
> msgQueue
->nextMessage
; pos
--)
409 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
-1];
410 msgQueue
->nextMessage
++;
411 if (msgQueue
->nextMessage
>= msgQueue
->queueSize
)
412 msgQueue
->nextMessage
= 0;
416 for ( ; pos
< msgQueue
->nextFreeMessage
; pos
++)
417 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
+1];
418 if (msgQueue
->nextFreeMessage
) msgQueue
->nextFreeMessage
--;
419 else msgQueue
->nextFreeMessage
= msgQueue
->queueSize
-1;
421 msgQueue
->msgCount
--;
422 if (!msgQueue
->msgCount
) msgQueue
->wakeBits
&= ~QS_POSTMESSAGE
;
426 /***********************************************************************
429 * Wake a queue upon reception of a hardware event.
431 static void QUEUE_WakeSomeone( UINT message
)
436 MESSAGEQUEUE
*queue
= pCursorQueue
;
438 if( (message
>= WM_KEYFIRST
) && (message
<= WM_KEYLAST
) )
441 if( pActiveQueue
) queue
= pActiveQueue
;
445 wakeBit
= (message
== WM_MOUSEMOVE
) ? QS_MOUSEMOVE
: QS_MOUSEBUTTON
;
446 if( (hwnd
= GetCapture32()) )
447 if( (wndPtr
= WIN_FindWndPtr( hwnd
)) )
448 queue
= (MESSAGEQUEUE
*)GlobalLock16( wndPtr
->hmemTaskQ
);
451 if( (hwnd
= GetSysModalWindow16()) )
452 if( (wndPtr
= WIN_FindWndPtr( hwnd
)) )
453 queue
= (MESSAGEQUEUE
*)GlobalLock16( wndPtr
->hmemTaskQ
);
457 queue
= GlobalLock16( hFirstQueue
);
460 if (queue
->wakeMask
& wakeBit
) break;
461 queue
= GlobalLock16( queue
->next
);
465 dprintf_msg(stddeb
,"WakeSomeone: couldn't find queue\n");
470 QUEUE_SetWakeBit( queue
, wakeBit
);
474 /***********************************************************************
477 * Add an event to the system message queue.
478 * Note: the position is relative to the desktop window.
480 void hardware_event( WORD message
, WORD wParam
, LONG lParam
,
481 int xPos
, int yPos
, DWORD time
, DWORD extraInfo
)
486 if (!sysMsgQueue
) return;
487 pos
= sysMsgQueue
->nextFreeMessage
;
489 /* Merge with previous event if possible */
491 if ((message
== WM_MOUSEMOVE
) && sysMsgQueue
->msgCount
)
494 else pos
= sysMsgQueue
->queueSize
- 1;
495 msg
= &sysMsgQueue
->messages
[pos
].msg
;
496 if ((msg
->message
== message
) && (msg
->wParam
== wParam
))
497 sysMsgQueue
->msgCount
--; /* Merge events */
499 pos
= sysMsgQueue
->nextFreeMessage
; /* Don't merge */
502 /* Check if queue is full */
504 if ((pos
== sysMsgQueue
->nextMessage
) && sysMsgQueue
->msgCount
)
506 /* Queue is full, beep (but not on every mouse motion...) */
507 if (message
!= WM_MOUSEMOVE
) MessageBeep(0);
513 msg
= &sysMsgQueue
->messages
[pos
].msg
;
515 msg
->message
= message
;
516 msg
->wParam
= wParam
;
517 msg
->lParam
= lParam
;
519 msg
->pt
.x
= xPos
& 0xffff;
520 msg
->pt
.y
= yPos
& 0xffff;
521 sysMsgQueue
->messages
[pos
].extraInfo
= extraInfo
;
522 if (pos
< sysMsgQueue
->queueSize
- 1) pos
++;
524 sysMsgQueue
->nextFreeMessage
= pos
;
525 sysMsgQueue
->msgCount
++;
526 QUEUE_WakeSomeone( message
);
530 /***********************************************************************
533 HTASK16
QUEUE_GetQueueTask( HQUEUE16 hQueue
)
535 MESSAGEQUEUE
*queue
= GlobalLock16( hQueue
);
536 return (queue
) ? queue
->hTask
: 0 ;
540 /***********************************************************************
541 * QUEUE_IncPaintCount
543 void QUEUE_IncPaintCount( HQUEUE16 hQueue
)
547 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
548 queue
->wPaintCount
++;
549 QUEUE_SetWakeBit( queue
, QS_PAINT
);
553 /***********************************************************************
554 * QUEUE_DecPaintCount
556 void QUEUE_DecPaintCount( HQUEUE16 hQueue
)
560 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
561 queue
->wPaintCount
--;
562 if (!queue
->wPaintCount
) queue
->wakeBits
&= ~QS_PAINT
;
566 /***********************************************************************
567 * QUEUE_IncTimerCount
569 void QUEUE_IncTimerCount( HQUEUE16 hQueue
)
573 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
574 queue
->wTimerCount
++;
575 QUEUE_SetWakeBit( queue
, QS_TIMER
);
579 /***********************************************************************
580 * QUEUE_DecTimerCount
582 void QUEUE_DecTimerCount( HQUEUE16 hQueue
)
586 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
587 queue
->wTimerCount
--;
588 if (!queue
->wTimerCount
) queue
->wakeBits
&= ~QS_TIMER
;
592 /***********************************************************************
593 * PostQuitMessage (USER.6)
595 void PostQuitMessage( INT exitCode
)
599 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return;
600 queue
->wPostQMsg
= TRUE
;
601 queue
->wExitCode
= (WORD
)exitCode
;
605 /***********************************************************************
606 * GetWindowTask16 (USER.224)
608 HTASK16
GetWindowTask16( HWND16 hwnd
)
610 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
612 if (!wndPtr
) return 0;
613 return QUEUE_GetQueueTask( wndPtr
->hmemTaskQ
);
617 /***********************************************************************
618 * SetMessageQueue (USER.266)
620 BOOL
SetMessageQueue( int size
)
622 HQUEUE16 hQueue
, hNewQueue
;
623 MESSAGEQUEUE
*queuePtr
;
625 dprintf_msg(stddeb
,"SetMessageQueue: task %04x size %i\n", GetCurrentTask(), size
);
627 if ((size
> MAX_QUEUE_SIZE
) || (size
<= 0)) return TRUE
;
629 if( !(hNewQueue
= QUEUE_CreateMsgQueue( size
)))
631 dprintf_msg(stddeb
,"SetMessageQueue: failed!\n");
634 queuePtr
= (MESSAGEQUEUE
*)GlobalLock16( hNewQueue
);
636 /* Copy data and free the old message queue */
637 if ((hQueue
= GetTaskQueue(0)) != 0)
639 MESSAGEQUEUE
*oldQ
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
640 memcpy( &queuePtr
->reserved2
, &oldQ
->reserved2
,
641 (int)oldQ
->messages
- (int)(&oldQ
->reserved2
) );
642 QUEUE_DeleteMsgQueue( hQueue
);
645 /* Link new queue into list */
646 queuePtr
->hTask
= GetCurrentTask();
647 queuePtr
->next
= hFirstQueue
;
648 hFirstQueue
= hNewQueue
;
650 if( !queuePtr
->next
) pCursorQueue
= queuePtr
;
652 SetTaskQueue( 0, hNewQueue
);
657 /***********************************************************************
658 * GetQueueStatus (USER.334)
660 DWORD
GetQueueStatus( UINT flags
)
665 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
666 ret
= MAKELONG( queue
->changeBits
, queue
->wakeBits
);
667 queue
->changeBits
= 0;
668 return ret
& MAKELONG( flags
, flags
);
672 /***********************************************************************
673 * GetInputState (USER.335)
679 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return FALSE
;
680 return queue
->wakeBits
& (QS_KEY
| QS_MOUSEBUTTON
);
684 /***********************************************************************
685 * GetMessagePos (USER.119)
687 DWORD
GetMessagePos(void)
691 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
692 return queue
->GetMessagePosVal
;
696 /***********************************************************************
697 * GetMessageTime (USER.120)
699 LONG
GetMessageTime(void)
703 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
704 return queue
->GetMessageTimeVal
;
708 /***********************************************************************
709 * GetMessageExtraInfo (USER.288)
711 LONG
GetMessageExtraInfo(void)
715 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
716 return queue
->GetMessageExtraInfoVal
;