msgqueue.c
来自「一个类似windows」· C语言 代码 · 共 1,894 行 · 第 1/5 页
C
1,894 行
/*
* ReactOS W32 Subsystem
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: msgqueue.c 21292 2006-03-11 23:50:04Z jimtabor $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Message queues
* FILE: subsys/win32k/ntuser/msgqueue.c
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* REVISION HISTORY:
* 06-06-2001 CSH Created
*/
/* INCLUDES ******************************************************************/
#include <w32k.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
#define SYSTEM_MESSAGE_QUEUE_SIZE (256)
static MSG SystemMessageQueue[SYSTEM_MESSAGE_QUEUE_SIZE];
static ULONG SystemMessageQueueHead = 0;
static ULONG SystemMessageQueueTail = 0;
static ULONG SystemMessageQueueCount = 0;
static KSPIN_LOCK SystemMessageQueueLock;
static ULONG volatile HardwareMessageQueueStamp = 0;
static LIST_ENTRY HardwareMessageQueueHead;
static KMUTANT HardwareMessageQueueLock;
static KEVENT HardwareMessageEvent;
static PAGED_LOOKASIDE_LIST MessageLookasideList;
static PAGED_LOOKASIDE_LIST TimerLookasideList;
#define IntLockSystemMessageQueue(OldIrql) \
KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql)
#define IntUnLockSystemMessageQueue(OldIrql) \
KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql)
#define IntUnLockSystemHardwareMessageQueueLock(Wait) \
KeReleaseMutant(&HardwareMessageQueueLock, IO_NO_INCREMENT, FALSE, Wait)
/* FUNCTIONS *****************************************************************/
HANDLE FASTCALL
IntMsqSetWakeMask(DWORD WakeMask)
{
PW32THREAD Win32Thread;
PUSER_MESSAGE_QUEUE MessageQueue;
HANDLE MessageEventHandle;
Win32Thread = PsGetWin32Thread();
if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
return 0;
MessageQueue = Win32Thread->MessageQueue;
MessageQueue->WakeMask = WakeMask;
MessageEventHandle = MessageQueue->NewMessagesHandle;
return MessageEventHandle;
}
BOOL FASTCALL
IntMsqClearWakeMask(VOID)
{
PW32THREAD Win32Thread;
PUSER_MESSAGE_QUEUE MessageQueue;
Win32Thread = PsGetWin32Thread();
if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
return FALSE;
MessageQueue = Win32Thread->MessageQueue;
MessageQueue->WakeMask = ~0;
return TRUE;
}
VOID FASTCALL
MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
{
Queue->PaintCount++;
Queue->QueueBits |= QS_PAINT;
Queue->ChangedBits |= QS_PAINT;
if (Queue->WakeMask & QS_PAINT)
KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE);
}
VOID FASTCALL
MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
{
Queue->PaintCount--;
}
NTSTATUS FASTCALL
MsqInitializeImpl(VOID)
{
/*CurrentFocusMessageQueue = NULL;*/
InitializeListHead(&HardwareMessageQueueHead);
KeInitializeEvent(&HardwareMessageEvent, NotificationEvent, 0);
KeInitializeSpinLock(&SystemMessageQueueLock);
KeInitializeMutant(&HardwareMessageQueueLock, 0);
ExInitializePagedLookasideList(&MessageLookasideList,
NULL,
NULL,
0,
sizeof(USER_MESSAGE),
0,
256);
ExInitializePagedLookasideList(&TimerLookasideList,
NULL,
NULL,
0,
sizeof(TIMER_ENTRY),
0,
64);
return(STATUS_SUCCESS);
}
VOID FASTCALL
MsqInsertSystemMessage(MSG* Msg)
{
LARGE_INTEGER LargeTickCount;
KIRQL OldIrql;
ULONG Prev;
IntLockSystemMessageQueue(OldIrql);
/*
* Bail out if the queue is full. FIXME: We should handle this case
* more gracefully.
*/
if (SystemMessageQueueCount == SYSTEM_MESSAGE_QUEUE_SIZE)
{
IntUnLockSystemMessageQueue(OldIrql);
return;
}
KeQueryTickCount(&LargeTickCount);
Msg->time = LargeTickCount.u.LowPart;
/*
* If we got WM_MOUSEMOVE and there are already messages in the
* system message queue, check if the last message is mouse move
* and if it is then just overwrite it.
*/
if (Msg->message == WM_MOUSEMOVE && SystemMessageQueueCount)
{
if (SystemMessageQueueTail == 0)
Prev = SYSTEM_MESSAGE_QUEUE_SIZE - 1;
else
Prev = SystemMessageQueueTail - 1;
if (SystemMessageQueue[Prev].message == WM_MOUSEMOVE)
{
SystemMessageQueueTail = Prev;
SystemMessageQueueCount--;
}
}
/*
* Actually insert the message into the system message queue.
*/
SystemMessageQueue[SystemMessageQueueTail] = *Msg;
SystemMessageQueueTail =
(SystemMessageQueueTail + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
SystemMessageQueueCount++;
IntUnLockSystemMessageQueue(OldIrql);
KeSetEvent(&HardwareMessageEvent, IO_NO_INCREMENT, FALSE);
}
BOOL FASTCALL
MsqIsDblClk(LPMSG Msg, BOOL Remove)
{
PWINSTATION_OBJECT WinStaObject;
PSYSTEM_CURSORINFO CurInfo;
LONG dX, dY;
BOOL Res;
if (PsGetWin32Thread()->Desktop == NULL)
{
return FALSE;
}
WinStaObject = PsGetWin32Thread()->Desktop->WindowStation;
CurInfo = IntGetSysCursorInfo(WinStaObject);
Res = (Msg->hwnd == (HWND)CurInfo->LastClkWnd) &&
((Msg->time - CurInfo->LastBtnDown) < CurInfo->DblClickSpeed);
if(Res)
{
dX = CurInfo->LastBtnDownX - Msg->pt.x;
dY = CurInfo->LastBtnDownY - Msg->pt.y;
if(dX < 0)
dX = -dX;
if(dY < 0)
dY = -dY;
Res = (dX <= CurInfo->DblClickWidth) &&
(dY <= CurInfo->DblClickHeight);
if(Res)
{
if(CurInfo->ButtonsDown)
Res = (CurInfo->ButtonsDown == Msg->message);
}
}
if(Remove)
{
if (Res)
{
CurInfo->LastBtnDown = 0;
CurInfo->LastBtnDownX = Msg->pt.x;
CurInfo->LastBtnDownY = Msg->pt.y;
CurInfo->LastClkWnd = NULL;
CurInfo->ButtonsDown = Msg->message;
}
else
{
CurInfo->LastBtnDownX = Msg->pt.x;
CurInfo->LastBtnDownY = Msg->pt.y;
CurInfo->LastClkWnd = (HANDLE)Msg->hwnd;
CurInfo->LastBtnDown = Msg->time;
CurInfo->ButtonsDown = Msg->message;
}
}
return Res;
}
BOOL static STDCALL
co_MsqTranslateMouseMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND hWnd, UINT FilterLow, UINT FilterHigh,
PUSER_MESSAGE Message, BOOL Remove, PBOOL Freed,
PWINDOW_OBJECT ScopeWin, PPOINT ScreenPoint, BOOL FromGlobalQueue)
{
USHORT Msg = Message->Msg.message;
PWINDOW_OBJECT Window = NULL;
HWND hCaptureWin;
ASSERT_REFS_CO(ScopeWin);
/*
co_WinPosWindowFromPoint can return a Window, and in that case
that window has a ref that we need to deref. Thats why we add "dummy"
refs in all other cases.
*/
hCaptureWin = IntGetCaptureWindow();
if (hCaptureWin == NULL)
{
if(Msg == WM_MOUSEWHEEL)
{
Window = UserGetWindowObject(IntGetFocusWindow());
if (Window) UserRefObject(Window);
}
else
{
co_WinPosWindowFromPoint(ScopeWin, NULL, &Message->Msg.pt, &Window);
if(Window == NULL)
{
Window = ScopeWin;
if (Window) UserRefObject(Window);
}
else
{
/* this is the one case where we dont add a ref, since the returned
window is already referenced */
}
}
}
else
{
/* FIXME - window messages should go to the right window if no buttons are
pressed */
Window = UserGetWindowObject(hCaptureWin);
if (Window) UserRefObject(Window);
}
if (Window == NULL)
{
if(!FromGlobalQueue)
{
RemoveEntryList(&Message->ListEntry);
if(MessageQueue->MouseMoveMsg == Message)
{
MessageQueue->MouseMoveMsg = NULL;
}
}
ExFreePool(Message);
*Freed = TRUE;
return(FALSE);
}
if (Window->MessageQueue != MessageQueue)
{
if (! FromGlobalQueue)
{
DPRINT("Moving msg between private queues\n");
/* This message is already queued in a private queue, but we need
* to move it to a different queue, perhaps because a new window
* was created which now covers the screen area previously taken
* by another window. To move it, we need to take it out of the
* old queue. Note that we're already holding the lock mutexes of the
* old queue */
RemoveEntryList(&Message->ListEntry);
/* remove the pointer for the current WM_MOUSEMOVE message in case we
just removed it */
if(MessageQueue->MouseMoveMsg == Message)
{
MessageQueue->MouseMoveMsg = NULL;
}
}
/* lock the destination message queue, so we don't get in trouble with other
threads, messing with it at the same time */
IntLockHardwareMessageQueue(Window->MessageQueue);
InsertTailList(&Window->MessageQueue->HardwareMessagesListHead,
&Message->ListEntry);
if(Message->Msg.message == WM_MOUSEMOVE)
{
if(Window->MessageQueue->MouseMoveMsg)
{
/* remove the old WM_MOUSEMOVE message, we're processing a more recent
one */
RemoveEntryList(&Window->MessageQueue->MouseMoveMsg->ListEntry);
ExFreePool(Window->MessageQueue->MouseMoveMsg);
}
/* save the pointer to the WM_MOUSEMOVE message in the new queue */
Window->MessageQueue->MouseMoveMsg = Message;
Window->MessageQueue->QueueBits |= QS_MOUSEMOVE;
Window->MessageQueue->ChangedBits |= QS_MOUSEMOVE;
if (Window->MessageQueue->WakeMask & QS_MOUSEMOVE)
KeSetEvent(Window->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
}
else
{
Window->MessageQueue->QueueBits |= QS_MOUSEBUTTON;
Window->MessageQueue->ChangedBits |= QS_MOUSEBUTTON;
if (Window->MessageQueue->WakeMask & QS_MOUSEBUTTON)
KeSetEvent(Window->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
}
IntUnLockHardwareMessageQueue(Window->MessageQueue);
*Freed = FALSE;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?