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 HQUEUE hFirstQueue
= 0;
18 static HQUEUE hmemSysMsgQueue
= 0;
19 static MESSAGEQUEUE
*pMouseQueue
= NULL
; /* Queue for last mouse message */
20 static MESSAGEQUEUE
*pKbdQueue
= NULL
; /* Queue for last kbd message */
21 static HQUEUE hDoomedQueue
= 0;
22 static MESSAGEQUEUE
*sysMsgQueue
= NULL
;
24 /***********************************************************************
25 * QUEUE_GetDoomedQueue/QUEUE_SetDoomedQueue
27 HQUEUE
QUEUE_GetDoomedQueue()
31 void QUEUE_SetDoomedQueue(HQUEUE hQueue
)
33 hDoomedQueue
= hQueue
;
36 /***********************************************************************
39 void QUEUE_DumpQueue( HQUEUE hQueue
)
43 if (!(pq
= (MESSAGEQUEUE
*) GlobalLock16( hQueue
)) ||
44 GlobalSize16(hQueue
) < sizeof(MESSAGEQUEUE
)+pq
->queueSize
*sizeof(QMSG
))
46 fprintf( stderr
, "%04x is not a queue handle\n", hQueue
);
51 "next: %12.4x Intertask SendMessage:\n"
52 "hTask: %11.4x ----------------------\n"
53 "msgSize: %9.4x hWnd: %10.4x\n"
54 "msgCount: %8.4x msg: %11.4x\n"
55 "msgNext: %9.4x wParam: %8.4x\n"
56 "msgFree: %9.4x lParam: %8.8x\n"
57 "qSize: %11.4x lRet: %10.8x\n"
58 "wWinVer: %9.4x ISMH: %10.4x\n"
59 "paints: %10.4x hSendTask: %5.4x\n"
60 "timers: %10.4x hPrevSend: %5.4x\n"
64 pq
->next
, pq
->hTask
, pq
->msgSize
, pq
->hWnd
,
65 pq
->msgCount
, pq
->msg
, pq
->nextMessage
, pq
->wParam
,
66 pq
->nextFreeMessage
, (unsigned)pq
->lParam
, pq
->queueSize
,
67 (unsigned)pq
->SendMessageReturn
, pq
->wWinVersion
, pq
->InSendMessageHandle
,
68 pq
->wPaintCount
, pq
->hSendingTask
, pq
->wTimerCount
,
69 pq
->hPrevSendingTask
, pq
->wakeBits
, pq
->wakeMask
, pq
->hCurHook
);
73 /***********************************************************************
76 void QUEUE_WalkQueues(void)
78 HQUEUE hQueue
= hFirstQueue
;
80 fprintf( stderr
, "Queue Size Msgs Task\n" );
83 MESSAGEQUEUE
*queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
);
86 fprintf( stderr
, "*** Bad queue handle %04x\n", hQueue
);
89 fprintf( stderr
, "%04x %5d %4d %04x %s\n",
90 hQueue
, queue
->msgSize
, queue
->msgCount
, queue
->hTask
,
91 MODULE_GetModuleName( GetExePtr(queue
->hTask
) ) );
94 fprintf( stderr
, "\n" );
98 /***********************************************************************
99 * QUEUE_CreateMsgQueue
101 * Creates a message queue. Doesn't link it into queue list!
103 static HQUEUE
QUEUE_CreateMsgQueue( int size
)
106 MESSAGEQUEUE
* msgQueue
;
108 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
110 dprintf_msg(stddeb
,"Creating message queue...\n");
112 queueSize
= sizeof(MESSAGEQUEUE
) + size
* sizeof(QMSG
);
113 if (!(hQueue
= GlobalAlloc16( GMEM_FIXED
| GMEM_ZEROINIT
, queueSize
)))
115 msgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hQueue
);
116 msgQueue
->self
= hQueue
;
117 msgQueue
->msgSize
= sizeof(QMSG
);
118 msgQueue
->queueSize
= size
;
119 msgQueue
->wWinVersion
= pTask
? pTask
->version
: 0;
120 GlobalUnlock16( hQueue
);
125 /***********************************************************************
126 * QUEUE_DeleteMsgQueue
128 * Unlinks and deletes a message queue.
130 BOOL
QUEUE_DeleteMsgQueue( HQUEUE hQueue
)
132 MESSAGEQUEUE
* msgQueue
= (MESSAGEQUEUE
*)GlobalLock16(hQueue
);
135 dprintf_msg(stddeb
,"Deleting message queue %04x\n", hQueue
);
137 if (!hQueue
|| !msgQueue
)
139 dprintf_msg(stddeb
,"DeleteMsgQueue: invalid argument.\n");
143 pPrev
= &hFirstQueue
;
144 while (*pPrev
&& (*pPrev
!= hQueue
))
146 MESSAGEQUEUE
*msgQ
= (MESSAGEQUEUE
*)GlobalLock16(*pPrev
);
149 if (*pPrev
) *pPrev
= msgQueue
->next
;
151 GlobalFree16( hQueue
);
156 /***********************************************************************
157 * QUEUE_CreateSysMsgQueue
159 * Create the system message queue, and set the double-click speed.
160 * Must be called only once.
162 BOOL
QUEUE_CreateSysMsgQueue( int size
)
164 if (size
> MAX_QUEUE_SIZE
) size
= MAX_QUEUE_SIZE
;
165 else if (size
<= 0) size
= 1;
166 if (!(hmemSysMsgQueue
= QUEUE_CreateMsgQueue( size
))) return FALSE
;
167 sysMsgQueue
= (MESSAGEQUEUE
*) GlobalLock16( hmemSysMsgQueue
);
172 /***********************************************************************
175 MESSAGEQUEUE
*QUEUE_GetSysQueue(void)
181 /***********************************************************************
184 * See "Windows Internals", p.449
186 void QUEUE_SetWakeBit( MESSAGEQUEUE
*queue
, WORD bit
)
188 if (bit
& QS_MOUSE
) pMouseQueue
= queue
;
189 if (bit
& QS_KEY
) pKbdQueue
= queue
;
190 queue
->changeBits
|= bit
;
191 queue
->wakeBits
|= bit
;
192 if (queue
->wakeMask
& bit
)
195 PostEvent( queue
->hTask
);
200 /***********************************************************************
203 void QUEUE_ClearWakeBit( MESSAGEQUEUE
*queue
, WORD bit
)
205 queue
->changeBits
&= ~bit
;
206 queue
->wakeBits
&= ~bit
;
210 /***********************************************************************
213 * See "Windows Internals", p.447
215 void QUEUE_WaitBits( WORD bits
)
221 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return;
222 if (queue
->changeBits
& bits
)
224 /* One of the bits is set; we can return */
228 if (queue
->wakeBits
& QS_SENDMESSAGE
)
230 /* Process the sent message immediately */
231 QUEUE_ReceiveMessage( queue
);
233 queue
->wakeMask
= bits
| QS_SENDMESSAGE
;
239 /***********************************************************************
240 * QUEUE_ReceiveMessage
242 * This routine is called when a sent message is waiting for the queue.
244 void QUEUE_ReceiveMessage( MESSAGEQUEUE
*queue
)
246 MESSAGEQUEUE
*senderQ
;
254 printf( "ReceiveMessage\n" );
255 if (!(queue
->wakeBits
& QS_SENDMESSAGE
)) return;
256 if (!(senderQ
= (MESSAGEQUEUE
*)GlobalLock16( queue
->hSendingTask
))) return;
258 /* Remove sending queue from the list */
259 oldSender
= queue
->InSendMessageHandle
;
260 queue
->InSendMessageHandle
= queue
->hSendingTask
;
261 queue
->hSendingTask
= senderQ
->hPrevSendingTask
;
262 senderQ
->hPrevSendingTask
= 0;
263 if (!queue
->hSendingTask
)
265 queue
->wakeBits
&= ~QS_SENDMESSAGE
;
266 queue
->changeBits
&= ~QS_SENDMESSAGE
;
269 /* Get the parameters from the sending task */
270 hwnd
= senderQ
->hWnd
;
272 wParam
= senderQ
->wParam
;
273 lParam
= senderQ
->lParam
;
275 QUEUE_SetWakeBit( senderQ
, QS_SMPARAMSFREE
);
277 printf( "ReceiveMessage: calling wnd proc %04x %04x %04x %08x\n",
278 hwnd
, msg
, wParam
, lParam
);
280 /* Call the window procedure */
281 /* FIXME: should we use CallWindowProc here? */
282 if (IsWindow( hwnd
))
284 DWORD extraInfo
= queue
->GetMessageExtraInfoVal
;
285 queue
->GetMessageExtraInfoVal
= senderQ
->GetMessageExtraInfoVal
;
286 result
= SendMessage16( hwnd
, msg
, wParam
, lParam
);
287 queue
->GetMessageExtraInfoVal
= extraInfo
; /* Restore extra info */
290 printf( "ReceiveMessage: wnd proc %04x %04x %04x %08x ret = %08x\n",
291 hwnd
, msg
, wParam
, lParam
, result
);
293 /* Return the result to the sender task */
294 ReplyMessage( result
);
296 queue
->InSendMessageHandle
= oldSender
;
300 /***********************************************************************
303 * Add a message to the queue. Return FALSE if queue is full.
305 BOOL
QUEUE_AddMsg( HQUEUE hQueue
, MSG16
* msg
, DWORD extraInfo
)
308 MESSAGEQUEUE
*msgQueue
;
310 if (!(msgQueue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return FALSE
;
311 pos
= msgQueue
->nextFreeMessage
;
313 /* Check if queue is full */
314 if ((pos
== msgQueue
->nextMessage
) && (msgQueue
->msgCount
> 0))
316 fprintf(stderr
,"MSG_AddMsg // queue is full !\n");
321 msgQueue
->messages
[pos
].msg
= *msg
;
322 msgQueue
->messages
[pos
].extraInfo
= extraInfo
;
323 if (pos
< msgQueue
->queueSize
-1) pos
++;
325 msgQueue
->nextFreeMessage
= pos
;
326 msgQueue
->msgCount
++;
327 QUEUE_SetWakeBit( msgQueue
, QS_POSTMESSAGE
);
332 /***********************************************************************
335 * Find a message matching the given parameters. Return -1 if none available.
337 int QUEUE_FindMsg( MESSAGEQUEUE
* msgQueue
, HWND hwnd
, int first
, int last
)
339 int i
, pos
= msgQueue
->nextMessage
;
341 dprintf_msg(stddeb
,"QUEUE_FindMsg: hwnd=%04x pos=%d\n", hwnd
, pos
);
343 if (!msgQueue
->msgCount
) return -1;
344 if (!hwnd
&& !first
&& !last
) return pos
;
346 for (i
= 0; i
< msgQueue
->msgCount
; i
++)
348 MSG16
* msg
= &msgQueue
->messages
[pos
].msg
;
350 if (!hwnd
|| (msg
->hwnd
== hwnd
))
352 if (!first
&& !last
) return pos
;
353 if ((msg
->message
>= first
) && (msg
->message
<= last
)) return pos
;
355 if (pos
< msgQueue
->queueSize
-1) pos
++;
362 /***********************************************************************
365 * Remove a message from the queue (pos must be a valid position).
367 void QUEUE_RemoveMsg( MESSAGEQUEUE
* msgQueue
, int pos
)
369 if (pos
>= msgQueue
->nextMessage
)
371 for ( ; pos
> msgQueue
->nextMessage
; pos
--)
372 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
-1];
373 msgQueue
->nextMessage
++;
374 if (msgQueue
->nextMessage
>= msgQueue
->queueSize
)
375 msgQueue
->nextMessage
= 0;
379 for ( ; pos
< msgQueue
->nextFreeMessage
; pos
++)
380 msgQueue
->messages
[pos
] = msgQueue
->messages
[pos
+1];
381 if (msgQueue
->nextFreeMessage
) msgQueue
->nextFreeMessage
--;
382 else msgQueue
->nextFreeMessage
= msgQueue
->queueSize
-1;
384 msgQueue
->msgCount
--;
385 if (!msgQueue
->msgCount
) msgQueue
->wakeBits
&= ~QS_POSTMESSAGE
;
389 /***********************************************************************
392 * Wake a queue upon reception of a hardware event.
394 static void QUEUE_WakeSomeone( UINT message
)
399 MESSAGEQUEUE
*queue
= NULL
;
401 if ((message
>= WM_KEYFIRST
) && (message
<= WM_KEYLAST
)) wakeBit
= QS_KEY
;
402 else wakeBit
= (message
== WM_MOUSEMOVE
) ? QS_MOUSEMOVE
: QS_MOUSEBUTTON
;
404 if (!(hwnd
= GetSysModalWindow()))
406 if (wakeBit
== QS_KEY
)
408 if (!(hwnd
= GetFocus())) hwnd
= GetActiveWindow();
410 else hwnd
= GetCapture();
414 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
415 if (wndPtr
) queue
= (MESSAGEQUEUE
*)GlobalLock16( wndPtr
->hmemTaskQ
);
417 else if (!(queue
= pMouseQueue
))
419 hQueue
= hFirstQueue
;
422 queue
= GlobalLock16( hQueue
);
423 if (queue
->wakeBits
& wakeBit
) break;
424 hQueue
= queue
->next
;
427 if (!queue
) printf( "WakeSomeone: no one found\n" );
428 if (queue
) QUEUE_SetWakeBit( queue
, wakeBit
);
432 /***********************************************************************
435 * Add an event to the system message queue.
436 * Note: the position is relative to the desktop window.
438 void hardware_event( WORD message
, WORD wParam
, LONG lParam
,
439 int xPos
, int yPos
, DWORD time
, DWORD extraInfo
)
444 if (!sysMsgQueue
) return;
445 pos
= sysMsgQueue
->nextFreeMessage
;
447 /* Merge with previous event if possible */
449 if ((message
== WM_MOUSEMOVE
) && sysMsgQueue
->msgCount
)
452 else pos
= sysMsgQueue
->queueSize
- 1;
453 msg
= &sysMsgQueue
->messages
[pos
].msg
;
454 if ((msg
->message
== message
) && (msg
->wParam
== wParam
))
455 sysMsgQueue
->msgCount
--; /* Merge events */
457 pos
= sysMsgQueue
->nextFreeMessage
; /* Don't merge */
460 /* Check if queue is full */
462 if ((pos
== sysMsgQueue
->nextMessage
) && sysMsgQueue
->msgCount
)
464 /* Queue is full, beep (but not on every mouse motion...) */
465 if (message
!= WM_MOUSEMOVE
) MessageBeep(0);
471 msg
= &sysMsgQueue
->messages
[pos
].msg
;
473 msg
->message
= message
;
474 msg
->wParam
= wParam
;
475 msg
->lParam
= lParam
;
477 msg
->pt
.x
= xPos
& 0xffff;
478 msg
->pt
.y
= yPos
& 0xffff;
479 sysMsgQueue
->messages
[pos
].extraInfo
= extraInfo
;
480 if (pos
< sysMsgQueue
->queueSize
- 1) pos
++;
482 sysMsgQueue
->nextFreeMessage
= pos
;
483 sysMsgQueue
->msgCount
++;
484 QUEUE_WakeSomeone( message
);
488 /***********************************************************************
491 HTASK
QUEUE_GetQueueTask( HQUEUE hQueue
)
493 MESSAGEQUEUE
*queue
= GlobalLock16( hQueue
);
494 return (queue
) ? queue
->hTask
: 0 ;
498 /***********************************************************************
499 * QUEUE_IncPaintCount
501 void QUEUE_IncPaintCount( HQUEUE hQueue
)
505 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
506 queue
->wPaintCount
++;
507 QUEUE_SetWakeBit( queue
, QS_PAINT
);
511 /***********************************************************************
512 * QUEUE_DecPaintCount
514 void QUEUE_DecPaintCount( HQUEUE hQueue
)
518 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
519 queue
->wPaintCount
--;
520 if (!queue
->wPaintCount
) queue
->wakeBits
&= ~QS_PAINT
;
524 /***********************************************************************
525 * QUEUE_IncTimerCount
527 void QUEUE_IncTimerCount( HQUEUE hQueue
)
531 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
532 queue
->wTimerCount
++;
533 QUEUE_SetWakeBit( queue
, QS_TIMER
);
537 /***********************************************************************
538 * QUEUE_DecTimerCount
540 void QUEUE_DecTimerCount( HQUEUE hQueue
)
544 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( hQueue
))) return;
545 queue
->wTimerCount
--;
546 if (!queue
->wTimerCount
) queue
->wakeBits
&= ~QS_TIMER
;
550 /***********************************************************************
551 * PostQuitMessage (USER.6)
553 void PostQuitMessage( INT exitCode
)
557 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return;
558 queue
->wPostQMsg
= TRUE
;
559 queue
->wExitCode
= (WORD
)exitCode
;
563 /***********************************************************************
564 * GetWindowTask (USER.224)
566 HTASK
GetWindowTask( HWND hwnd
)
568 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
570 if (!wndPtr
) return 0;
571 return QUEUE_GetQueueTask( wndPtr
->hmemTaskQ
);
575 /***********************************************************************
576 * SetMessageQueue (USER.266)
578 BOOL
SetMessageQueue( int size
)
580 HQUEUE hQueue
, hNewQueue
;
581 MESSAGEQUEUE
*queuePtr
;
583 dprintf_msg(stddeb
,"SetMessageQueue: task %04x size %i\n", GetCurrentTask(), size
);
585 if ((size
> MAX_QUEUE_SIZE
) || (size
<= 0)) return TRUE
;
587 if( !(hNewQueue
= QUEUE_CreateMsgQueue( size
)))
589 dprintf_msg(stddeb
,"SetMessageQueue: failed!\n");
593 /* Free the old message queue */
594 if ((hQueue
= GetTaskQueue(0)) != 0) QUEUE_DeleteMsgQueue( hQueue
);
596 /* Link new queue into list */
597 queuePtr
= (MESSAGEQUEUE
*)GlobalLock16( hNewQueue
);
598 queuePtr
->hTask
= GetCurrentTask();
599 queuePtr
->next
= hFirstQueue
;
600 hFirstQueue
= hNewQueue
;
602 SetTaskQueue( 0, hNewQueue
);
607 /***********************************************************************
608 * GetQueueStatus (USER.334)
610 DWORD
GetQueueStatus( UINT flags
)
615 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
616 ret
= MAKELONG( queue
->changeBits
, queue
->wakeBits
);
617 queue
->changeBits
= 0;
618 return ret
& MAKELONG( flags
, flags
);
622 /***********************************************************************
623 * GetInputState (USER.335)
629 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return FALSE
;
630 return queue
->wakeBits
& (QS_KEY
| QS_MOUSEBUTTON
);
634 /***********************************************************************
635 * GetMessagePos (USER.119)
637 DWORD
GetMessagePos(void)
641 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
642 return queue
->GetMessagePosVal
;
646 /***********************************************************************
647 * GetMessageTime (USER.120)
649 LONG
GetMessageTime(void)
653 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
654 return queue
->GetMessageTimeVal
;
658 /***********************************************************************
659 * GetMessageExtraInfo (USER.288)
661 LONG
GetMessageExtraInfo(void)
665 if (!(queue
= (MESSAGEQUEUE
*)GlobalLock16( GetTaskQueue(0) ))) return 0;
666 return queue
->GetMessageExtraInfoVal
;