📄 window.c
字号:
/*
* 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.
*/
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Windows
* FILE: subsys/win32k/ntuser/window.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>
/* dialog resources appear to pass this in 16 bits, handle them properly */
#define CW_USEDEFAULT16 (0x8000)
#define POINT_IN_RECT(p, r) (((r.bottom >= p.y) && (r.top <= p.y))&&((r.left <= p.x )&&( r.right >= p.x )))
/* PRIVATE FUNCTIONS **********************************************************/
/*
* InitWindowImpl
*
* Initialize windowing implementation.
*/
NTSTATUS FASTCALL
InitWindowImpl(VOID)
{
return STATUS_SUCCESS;
}
/*
* CleanupWindowImpl
*
* Cleanup windowing implementation.
*/
NTSTATUS FASTCALL
CleanupWindowImpl(VOID)
{
return STATUS_SUCCESS;
}
/* HELPER FUNCTIONS ***********************************************************/
PWINDOW_OBJECT FASTCALL IntGetWindowObject(HWND hWnd)
{
PWINDOW_OBJECT Window;
if (!hWnd) return NULL;
Window = UserGetWindowObject(hWnd);
if (Window)
{
ASSERT(USER_BODY_TO_HEADER(Window)->RefCount >= 0);
USER_BODY_TO_HEADER(Window)->RefCount++;
}
return Window;
}
/* temp hack */
PWINDOW_OBJECT FASTCALL UserGetWindowObject(HWND hWnd)
{
PW32THREADINFO ti;
PWINDOW_OBJECT Window;
if (PsGetCurrentProcess() != PsInitialSystemProcess)
{
ti = GetW32ThreadInfo();
if (ti == NULL)
{
SetLastWin32Error(ERROR_ACCESS_DENIED);
return NULL;
}
}
if (!hWnd)
{
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
return NULL;
}
Window = (PWINDOW_OBJECT)UserGetObject(gHandleTable, hWnd, otWindow);
if (!Window || 0 != (Window->Status & WINDOWSTATUS_DESTROYED))
{
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
return NULL;
}
ASSERT(USER_BODY_TO_HEADER(Window)->RefCount >= 0);
return Window;
}
/*
* IntIsWindow
*
* The function determines whether the specified window handle identifies
* an existing window.
*
* Parameters
* hWnd
* Handle to the window to test.
*
* Return Value
* If the window handle identifies an existing window, the return value
* is TRUE. If the window handle does not identify an existing window,
* the return value is FALSE.
*/
BOOL FASTCALL
IntIsWindow(HWND hWnd)
{
PWINDOW_OBJECT Window;
if (!(Window = UserGetWindowObject(hWnd)))
return FALSE;
return TRUE;
}
/*
Caller must NOT dereference retval!
But if caller want the returned value to persist spanning a co_ call,
it must reference the value (because the owner is not garanteed to
exist just because the owned window exist)!
*/
PWINDOW_OBJECT FASTCALL
IntGetParent(PWINDOW_OBJECT Wnd)
{
if (Wnd->Style & WS_POPUP)
{
return UserGetWindowObject(Wnd->hOwner);
}
else if (Wnd->Style & WS_CHILD)
{
return Wnd->Parent;
}
return NULL;
}
/*
Caller must NOT dereference retval!
But if caller want the returned value to persist spanning a co_ call,
it must reference the value (because the owner is not garanteed to
exist just because the owned window exist)!
*/
PWINDOW_OBJECT FASTCALL
IntGetOwner(PWINDOW_OBJECT Wnd)
{
return UserGetWindowObject(Wnd->hOwner);
}
/*
* IntWinListChildren
*
* Compile a list of all child window handles from given window.
*
* Remarks
* This function is similar to Wine WIN_ListChildren. The caller
* must free the returned list with ExFreePool.
*/
HWND* FASTCALL
IntWinListChildren(PWINDOW_OBJECT Window)
{
PWINDOW_OBJECT Child;
HWND *List;
UINT Index, NumChildren = 0;
for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
++NumChildren;
List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), TAG_WINLIST);
if(!List)
{
DPRINT1("Failed to allocate memory for children array\n");
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
for (Child = Window->FirstChild, Index = 0;
Child != NULL;
Child = Child->NextSibling, ++Index)
List[Index] = Child->hSelf;
List[Index] = NULL;
return List;
}
/***********************************************************************
* IntSendDestroyMsg
*/
static void IntSendDestroyMsg(HWND hWnd)
{
PWINDOW_OBJECT Window;
#if 0 /* FIXME */
GUITHREADINFO info;
if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
{
if (hWnd == info.hwndCaret)
{
DestroyCaret();
}
}
#endif
Window = UserGetWindowObject(hWnd);
if (Window)
{
// USER_REFERENCE_ENTRY Ref;
// UserRefObjectCo(Window, &Ref);
if (!IntGetOwner(Window) && !IntGetParent(Window))
{
co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM) hWnd);
}
// UserDerefObjectCo(Window);
}
/* The window could already be destroyed here */
/*
* Send the WM_DESTROY to the window.
*/
co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
/*
* This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
* make sure that the window still exists when we come back.
*/
#if 0 /* FIXME */
if (IsWindow(Wnd))
{
HWND* pWndArray;
int i;
if (!(pWndArray = WIN_ListChildren( hwnd )))
return;
/* start from the end (FIXME: is this needed?) */
for (i = 0; pWndArray[i]; i++)
;
while (--i >= 0)
{
if (IsWindow( pWndArray[i] ))
WIN_SendDestroyMsg( pWndArray[i] );
}
HeapFree(GetProcessHeap(), 0, pWndArray);
}
else
{
DPRINT("destroyed itself while in WM_DESTROY!\n");
}
#endif
}
/***********************************************************************
* IntDestroyWindow
*
* Destroy storage associated to a window. "Internals" p.358
*
* This is the "functional" DestroyWindows function ei. all stuff
* done in CreateWindow is undone here and not in DestroyWindow:-P
*/
static LRESULT co_UserFreeWindow(PWINDOW_OBJECT Window,
PW32PROCESS ProcessData,
PW32THREAD ThreadData,
BOOLEAN SendMessages)
{
HWND *Children;
HWND *ChildHandle;
PWINDOW_OBJECT Child;
PMENU_OBJECT Menu;
BOOLEAN BelongsToThreadData;
ASSERT(Window);
if(Window->Status & WINDOWSTATUS_DESTROYING)
{
DPRINT("Tried to call IntDestroyWindow() twice\n");
return 0;
}
Window->Status |= WINDOWSTATUS_DESTROYING;
Window->Style &= ~WS_VISIBLE;
/* remove the window already at this point from the thread window list so we
don't get into trouble when destroying the thread windows while we're still
in IntDestroyWindow() */
RemoveEntryList(&Window->ThreadListEntry);
BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
IntDeRegisterShellHookWindow(Window->hSelf);
if(SendMessages)
{
/* Send destroy messages */
IntSendDestroyMsg(Window->hSelf);
}
/* free child windows */
Children = IntWinListChildren(Window);
if (Children)
{
for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
{
if ((Child = IntGetWindowObject(*ChildHandle)))
{
if(!IntWndBelongsToThread(Child, ThreadData))
{
/* send WM_DESTROY messages to windows not belonging to the same thread */
IntSendDestroyMsg(Child->hSelf);
}
else
co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
UserDerefObject(Child);
}
}
ExFreePool(Children);
}
if(SendMessages)
{
/*
* Clear the update region to make sure no WM_PAINT messages will be
* generated for this window while processing the WM_NCDESTROY.
*/
co_UserRedrawWindow(Window, NULL, 0,
RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
if(BelongsToThreadData)
co_IntSendMessage(Window->hSelf, WM_NCDESTROY, 0, 0);
}
MsqRemoveTimersWindow(ThreadData->MessageQueue, Window->hSelf);
/* flush the message queue */
MsqRemoveWindowMessagesFromQueue(Window);
/* from now on no messages can be sent to this window anymore */
Window->Status |= WINDOWSTATUS_DESTROYED;
/* don't remove the WINDOWSTATUS_DESTROYING bit */
/* reset shell window handles */
if(ThreadData->Desktop)
{
if (Window->hSelf == ThreadData->Desktop->WindowStation->ShellWindow)
ThreadData->Desktop->WindowStation->ShellWindow = NULL;
if (Window->hSelf == ThreadData->Desktop->WindowStation->ShellListView)
ThreadData->Desktop->WindowStation->ShellListView = NULL;
}
/* Unregister hot keys */
UnregisterWindowHotKeys (Window);
/* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
#if 0 /* FIXME */
WinPosCheckInternalPos(Window->hSelf);
if (Window->hSelf == GetCapture())
{
ReleaseCapture();
}
/* free resources associated with the window */
TIMER_RemoveWindowTimers(Window->hSelf);
#endif
if (!(Window->Style & WS_CHILD) && Window->IDMenu
&& (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
{
IntDestroyMenuObject(Menu, TRUE, TRUE);
Window->IDMenu = 0;
}
if(Window->SystemMenu
&& (Menu = UserGetMenuObject(Window->SystemMenu)))
{
IntDestroyMenuObject(Menu, TRUE, TRUE);
Window->SystemMenu = (HMENU)0;
}
DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
#if 0 /* FIXME */
WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
CLASS_RemoveWindow(Window->Class);
#endif
IntUnlinkWindow(Window);
UserRefObject(Window);
ObmDeleteObject(Window->hSelf, otWindow);
IntDestroyScrollBars(Window);
if (!Window->Class->System && Window->CallProc != NULL)
{
DestroyCallProc(Window->ti->Desktop,
Window->CallProc);
}
if (Window->CallProc2 != NULL)
{
DestroyCallProc(Window->ti->Desktop,
Window->CallProc2);
}
/* dereference the class */
IntDereferenceClass(Window->Class,
Window->ti->Desktop,
Window->ti->kpi);
Window->Class = NULL;
if(Window->WindowRegion)
{
NtGdiDeleteObject(Window->WindowRegion);
}
RtlFreeUnicodeString(&Window->WindowName);
UserDerefObject(Window);
IntClipboardFreeWindow(Window);
return 0;
}
VOID FASTCALL
IntGetWindowBorderMeasures(PWINDOW_OBJECT Window, UINT *cx, UINT *cy)
{
if(HAS_DLGFRAME(Window->Style, Window->ExStyle) && !(Window->Style & WS_MINIMIZE))
{
*cx = UserGetSystemMetrics(SM_CXDLGFRAME);
*cy = UserGetSystemMetrics(SM_CYDLGFRAME);
}
else
{
if(HAS_THICKFRAME(Window->Style, Window->ExStyle)&& !(Window->Style & WS_MINIMIZE))
{
*cx = UserGetSystemMetrics(SM_CXFRAME);
*cy = UserGetSystemMetrics(SM_CYFRAME);
}
else if(HAS_THINFRAME(Window->Style, Window->ExStyle))
{
*cx = UserGetSystemMetrics(SM_CXBORDER);
*cy = UserGetSystemMetrics(SM_CYBORDER);
}
else
{
*cx = *cy = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -