3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * PURPOSE: Message queues
6 * FILE: subsys/win32k/ntuser/msgqueue.c
7 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * 06-06-2001 CSH Created
12 /* INCLUDES ******************************************************************/
14 #include <ddk/ntddk.h>
15 #include <win32k/win32k.h>
16 #include <include/msgqueue.h>
17 #include <include/callback.h>
18 #include <include/window.h>
19 #include <include/winpos.h>
20 #include <include/class.h>
25 /* GLOBALS *******************************************************************/
27 #define SYSTEM_MESSAGE_QUEUE_SIZE (256)
29 static MSG SystemMessageQueue[SYSTEM_MESSAGE_QUEUE_SIZE];
30 static ULONG SystemMessageQueueHead = 0;
31 static ULONG SystemMessageQueueTail = 0;
32 static ULONG SystemMessageQueueCount = 0;
33 static KSPIN_LOCK SystemMessageQueueLock;
35 static ULONG HardwareMessageQueueStamp = 0;
36 static LIST_ENTRY HardwareMessageQueueHead;
37 static FAST_MUTEX HardwareMessageQueueLock;
39 static KEVENT HardwareMessageEvent;
41 /* FUNCTIONS *****************************************************************/
44 MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
46 ExAcquireFastMutex(&Queue->Lock);
48 Queue->PaintPosted = TRUE;
49 ExReleaseFastMutex(&Queue->Lock);
53 MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
55 ExAcquireFastMutex(&Queue->Lock);
57 if (Queue->PaintCount == 0)
59 Queue->PaintPosted = FALSE;
61 ExReleaseFastMutex(&Queue->Lock);
66 MsqInitializeImpl(VOID)
68 /*CurrentFocusMessageQueue = NULL;*/
69 InitializeListHead(&HardwareMessageQueueHead);
70 KeInitializeEvent(&HardwareMessageEvent, NotificationEvent, 0);
71 KeInitializeSpinLock(&SystemMessageQueueLock);
72 ExInitializeFastMutex(&HardwareMessageQueueLock);
73 return(STATUS_SUCCESS);
77 MsqInsertSystemMessage(MSG* Msg)
81 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
82 if (SystemMessageQueueCount == SYSTEM_MESSAGE_QUEUE_SIZE)
84 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
87 SystemMessageQueue[SystemMessageQueueTail] = *Msg;
88 SystemMessageQueueTail =
89 (SystemMessageQueueTail + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
90 SystemMessageQueueCount++;
91 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
92 KeSetEvent(&HardwareMessageEvent, IO_NO_INCREMENT, FALSE);
96 MsqTranslateMouseMessage(HWND hWnd, UINT FilterLow, UINT FilterHigh,
97 PUSER_MESSAGE Message, BOOL Remove,
98 PWINDOW_OBJECT ScopeWin, PUSHORT HitTest,
99 PPOINT ScreenPoint, PBOOL MouseClick)
101 static ULONG ClkTime = 0;
102 static USHORT ClkMessage = 0;
103 static HWND ClkWnd = 0;
104 static POINT ClkPos = {0, 0};
106 USHORT Msg = Message->Msg.message;
107 PWINDOW_OBJECT Window;
111 /* FIXME: Handle window capture. */
113 *HitTest = WinPosWindowFromPoint(ScopeWin, Message->Msg.pt, &Window);
115 if (Window->MessageQueue != PsGetWin32Thread()->MessageQueue)
117 ExAcquireFastMutex(&Window->MessageQueue->Lock);
118 InsertTailList(&Window->MessageQueue->HardwareMessagesListHead,
119 &Message->ListEntry);
120 ExReleaseFastMutex(&Window->MessageQueue->Lock);
121 KeSetEvent(&Window->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
125 if (hWnd != NULL && Window->Self != hWnd &&
126 !W32kIsChildWindow(hWnd, Window->Self))
131 if (Msg == WM_LBUTTONDOWN || Msg == WM_RBUTTONDOWN || Msg == WM_MBUTTONDOWN)
133 (*MouseClick) = Click = 1;
137 if (W32kGetClassLong(Window, GCL_STYLE) & CS_DBLCLKS ||
138 (*HitTest) != HTCLIENT)
140 if (Msg == ClkMessage &&
141 Window->Self == ClkWnd &&
142 (Message->Msg.time - ClkTime) < 452 &&
143 abs(Message->Msg.pt.x - ClkPos.x) < 2 &&
144 abs(Message->Msg.pt.y - ClkPos.y) < 2)
146 Msg += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
152 *ScreenPoint = Message->Msg.pt;
154 if ((*HitTest) != HTCLIENT)
156 Msg += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
157 Message->Msg.wParam = *HitTest;
161 Point = Message->Msg.pt;
163 Point.x -= Window->ClientRect.left;
164 Point.y -= Window->ClientRect.top;
167 /* FIXME: Check message filter. */
173 ClkTime = Message->Msg.time;
175 ClkWnd = Window->Self;
176 ClkPos = (*ScreenPoint);
185 Message->Msg.hwnd = Window->Self;
186 Message->Msg.message = Msg;
187 Message->Msg.lParam = MAKELONG(Point.x, Point.y);
193 MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND hWnd,
194 UINT FilterLow, UINT FilterHigh, BOOL Remove,
195 PUSER_MESSAGE* Message)
202 PLIST_ENTRY CurrentEntry;
204 PWINDOW_OBJECT DesktopWindow;
206 DesktopWindow = W32kGetWindowObject(W32kGetDesktopWindow());
208 /* Process messages in the message queue itself. */
209 ExAcquireFastMutex(&MessageQueue->Lock);
210 CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink;
211 while (CurrentEntry != &MessageQueue->HardwareMessagesListHead)
213 PUSER_MESSAGE Current =
214 CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
215 CurrentEntry = CurrentEntry->Flink;
216 RemoveEntryList(&Current->ListEntry);
217 if (Current->Msg.message >= WM_MOUSEFIRST &&
218 Current->Msg.message <= WM_MOUSELAST)
220 Accept = MsqTranslateMouseMessage(hWnd, FilterLow, FilterHigh,
222 DesktopWindow, &HitTest,
223 &ScreenPoint, &MouseClick);
226 RemoveEntryList(&Current->ListEntry);
227 ExReleaseFastMutex(&MessageQueue->Lock);
229 W32kReleaseWindowObject(DesktopWindow);
233 CurrentEntry = CurrentEntry->Flink;
235 ExReleaseFastMutex(&MessageQueue->Lock);
237 /* Now try the global queue. */
238 ExAcquireFastMutex(&HardwareMessageQueueLock);
239 /* Transfer all messages from the DPC accessible queue to the main queue. */
240 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
241 while (SystemMessageQueueCount > 0)
243 PUSER_MESSAGE UserMsg;
246 Msg = SystemMessageQueue[SystemMessageQueueHead];
247 SystemMessageQueueHead =
248 (SystemMessageQueueHead + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
249 SystemMessageQueueCount--;
250 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
251 UserMsg = ExAllocatePool(NonPagedPool, sizeof(USER_MESSAGE));
253 InsertTailList(&HardwareMessageQueueHead, &UserMsg->ListEntry);
254 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
256 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
257 HardwareMessageQueueStamp++;
259 /* Process messages in the queue until we find one to return. */
260 CurrentEntry = HardwareMessageQueueHead.Flink;
261 while (CurrentEntry != &HardwareMessageQueueHead)
263 PUSER_MESSAGE Current =
264 CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
265 CurrentEntry = CurrentEntry->Flink;
266 RemoveEntryList(&Current->ListEntry);
267 if (Current->Msg.message >= WM_MOUSEFIRST &&
268 Current->Msg.message <= WM_MOUSELAST)
270 ActiveStamp = HardwareMessageQueueStamp;
271 ExReleaseFastMutex(&HardwareMessageQueueLock);
272 /* Translate the message. */
273 Accept = MsqTranslateMouseMessage(hWnd, FilterLow, FilterHigh,
275 DesktopWindow, &HitTest,
276 &ScreenPoint, &MouseClick);
277 ExAcquireFastMutex(&HardwareMessageQueueLock);
280 /* Check for no more messages in the system queue. */
281 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
282 if (SystemMessageQueueCount == 0 &&
283 IsListEmpty(&HardwareMessageQueueHead))
285 KeClearEvent(&HardwareMessageEvent);
287 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
290 If we aren't removing the message then add it to the private
295 InsertTailList(&MessageQueue->HardwareMessagesListHead,
296 &Current->ListEntry);
298 ExReleaseFastMutex(&HardwareMessageQueueLock);
300 W32kReleaseWindowObject(DesktopWindow);
303 /* If the contents of the queue changed then restart processing. */
304 if (HardwareMessageQueueStamp != ActiveStamp)
306 CurrentEntry = HardwareMessageQueueHead.Flink;
311 /* Check if the system message queue is now empty. */
312 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
313 if (SystemMessageQueueCount == 0 && IsListEmpty(&HardwareMessageQueueHead))
315 KeClearEvent(&HardwareMessageEvent);
317 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
318 ExReleaseFastMutex(&HardwareMessageQueueLock);
324 MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
328 PUSER_MESSAGE Message;
330 if (CurrentFocusMessageQueue == NULL)
335 Msg.hwnd = CurrentFocusMessageQueue->FocusWindow;
339 /* FIXME: Initialize time and point. */
341 Message = MsqCreateMessage(&Msg);
342 MsqPostMessage(CurrentFocusMessageQueue, Message, TRUE);
347 MsqInitializeMessage(PUSER_MESSAGE Message,
350 RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
354 MsqCreateMessage(LPMSG Msg)
356 PUSER_MESSAGE Message;
358 Message = (PUSER_MESSAGE)ExAllocatePool(PagedPool, sizeof(USER_MESSAGE));
364 MsqInitializeMessage(Message, Msg);
370 MsqDestroyMessage(PUSER_MESSAGE Message)
376 MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue)
378 PLIST_ENTRY ListEntry;
379 PUSER_SENT_MESSAGE_NOTIFY Message;
381 while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
383 ExAcquireFastMutex(&MessageQueue->Lock);
384 ListEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
385 Message = CONTAINING_RECORD(ListEntry, USER_SENT_MESSAGE_NOTIFY,
387 ExReleaseFastMutex(&MessageQueue->Lock);
389 W32kCallSentMessageCallback(Message->CompletionCallback,
392 Message->CompletionCallbackContext,
398 MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue)
400 return(!IsListEmpty(&MessageQueue->SentMessagesListHead));
404 MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
406 PUSER_SENT_MESSAGE Message;
409 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage;
411 ExAcquireFastMutex(&MessageQueue->Lock);
412 if (IsListEmpty(&MessageQueue->SentMessagesListHead))
414 ExReleaseFastMutex(&MessageQueue->Lock);
417 Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
418 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
419 ExReleaseFastMutex(&MessageQueue->Lock);
421 /* Call the window procedure. */
422 Result = W32kCallWindowProc(NULL,
424 Message->Msg.message,
426 Message->Msg.lParam);
428 /* Let the sender know the result. */
429 if (Message->Result != NULL)
431 *Message->Result = Result;
434 /* Notify the sender. */
435 if (Message->CompletionEvent != NULL)
437 KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
440 /* Notify the sender if they specified a callback. */
441 if (Message->CompletionCallback != NULL)
443 NotifyMessage = ExAllocatePool(NonPagedPool,
444 sizeof(USER_SENT_MESSAGE_NOTIFY));
445 NotifyMessage->CompletionCallback =
446 Message->CompletionCallback;
447 NotifyMessage->CompletionCallbackContext =
448 Message->CompletionCallbackContext;
449 NotifyMessage->Result = Result;
450 NotifyMessage->hWnd = Message->Msg.hwnd;
451 NotifyMessage->Msg = Message->Msg.message;
452 MsqSendNotifyMessage(Message->CompletionQueue, NotifyMessage);
460 MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
461 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage)
463 ExAcquireFastMutex(&MessageQueue->Lock);
464 InsertTailList(&MessageQueue->NotifyMessagesListHead,
465 &NotifyMessage->ListEntry);
466 ExReleaseFastMutex(&MessageQueue->Lock);
470 MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
471 PUSER_SENT_MESSAGE Message)
473 ExAcquireFastMutex(&MessageQueue->Lock);
474 InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
475 ExReleaseFastMutex(&MessageQueue->Lock);
479 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, PUSER_MESSAGE Message)
481 ExAcquireFastMutex(&MessageQueue->Lock);
482 InsertTailList(&MessageQueue->PostedMessagesListHead,
483 &Message->ListEntry);
484 KeSetEvent(&MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
485 ExReleaseFastMutex(&MessageQueue->Lock);
489 MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
493 IN UINT MsgFilterLow,
494 IN UINT MsgFilterHigh,
495 OUT PUSER_MESSAGE* Message)
497 PLIST_ENTRY CurrentEntry;
498 PUSER_MESSAGE CurrentMessage;
499 PLIST_ENTRY ListHead;
503 return(MsqPeekHardwareMessage(MessageQueue, Wnd,
504 MsgFilterLow, MsgFilterHigh,
508 ExAcquireFastMutex(&MessageQueue->Lock);
509 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
510 ListHead = &MessageQueue->PostedMessagesListHead;
511 while (CurrentEntry != ListHead)
513 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
515 if ((Wnd == 0 || Wnd == CurrentMessage->Msg.hwnd) &&
516 ((MsgFilterLow == 0 && MsgFilterHigh == 0) ||
517 (MsgFilterLow <= CurrentMessage->Msg.message &&
518 MsgFilterHigh >= CurrentMessage->Msg.message)))
522 RemoveEntryList(&CurrentMessage->ListEntry);
524 ExReleaseFastMutex(&MessageQueue->Lock);
525 *Message = CurrentMessage;
528 CurrentEntry = CurrentEntry->Flink;
530 ExReleaseFastMutex(&MessageQueue->Lock);
535 MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue)
537 PVOID WaitObjects[2] = {&MessageQueue->NewMessages, &HardwareMessageEvent};
538 return(KeWaitForMultipleObjects(2,
549 MsqInitializeMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
551 InitializeListHead(&MessageQueue->PostedMessagesListHead);
552 InitializeListHead(&MessageQueue->SentMessagesListHead);
553 InitializeListHead(&MessageQueue->HardwareMessagesListHead);
554 ExInitializeFastMutex(&MessageQueue->Lock);
555 MessageQueue->QuitPosted = FALSE;
556 MessageQueue->QuitExitCode = 0;
557 KeInitializeEvent(&MessageQueue->NewMessages, NotificationEvent, FALSE);
558 MessageQueue->QueueStatus = 0;
559 MessageQueue->FocusWindow = NULL;
563 MsqFreeMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
565 PLIST_ENTRY CurrentEntry;
566 PUSER_MESSAGE CurrentMessage;
568 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
569 while (CurrentEntry != &MessageQueue->PostedMessagesListHead)
571 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
573 CurrentEntry = CurrentEntry->Flink;
574 ExFreePool(CurrentMessage);
579 MsqCreateMessageQueue(VOID)
581 PUSER_MESSAGE_QUEUE MessageQueue;
583 MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePool(PagedPool,
584 sizeof(USER_MESSAGE_QUEUE));
590 MsqInitializeMessageQueue(MessageQueue);
596 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
598 MsqFreeMessageQueue(MessageQueue);
599 ExFreePool(MessageQueue);