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 hmemSysMsgQueue
= 0;
19 static MESSAGEQUEUE
*pMouseQueue
= NULL
; /* Queue for last mouse message */
20 static MESSAGEQUEUE
*pKbdQueue
= NULL
; /* Queue for last kbd message */
21 static HQUEUE16 hDoomedQueue
= 0;
22 static MESSAGEQUEUE
*sysMsgQueue
= NULL
;
24 /***********************************************************************
27 void QUEUE_DumpQueue( HQUEUE16 hQueue
)
31 if (!(pq
= (MESSAGEQUEUE
*) GlobalLock16( hQueue
)) ||
32 GlobalSize16(hQueue
) < sizeof(MESSAGEQUEUE
)+pq
->queueSize
*sizeof(QMSG
))
34 fprintf( stderr
, "%04x is not a queue handle\n", hQueue
);
39 "next: %12.4x Intertask SendMessage:\n"
40 "hTask: %11.4x ----------------------\n"
41 "msgSize: %9.4x hWnd: %10.4x\n"
42 "msgCount: %8.4x msg: %11.4x\n"
43 "msgNext: %9.4x wParam: %8.4x\n"
44 "msgFree: %9.4x lParam: %8.8x\n"
45 "qSize: %11.4x lRet: %10.8x\n"
46 "wWinVer: %9.4x ISMH: %10.4x\n"
47 "paints: %10.4x hSendTask: %5.4x\n"
48 "timers: %10.4x hPrevSend: %5.4x\n"
52 pq
->next
, pq
->hTask
, pq
->msgSize
, pq
->hWnd
,
53 pq
->msgCount
, pq
->msg
, pq
->nextMessage
, pq
->wParam
,
54 pq
->nextFreeMessage
, (unsigned)pq
->lParam
, pq
->queueSize
,
55 (unsigned)pq
->SendMessageReturn
, pq
->wWinVersion
, pq
->InSendMessageHandle
,
56 pq
->wPaintCount
, pq
->hSendingTask
, pq
->wTimerCount
,
57 pq
->hPrevSendingTask
, pq
->wakeBits
, pq
->wakeMask
, pq
->hCurHook
);
61 /***********************************************************************
64 void QUEUE_WalkQueues(void)
66 HQUEUE16 hQueue
= hFirstQueue
;
68 fprintf( stderr
, "Queue Size Msgs Task\n" );
71 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
74 fprintf( stderr
, "*** Bad queue handle %04x\n", hQueue
);
77 fprintf( stderr
, "%04x %5d %4d %04x %s\n",
78 hQueue
, queue
->msgSize
, queue
->msgCount
, queue
->hTask
,
79 MODULE_GetModuleName( GetExePtr(queue
->hTask
) ) );
82 fprintf( stderr
, "\n" );
86 /***********************************************************************
89 BOOL32
QUEUE_IsDoomedQueue( HQUEUE16 hQueue
)
91 return (hDoomedQueue
&& (hQueue
== hDoomedQueue
));
95 /***********************************************************************
96 * QUEUE_SetDoomedQueue
98 void QUEUE_SetDoomedQueue( HQUEUE16 hQueue
)
100 hDoomedQueue
= hQueue
;
104 /***********************************************************************
105 * QUEUE_CreateMsgQueue
107 * Creates a message queue. Doesn't link it into queue list!
109 static HQUEUE16
QUEUE_CreateMsgQueue( int size
)
112 MESSAGEQUEUE
* msgQueue
;
114 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
116 dprintf_msg(stddeb
,"Creating message queue...\n");
118 queueSize
= sizeof(MESSAGEQUEUE
) + size
* sizeof(QMSG
);
119 if (!(hQueue
= GlobalAlloc16( GMEM_FIXED
| GMEM_ZEROINIT
, queueSize
)))
121 msgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hQueue
);
122 msgQueue
->self
= hQueue
;
123 msgQueue
->msgSize
= sizeof(QMSG
);
124 msgQueue
->queueSize
= size
;
125 msgQueue
->wWinVersion
= pTask
? pTask
->version
: 0;
126 GlobalUnlock16( hQueue
);
131 /***********************************************************************
132 * QUEUE_DeleteMsgQueue
134 * Unlinks and deletes a message queue.
136 BOOL32
QUEUE_DeleteMsgQueue( HQUEUE16 hQueue
)
138 MESSAGEQUEUE
* msgQueue
= (MESSAGEQUEUE
*)GlobalLock16(hQueue
);
141 dprintf_msg(stddeb
,"Deleting message queue %04x\n", hQueue
);
143 if (!hQueue
|| !msgQueue
)
145 dprintf_msg(stddeb
,"DeleteMsgQueue: invalid argument.\n");
149 pPrev
= &hFirstQueue
;
150 while (*pPrev
&& (*pPrev
!= hQueue
))
152 MESSAGEQUEUE
*msgQ
= (MESSAGEQUEUE
*)GlobalLock16(*pPrev
);
155 if (*pPrev
) *pPrev
= msgQueue
->next
;
157 GlobalFree16( hQueue
);
162 /***********************************************************************
163 * QUEUE_CreateSysMsgQueue
165 * Create the system message queue, and set the double-click speed.
166 * Must be called only once.
168 BOOL32
QUEUE_CreateSysMsgQueue( int size
)
170 if (size
> MAX_QUEUE_SIZE
) size
= MAX_QUEUE_SIZE
;
171 else if (size
<= 0) size
= 1;
172 if (!(hmemSysMsgQueue
= QUEUE_CreateMsgQueue( size
))) return FALSE
;
173 sysMsgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hmemSysMsgQueue
);
178 /***********************************************************************
181 MESSAGEQUEUE
*QUEUE_GetSysQueue(void)
187 /***********************************************************************
190 * See "Windows Internals", p.449
192 void QUEUE_SetWakeBit( MESSAGEQUEUE
*queue
, WORD bit
)
194 if (bit
& QS_MOUSE
) pMouseQueue
= queue
;
195 if (bit
& QS_KEY
) pKbdQueue
= queue
;
196 queue
->changeBits
|= bit
;
197 queue
->wakeBits
|= bit
;
198 if (queue
->wakeMask
& bit
)
201 PostEvent( queue
->hTask
);
206 /***********************************************************************
209 void QUEUE_ClearWakeBit( MESSAGEQUEUE
*queue
, WORD bit
)
211 queue
->changeBits
&= ~bit
;
212 queue
->wakeBits
&= ~bit
;
216 /***********************************************************************
219 * See "Windows Internals", p.447
221 void QUEUE_WaitBits( WORD bits
)
227 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return;
228 if (queue
->changeBits
& bits
)
230 /* One of the bits is set; we can return */
234 if (queue
->wakeBits
& QS_SENDMESSAGE
)
236 /* Process the sent message immediately */
237 QUEUE_ReceiveMessage( queue
);
239 queue
->wakeMask
= bits
| QS_SENDMESSAGE
;
245 /***********************************************************************
246 * QUEUE_ReceiveMessage
248 * This routine is called when a sent message is waiting for the queue.
250 void QUEUE_ReceiveMessage( MESSAGEQUEUE
*queue
)
252 MESSAGEQUEUE
*senderQ
;
260 printf( "ReceiveMessage\n" );
261 if (!(queue
->wakeBits
& QS_SENDMESSAGE
)) return;
262 if (!(senderQ
= (MESSAGEQUEUE
*)GlobalLock16( queue
->hSendingTask
))) return;
264 /* Remove sending queue from the list */
265 oldSender
= queue
->InSendMessageHandle
;
266 queue
->InSendMessageHandle
= queue
->hSendingTask
;
267 queue
->hSendingTask
= senderQ
->hPrevSendingTask
;
268 senderQ
->hPrevSendingTask
= 0;
269 if (!queue
->hSendingTask
)
271 queue
->wakeBits
&= ~QS_SENDMESSAGE
;
272 queue
->changeBits
&= ~QS_SENDMESSAGE
;
275 /* Get the parameters from the sending task */
276 hwnd
= senderQ
->hWnd
;
278 wParam
= senderQ
->wParam
;
279 lParam
= senderQ
->lParam
;
281 QUEUE_SetWakeBit( senderQ
, QS_SMPARAMSFREE
);
283 printf( "ReceiveMessage: calling wnd proc %04x %04x %04x %08x\n",
284 hwnd
, msg
, wParam
, lParam
);
286 /* Call the window procedure */
287 /* FIXME: should we use CallWindowProc here? */
288 if (IsWindow( hwnd
))
290 DWORD extraInfo
= queue
->GetMessageExtraInfoVal
;
291 queue
->GetMessageExtraInfoVal
= senderQ
->GetMessageExtraInfoVal
;
292 result
= SendMessage16( hwnd
, msg
, wParam
, lParam
);
293 queue
->GetMessageExtraInfoVal
= extraInfo
; /* Restore extra info */
296 printf( "ReceiveMessage: wnd proc %04x %04x %04x %08x ret = %08x\n",
297 hwnd
, msg
, wParam
, lParam
, result
);
299 /* Return the result to the sender task */
300 ReplyMessage( result
);
302 queue
->InSendMessageHandle
= oldSender
;
306 /***********************************************************************
309 * Add a message to the queue. Return FALSE if queue is full.
311 BOOL32
QUEUE_AddMsg( HQUEUE16 hQueue
, MSG16
* msg
, DWORD extraInfo
)
314 MESSAGEQUEUE
*msgQueue
;
316 if (!(msgQueue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return FALSE
;
317 pos
= msgQueue
->nextFreeMessage
;
319 /* Check if queue is full */
320 if ((pos
== msgQueue
->nextMessage
) && (msgQueue
->msgCount
> 0))
322 fprintf(stderr
,"MSG_AddMsg // queue is full !\n");
327 msgQueue
->messages
[pos
].msg
= *msg
;
328 msgQueue
->messages
[pos
].extraInfo
= extraInfo
;
329 if (pos
< msgQueue
->queueSize
-1) pos
++;
331 msgQueue
->nextFreeMessage
= pos
;
332 msgQueue
->msgCount
++;
333 QUEUE_SetWakeBit( msgQueue
, QS_POSTMESSAGE
);
338 /***********************************************************************
341 * Find a message matching the given parameters. Return -1 if none available.
343 int QUEUE_FindMsg( MESSAGEQUEUE
* msgQueue
, HWND32 hwnd
, int first
, int last
)
345 int i
, pos
= msgQueue
->nextMessage
;
347 dprintf_msg(stddeb
,"QUEUE_FindMsg: hwnd=%04x pos=%d\n", hwnd
, pos
);
349 if (!msgQueue
->msgCount
) return -1;
350 if (!hwnd
&& !first
&& !last
) return pos
;
352 for (i
= 0; i
< msgQueue
->msgCount
; i
++)
354 MSG16
* msg
= &msgQueue
->messages
[pos
].msg
;
356 if (!hwnd
|| (msg
->hwnd
== hwnd
))
358 if (!first
&& !last
) return pos
;
359 if ((msg
->message
>= first
) && (msg
->message
<= last
)) return pos
;
361 if (pos
< msgQueue
->queueSize
-1) pos
++;
368 /***********************************************************************
371 * Remove a message from the queue (pos must be a valid position).
373 void QUEUE_RemoveMsg( MESSAGEQUEUE
* msgQueue
, int pos
)
375 if (pos
>= msgQueue
->nextMessage
)
377 for ( ; pos
> msgQueue
->nextMessage
; pos
--)
378 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
-1];
379 msgQueue
->nextMessage
++;
380 if (msgQueue
->nextMessage
>= msgQueue
->queueSize
)
381 msgQueue
->nextMessage
= 0;
385 for ( ; pos
< msgQueue
->nextFreeMessage
; pos
++)
386 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
+1];
387 if (msgQueue
->nextFreeMessage
) msgQueue
->nextFreeMessage
--;
388 else msgQueue
->nextFreeMessage
= msgQueue
->queueSize
-1;
390 msgQueue
->msgCount
--;
391 if (!msgQueue
->msgCount
) msgQueue
->wakeBits
&= ~QS_POSTMESSAGE
;
395 /***********************************************************************
398 * Wake a queue upon reception of a hardware event.
400 static void QUEUE_WakeSomeone( UINT message
)
405 MESSAGEQUEUE
*queue
= NULL
;
407 if ((message
>= WM_KEYFIRST
) && (message
<= WM_KEYLAST
)) wakeBit
= QS_KEY
;
408 else wakeBit
= (message
== WM_MOUSEMOVE
) ? QS_MOUSEMOVE
: QS_MOUSEBUTTON
;
410 if (!(hwnd
= GetSysModalWindow16()))
412 if (wakeBit
== QS_KEY
)
414 if (!(hwnd
= GetFocus())) hwnd
= GetActiveWindow();
416 else hwnd
= GetCapture();
420 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
421 if (wndPtr
) queue
= (MESSAGEQUEUE
*)GlobalLock16( wndPtr
->hmemTaskQ
);
423 else if (!(queue
= pMouseQueue
))
425 hQueue
= hFirstQueue
;
428 queue
= GlobalLock16( hQueue
);
429 if (queue
->wakeBits
& wakeBit
) break;
430 hQueue
= queue
->next
;
433 if (!queue
) printf( "WakeSomeone: no one found\n" );
434 if (queue
) QUEUE_SetWakeBit( queue
, wakeBit
);
438 /***********************************************************************
441 * Add an event to the system message queue.
442 * Note: the position is relative to the desktop window.
444 void hardware_event( WORD message
, WORD wParam
, LONG lParam
,
445 int xPos
, int yPos
, DWORD time
, DWORD extraInfo
)
450 if (!sysMsgQueue
) return;
451 pos
= sysMsgQueue
->nextFreeMessage
;
453 /* Merge with previous event if possible */
455 if ((message
== WM_MOUSEMOVE
) && sysMsgQueue
->msgCount
)
458 else pos
= sysMsgQueue
->queueSize
- 1;
459 msg
= &sysMsgQueue
->messages
[pos
].msg
;
460 if ((msg
->message
== message
) && (msg
->wParam
== wParam
))
461 sysMsgQueue
->msgCount
--; /* Merge events */
463 pos
= sysMsgQueue
->nextFreeMessage
; /* Don't merge */
466 /* Check if queue is full */
468 if ((pos
== sysMsgQueue
->nextMessage
) && sysMsgQueue
->msgCount
)
470 /* Queue is full, beep (but not on every mouse motion...) */
471 if (message
!= WM_MOUSEMOVE
) MessageBeep(0);
477 msg
= &sysMsgQueue
->messages
[pos
].msg
;
479 msg
->message
= message
;
480 msg
->wParam
= wParam
;
481 msg
->lParam
= lParam
;
483 msg
->pt
.x
= xPos
& 0xffff;
484 msg
->pt
.y
= yPos
& 0xffff;
485 sysMsgQueue
->messages
[pos
].extraInfo
= extraInfo
;
486 if (pos
< sysMsgQueue
->queueSize
- 1) pos
++;
488 sysMsgQueue
->nextFreeMessage
= pos
;
489 sysMsgQueue
->msgCount
++;
490 QUEUE_WakeSomeone( message
);
494 /***********************************************************************
497 HTASK16
QUEUE_GetQueueTask( HQUEUE16 hQueue
)
499 MESSAGEQUEUE
*queue
= GlobalLock16( hQueue
);
500 return (queue
) ? queue
->hTask
: 0 ;
504 /***********************************************************************
505 * QUEUE_IncPaintCount
507 void QUEUE_IncPaintCount( HQUEUE16 hQueue
)
511 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
512 queue
->wPaintCount
++;
513 QUEUE_SetWakeBit( queue
, QS_PAINT
);
517 /***********************************************************************
518 * QUEUE_DecPaintCount
520 void QUEUE_DecPaintCount( HQUEUE16 hQueue
)
524 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
525 queue
->wPaintCount
--;
526 if (!queue
->wPaintCount
) queue
->wakeBits
&= ~QS_PAINT
;
530 /***********************************************************************
531 * QUEUE_IncTimerCount
533 void QUEUE_IncTimerCount( HQUEUE16 hQueue
)
537 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
538 queue
->wTimerCount
++;
539 QUEUE_SetWakeBit( queue
, QS_TIMER
);
543 /***********************************************************************
544 * QUEUE_DecTimerCount
546 void QUEUE_DecTimerCount( HQUEUE16 hQueue
)
550 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
551 queue
->wTimerCount
--;
552 if (!queue
->wTimerCount
) queue
->wakeBits
&= ~QS_TIMER
;
556 /***********************************************************************
557 * PostQuitMessage (USER.6)
559 void PostQuitMessage( INT exitCode
)
563 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return;
564 queue
->wPostQMsg
= TRUE
;
565 queue
->wExitCode
= (WORD
)exitCode
;
569 /***********************************************************************
570 * GetWindowTask16 (USER.224)
572 HTASK16
GetWindowTask16( HWND16 hwnd
)
574 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
576 if (!wndPtr
) return 0;
577 return QUEUE_GetQueueTask( wndPtr
->hmemTaskQ
);
581 /***********************************************************************
582 * SetMessageQueue (USER.266)
584 BOOL
SetMessageQueue( int size
)
586 HQUEUE16 hQueue
, hNewQueue
;
587 MESSAGEQUEUE
*queuePtr
;
589 dprintf_msg(stddeb
,"SetMessageQueue: task %04x size %i\n", GetCurrentTask(), size
);
591 if ((size
> MAX_QUEUE_SIZE
) || (size
<= 0)) return TRUE
;
593 if( !(hNewQueue
= QUEUE_CreateMsgQueue( size
)))
595 dprintf_msg(stddeb
,"SetMessageQueue: failed!\n");
599 /* Free the old message queue */
600 if ((hQueue
= GetTaskQueue(0)) != 0) QUEUE_DeleteMsgQueue( hQueue
);
602 /* Link new queue into list */
603 queuePtr
= (MESSAGEQUEUE
*)GlobalLock16( hNewQueue
);
604 queuePtr
->hTask
= GetCurrentTask();
605 queuePtr
->next
= hFirstQueue
;
606 hFirstQueue
= hNewQueue
;
608 SetTaskQueue( 0, hNewQueue
);
613 /***********************************************************************
614 * GetQueueStatus (USER.334)
616 DWORD
GetQueueStatus( UINT flags
)
621 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
622 ret
= MAKELONG( queue
->changeBits
, queue
->wakeBits
);
623 queue
->changeBits
= 0;
624 return ret
& MAKELONG( flags
, flags
);
628 /***********************************************************************
629 * GetInputState (USER.335)
635 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return FALSE
;
636 return queue
->wakeBits
& (QS_KEY
| QS_MOUSEBUTTON
);
640 /***********************************************************************
641 * GetMessagePos (USER.119)
643 DWORD
GetMessagePos(void)
647 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
648 return queue
->GetMessagePosVal
;
652 /***********************************************************************
653 * GetMessageTime (USER.120)
655 LONG
GetMessageTime(void)
659 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
660 return queue
->GetMessageTimeVal
;
664 /***********************************************************************
665 * GetMessageExtraInfo (USER.288)
667 LONG
GetMessageExtraInfo(void)
671 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
672 return queue
->GetMessageExtraInfoVal
;