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);
120 if (Window->MessageQueue != PsGetWin32Thread()->MessageQueue)
122 ExAcquireFastMutex(&Window->MessageQueue->Lock);
123 InsertTailList(&Window->MessageQueue->HardwareMessagesListHead,
124 &Message->ListEntry);
125 ExReleaseFastMutex(&Window->MessageQueue->Lock);
126 KeSetEvent(&Window->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
130 if (hWnd != NULL && Window->Self != hWnd &&
131 !W32kIsChildWindow(hWnd, Window->Self))
136 if (Msg == WM_LBUTTONDOWN || Msg == WM_RBUTTONDOWN || Msg == WM_MBUTTONDOWN)
138 (*MouseClick) = Click = 1;
142 if (W32kGetClassLong(Window, GCL_STYLE) & CS_DBLCLKS ||
143 (*HitTest) != HTCLIENT)
145 if (Msg == ClkMessage &&
146 Window->Self == ClkWnd &&
147 (Message->Msg.time - ClkTime) < 452 &&
148 abs(Message->Msg.pt.x - ClkPos.x) < 2 &&
149 abs(Message->Msg.pt.y - ClkPos.y) < 2)
151 Msg += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
157 *ScreenPoint = Message->Msg.pt;
159 if ((*HitTest) != HTCLIENT)
161 Msg += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
162 Message->Msg.wParam = *HitTest;
166 Point = Message->Msg.pt;
168 Point.x -= Window->ClientRect.left;
169 Point.y -= Window->ClientRect.top;
172 /* FIXME: Check message filter. */
178 ClkTime = Message->Msg.time;
180 ClkWnd = Window->Self;
181 ClkPos = (*ScreenPoint);
190 Message->Msg.hwnd = Window->Self;
191 Message->Msg.message = Msg;
192 Message->Msg.lParam = MAKELONG(Point.x, Point.y);
198 MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND hWnd,
199 UINT FilterLow, UINT FilterHigh, BOOL Remove,
200 PUSER_MESSAGE* Message)
207 PLIST_ENTRY CurrentEntry;
209 PWINDOW_OBJECT DesktopWindow;
211 DesktopWindow = W32kGetWindowObject(W32kGetDesktopWindow());
213 /* Process messages in the message queue itself. */
214 ExAcquireFastMutex(&MessageQueue->Lock);
215 CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink;
216 while (CurrentEntry != &MessageQueue->HardwareMessagesListHead)
218 PUSER_MESSAGE Current =
219 CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
220 CurrentEntry = CurrentEntry->Flink;
221 RemoveEntryList(&Current->ListEntry);
222 if (Current->Msg.message >= WM_MOUSEFIRST &&
223 Current->Msg.message <= WM_MOUSELAST)
225 Accept = MsqTranslateMouseMessage(hWnd, FilterLow, FilterHigh,
227 DesktopWindow, &HitTest,
228 &ScreenPoint, &MouseClick);
231 RemoveEntryList(&Current->ListEntry);
232 ExReleaseFastMutex(&MessageQueue->Lock);
234 W32kReleaseWindowObject(DesktopWindow);
238 CurrentEntry = CurrentEntry->Flink;
240 ExReleaseFastMutex(&MessageQueue->Lock);
242 /* Now try the global queue. */
243 ExAcquireFastMutex(&HardwareMessageQueueLock);
244 /* Transfer all messages from the DPC accessible queue to the main queue. */
245 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
246 while (SystemMessageQueueCount > 0)
248 PUSER_MESSAGE UserMsg;
251 Msg = SystemMessageQueue[SystemMessageQueueHead];
252 SystemMessageQueueHead =
253 (SystemMessageQueueHead + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
254 SystemMessageQueueCount--;
255 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
256 UserMsg = ExAllocatePool(NonPagedPool, sizeof(USER_MESSAGE));
258 InsertTailList(&HardwareMessageQueueHead, &UserMsg->ListEntry);
259 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
261 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
262 HardwareMessageQueueStamp++;
264 /* Process messages in the queue until we find one to return. */
265 CurrentEntry = HardwareMessageQueueHead.Flink;
266 while (CurrentEntry != &HardwareMessageQueueHead)
268 PUSER_MESSAGE Current =
269 CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
270 CurrentEntry = CurrentEntry->Flink;
271 RemoveEntryList(&Current->ListEntry);
272 if (Current->Msg.message >= WM_MOUSEFIRST &&
273 Current->Msg.message <= WM_MOUSELAST)
275 ActiveStamp = HardwareMessageQueueStamp;
276 ExReleaseFastMutex(&HardwareMessageQueueLock);
277 /* Translate the message. */
278 Accept = MsqTranslateMouseMessage(hWnd, FilterLow, FilterHigh,
280 DesktopWindow, &HitTest,
281 &ScreenPoint, &MouseClick);
282 ExAcquireFastMutex(&HardwareMessageQueueLock);
285 /* Check for no more messages in the system queue. */
286 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
287 if (SystemMessageQueueCount == 0 &&
288 IsListEmpty(&HardwareMessageQueueHead))
290 KeClearEvent(&HardwareMessageEvent);
292 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
295 If we aren't removing the message then add it to the private
300 InsertTailList(&MessageQueue->HardwareMessagesListHead,
301 &Current->ListEntry);
303 ExReleaseFastMutex(&HardwareMessageQueueLock);
305 W32kReleaseWindowObject(DesktopWindow);
308 /* If the contents of the queue changed then restart processing. */
309 if (HardwareMessageQueueStamp != ActiveStamp)
311 CurrentEntry = HardwareMessageQueueHead.Flink;
316 /* Check if the system message queue is now empty. */
317 KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql);
318 if (SystemMessageQueueCount == 0 && IsListEmpty(&HardwareMessageQueueHead))
320 KeClearEvent(&HardwareMessageEvent);
322 KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql);
323 ExReleaseFastMutex(&HardwareMessageQueueLock);
329 MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
333 PUSER_MESSAGE Message;
335 if (CurrentFocusMessageQueue == NULL)
340 Msg.hwnd = CurrentFocusMessageQueue->FocusWindow;
344 /* FIXME: Initialize time and point. */
346 Message = MsqCreateMessage(&Msg);
347 MsqPostMessage(CurrentFocusMessageQueue, Message, TRUE);
352 MsqInitializeMessage(PUSER_MESSAGE Message,
355 RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
359 MsqCreateMessage(LPMSG Msg)
361 PUSER_MESSAGE Message;
363 Message = (PUSER_MESSAGE)ExAllocatePool(PagedPool, sizeof(USER_MESSAGE));
369 MsqInitializeMessage(Message, Msg);
375 MsqDestroyMessage(PUSER_MESSAGE Message)
381 MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue)
383 PLIST_ENTRY ListEntry;
384 PUSER_SENT_MESSAGE_NOTIFY Message;
386 while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
388 ExAcquireFastMutex(&MessageQueue->Lock);
389 ListEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
390 Message = CONTAINING_RECORD(ListEntry, USER_SENT_MESSAGE_NOTIFY,
392 ExReleaseFastMutex(&MessageQueue->Lock);
394 W32kCallSentMessageCallback(Message->CompletionCallback,
397 Message->CompletionCallbackContext,
403 MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue)
405 return(!IsListEmpty(&MessageQueue->SentMessagesListHead));
409 MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
411 PUSER_SENT_MESSAGE Message;
414 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage;
416 ExAcquireFastMutex(&MessageQueue->Lock);
417 if (IsListEmpty(&MessageQueue->SentMessagesListHead))
419 ExReleaseFastMutex(&MessageQueue->Lock);
422 Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
423 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
424 ExReleaseFastMutex(&MessageQueue->Lock);
426 /* Call the window procedure. */
427 Result = W32kCallWindowProc(NULL,
429 Message->Msg.message,
431 Message->Msg.lParam);
433 /* Let the sender know the result. */
434 if (Message->Result != NULL)
436 *Message->Result = Result;
439 /* Notify the sender. */
440 if (Message->CompletionEvent != NULL)
442 KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
445 /* Notify the sender if they specified a callback. */
446 if (Message->CompletionCallback != NULL)
448 NotifyMessage = ExAllocatePool(NonPagedPool,
449 sizeof(USER_SENT_MESSAGE_NOTIFY));
450 NotifyMessage->CompletionCallback =
451 Message->CompletionCallback;
452 NotifyMessage->CompletionCallbackContext =
453 Message->CompletionCallbackContext;
454 NotifyMessage->Result = Result;
455 NotifyMessage->hWnd = Message->Msg.hwnd;
456 NotifyMessage->Msg = Message->Msg.message;
457 MsqSendNotifyMessage(Message->CompletionQueue, NotifyMessage);
465 MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
466 PUSER_SENT_MESSAGE_NOTIFY NotifyMessage)
468 ExAcquireFastMutex(&MessageQueue->Lock);
469 InsertTailList(&MessageQueue->NotifyMessagesListHead,
470 &NotifyMessage->ListEntry);
471 ExReleaseFastMutex(&MessageQueue->Lock);
475 MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
476 PUSER_SENT_MESSAGE Message)
478 ExAcquireFastMutex(&MessageQueue->Lock);
479 InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
480 ExReleaseFastMutex(&MessageQueue->Lock);
484 MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, PUSER_MESSAGE Message)
486 ExAcquireFastMutex(&MessageQueue->Lock);
487 InsertTailList(&MessageQueue->PostedMessagesListHead,
488 &Message->ListEntry);
489 KeSetEvent(&MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
490 ExReleaseFastMutex(&MessageQueue->Lock);
494 MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
498 IN UINT MsgFilterLow,
499 IN UINT MsgFilterHigh,
500 OUT PUSER_MESSAGE* Message)
502 PLIST_ENTRY CurrentEntry;
503 PUSER_MESSAGE CurrentMessage;
504 PLIST_ENTRY ListHead;
508 return(MsqPeekHardwareMessage(MessageQueue, Wnd,
509 MsgFilterLow, MsgFilterHigh,
513 ExAcquireFastMutex(&MessageQueue->Lock);
514 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
515 ListHead = &MessageQueue->PostedMessagesListHead;
516 while (CurrentEntry != ListHead)
518 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
520 if ((Wnd == 0 || Wnd == CurrentMessage->Msg.hwnd) &&
521 ((MsgFilterLow == 0 && MsgFilterHigh == 0) ||
522 (MsgFilterLow <= CurrentMessage->Msg.message &&
523 MsgFilterHigh >= CurrentMessage->Msg.message)))
527 RemoveEntryList(&CurrentMessage->ListEntry);
529 ExReleaseFastMutex(&MessageQueue->Lock);
530 *Message = CurrentMessage;
533 CurrentEntry = CurrentEntry->Flink;
535 ExReleaseFastMutex(&MessageQueue->Lock);
540 MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue)
542 PVOID WaitObjects[2] = {&MessageQueue->NewMessages, &HardwareMessageEvent};
543 return(KeWaitForMultipleObjects(2,
554 MsqInitializeMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
556 InitializeListHead(&MessageQueue->PostedMessagesListHead);
557 InitializeListHead(&MessageQueue->SentMessagesListHead);
558 InitializeListHead(&MessageQueue->HardwareMessagesListHead);
559 ExInitializeFastMutex(&MessageQueue->Lock);
560 MessageQueue->QuitPosted = FALSE;
561 MessageQueue->QuitExitCode = 0;
562 KeInitializeEvent(&MessageQueue->NewMessages, NotificationEvent, FALSE);
563 MessageQueue->QueueStatus = 0;
564 MessageQueue->FocusWindow = NULL;
568 MsqFreeMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
570 PLIST_ENTRY CurrentEntry;
571 PUSER_MESSAGE CurrentMessage;
573 CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
574 while (CurrentEntry != &MessageQueue->PostedMessagesListHead)
576 CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
578 CurrentEntry = CurrentEntry->Flink;
579 ExFreePool(CurrentMessage);
584 MsqCreateMessageQueue(VOID)
586 PUSER_MESSAGE_QUEUE MessageQueue;
588 MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePool(PagedPool,
589 sizeof(USER_MESSAGE_QUEUE));
595 MsqInitializeMessageQueue(MessageQueue);
601 MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
603 MsqFreeMessageQueue(MessageQueue);
604 ExFreePool(MessageQueue);