2003-05-18 17:16:18 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
2002-07-04 20:12:28 +00:00
|
|
|
*
|
2004-02-24 01:30:58 +00:00
|
|
|
* $Id: painting.c,v 1.73 2004/02/24 01:30:57 weiden Exp $
|
2003-11-18 20:49:39 +00:00
|
|
|
*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* PURPOSE: Window painting function
|
|
|
|
* FILE: subsys/win32k/ntuser/painting.c
|
|
|
|
* PROGRAMER: Filip Navara (xnavara@volny.cz)
|
|
|
|
* REVISION HISTORY:
|
|
|
|
* 06/06/2001 Created (?)
|
|
|
|
* 18/11/2003 Complete rewrite
|
2002-07-04 20:12:28 +00:00
|
|
|
*/
|
2003-11-18 20:49:39 +00:00
|
|
|
|
2002-07-04 20:12:28 +00:00
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
|
|
|
#include <ddk/ntddk.h>
|
2003-11-18 20:49:39 +00:00
|
|
|
#include <internal/safe.h>
|
2002-07-04 20:12:28 +00:00
|
|
|
#include <win32k/win32k.h>
|
|
|
|
#include <include/object.h>
|
|
|
|
#include <include/guicheck.h>
|
|
|
|
#include <include/window.h>
|
2003-12-12 18:18:21 +00:00
|
|
|
#include <include/desktop.h>
|
2003-12-08 18:21:25 +00:00
|
|
|
#include <include/winpos.h>
|
2002-07-04 20:12:28 +00:00
|
|
|
#include <include/class.h>
|
2003-12-08 18:21:25 +00:00
|
|
|
#include <include/caret.h>
|
2002-07-04 20:12:28 +00:00
|
|
|
#include <include/error.h>
|
|
|
|
#include <include/winsta.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#include <include/painting.h>
|
|
|
|
#include <user32/wininternal.h>
|
|
|
|
#include <include/rect.h>
|
|
|
|
#include <win32k/coord.h>
|
2002-07-18 21:59:18 +00:00
|
|
|
#include <win32k/region.h>
|
2003-08-02 19:56:19 +00:00
|
|
|
#include <include/vis.h>
|
2003-12-13 12:12:41 +00:00
|
|
|
#include <include/intgdi.h>
|
2002-07-04 20:12:28 +00:00
|
|
|
|
|
|
|
#define NDEBUG
|
2004-02-04 23:01:07 +00:00
|
|
|
#include <win32k/debug1.h>
|
2002-07-04 20:12:28 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
2003-05-26 18:52:37 +00:00
|
|
|
|
2003-11-21 17:01:16 +00:00
|
|
|
VOID FASTCALL
|
2003-12-28 10:56:20 +00:00
|
|
|
IntValidateParent(PWINDOW_OBJECT Child, HRGN ValidRegion)
|
2003-11-21 17:01:16 +00:00
|
|
|
{
|
2004-02-24 01:30:58 +00:00
|
|
|
PWINDOW_OBJECT ParentWindow = IntGetParentObject(Child), OldWindow;
|
2003-11-21 17:01:16 +00:00
|
|
|
|
2004-02-24 01:30:58 +00:00
|
|
|
while (ParentWindow)
|
2003-11-21 17:01:16 +00:00
|
|
|
{
|
2004-02-24 01:30:58 +00:00
|
|
|
if (!(ParentWindow->Style & WS_CLIPCHILDREN))
|
2003-11-21 17:01:16 +00:00
|
|
|
{
|
2004-02-04 23:01:07 +00:00
|
|
|
ExAcquireFastMutex(&ParentWindow->UpdateLock);
|
2003-11-21 17:01:16 +00:00
|
|
|
if (ParentWindow->UpdateRegion != 0)
|
|
|
|
{
|
|
|
|
INT OffsetX, OffsetY;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We must offset the child region by the offset of the
|
|
|
|
* child rect in the parent.
|
|
|
|
*/
|
|
|
|
OffsetX = Child->WindowRect.left - ParentWindow->WindowRect.left;
|
|
|
|
OffsetY = Child->WindowRect.top - ParentWindow->WindowRect.top;
|
2004-01-12 00:07:34 +00:00
|
|
|
NtGdiOffsetRgn(ValidRegion, OffsetX, OffsetY);
|
2003-11-21 17:01:16 +00:00
|
|
|
NtGdiCombineRgn(ParentWindow->UpdateRegion, ParentWindow->UpdateRegion,
|
2003-12-28 10:56:20 +00:00
|
|
|
ValidRegion, RGN_DIFF);
|
2003-11-21 17:01:16 +00:00
|
|
|
/* FIXME: If the resulting region is empty, remove fake posted paint message */
|
2003-12-28 10:56:20 +00:00
|
|
|
NtGdiOffsetRgn(ValidRegion, -OffsetX, -OffsetY);
|
2003-11-21 17:01:16 +00:00
|
|
|
}
|
2004-02-04 23:01:07 +00:00
|
|
|
ExReleaseFastMutex(&ParentWindow->UpdateLock);
|
2003-11-21 17:01:16 +00:00
|
|
|
}
|
2004-02-24 01:30:58 +00:00
|
|
|
OldWindow = ParentWindow;
|
|
|
|
ParentWindow = IntGetParentObject(ParentWindow);
|
|
|
|
IntReleaseWindowObject(OldWindow);
|
2003-11-21 17:01:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/*
|
|
|
|
* IntPaintWindows
|
|
|
|
*
|
|
|
|
* Internal function used by IntRedrawWindow.
|
|
|
|
*/
|
|
|
|
|
2004-02-04 23:01:07 +00:00
|
|
|
STATIC VOID FASTCALL
|
2003-11-18 20:49:39 +00:00
|
|
|
IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
|
2002-08-26 23:20:54 +00:00
|
|
|
{
|
2003-12-07 23:02:57 +00:00
|
|
|
HDC hDC;
|
|
|
|
HWND hWnd = Window->Self;
|
2004-02-21 22:22:26 +00:00
|
|
|
HRGN TempRegion;
|
2003-11-18 20:49:39 +00:00
|
|
|
|
2003-12-07 23:02:57 +00:00
|
|
|
if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
|
|
|
|
{
|
|
|
|
if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
|
|
|
|
{
|
2004-02-04 23:01:07 +00:00
|
|
|
ExAcquireFastMutex(&Window->UpdateLock);
|
2004-02-03 17:53:55 +00:00
|
|
|
if (Window->NCUpdateRegion)
|
|
|
|
{
|
|
|
|
IntValidateParent(Window, Window->NCUpdateRegion);
|
|
|
|
}
|
2004-02-21 22:22:26 +00:00
|
|
|
TempRegion = Window->NCUpdateRegion;
|
2003-12-27 15:09:51 +00:00
|
|
|
Window->NCUpdateRegion = NULL;
|
|
|
|
Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
|
|
|
|
MsqDecPaintCountQueue(Window->MessageQueue);
|
2004-02-04 23:01:07 +00:00
|
|
|
ExReleaseFastMutex(&Window->UpdateLock);
|
2004-02-21 22:22:26 +00:00
|
|
|
IntSendMessage(hWnd, WM_NCPAINT, (WPARAM)TempRegion, 0);
|
2003-12-07 23:02:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
|
|
|
|
{
|
|
|
|
if (Window->UpdateRegion)
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
2004-01-17 15:18:25 +00:00
|
|
|
IntValidateParent(Window, Window->UpdateRegion);
|
2003-12-07 23:02:57 +00:00
|
|
|
hDC = NtUserGetDCEx(hWnd, 0, DCX_CACHE | DCX_USESTYLE |
|
|
|
|
DCX_INTERSECTUPDATE);
|
|
|
|
if (hDC != NULL)
|
|
|
|
{
|
2003-12-26 22:52:12 +00:00
|
|
|
if (IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0))
|
2003-12-07 23:02:57 +00:00
|
|
|
{
|
|
|
|
Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
|
|
|
|
}
|
2003-11-19 09:10:36 +00:00
|
|
|
NtUserReleaseDC(hWnd, hDC);
|
2003-12-07 23:02:57 +00:00
|
|
|
}
|
2003-11-18 20:49:39 +00:00
|
|
|
}
|
2003-12-07 23:02:57 +00:00
|
|
|
}
|
2003-11-18 20:49:39 +00:00
|
|
|
|
2003-12-07 23:02:57 +00:00
|
|
|
if (Flags & RDW_UPDATENOW)
|
|
|
|
{
|
|
|
|
if (Window->UpdateRegion != NULL ||
|
|
|
|
Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
|
2003-11-19 09:10:36 +00:00
|
|
|
{
|
2003-12-26 22:52:12 +00:00
|
|
|
IntSendMessage(hWnd, WM_PAINT, 0, 0);
|
2004-02-04 23:01:07 +00:00
|
|
|
ExAcquireFastMutex(&Window->UpdateLock);
|
2003-12-07 23:02:57 +00:00
|
|
|
if (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
|
|
|
|
{
|
2003-11-19 09:10:36 +00:00
|
|
|
Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
|
|
|
|
if (Window->UpdateRegion == NULL)
|
2003-12-07 23:02:57 +00:00
|
|
|
{
|
|
|
|
MsqDecPaintCountQueue(Window->MessageQueue);
|
|
|
|
}
|
|
|
|
}
|
2004-02-04 23:01:07 +00:00
|
|
|
ExReleaseFastMutex(&Window->UpdateLock);
|
2003-11-19 09:10:36 +00:00
|
|
|
}
|
2003-12-07 23:02:57 +00:00
|
|
|
}
|
|
|
|
}
|
2003-11-18 20:49:39 +00:00
|
|
|
|
2003-12-07 23:02:57 +00:00
|
|
|
/*
|
|
|
|
* Check that the window is still valid at this point
|
|
|
|
*/
|
2003-11-18 20:49:39 +00:00
|
|
|
|
2003-12-07 23:02:57 +00:00
|
|
|
if (! IntIsWindow(hWnd))
|
|
|
|
{
|
2003-11-18 20:49:39 +00:00
|
|
|
return;
|
2003-12-07 23:02:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Paint child windows.
|
|
|
|
*/
|
|
|
|
if (!(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
|
2004-01-17 15:18:25 +00:00
|
|
|
((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
|
2003-12-07 23:02:57 +00:00
|
|
|
{
|
2003-11-18 20:49:39 +00:00
|
|
|
HWND *List, *phWnd;
|
|
|
|
|
|
|
|
if ((List = IntWinListChildren(Window)))
|
2003-12-07 23:02:57 +00:00
|
|
|
{
|
|
|
|
for (phWnd = List; *phWnd; ++phWnd)
|
2003-11-19 09:10:36 +00:00
|
|
|
{
|
2003-12-07 23:02:57 +00:00
|
|
|
Window = IntGetWindowObject(*phWnd);
|
2004-02-21 13:13:27 +00:00
|
|
|
if (Window && (Window->Style & WS_VISIBLE))
|
2003-12-07 23:02:57 +00:00
|
|
|
{
|
|
|
|
IntPaintWindows(Window, Flags);
|
|
|
|
IntReleaseWindowObject(Window);
|
|
|
|
}
|
2003-11-19 09:10:36 +00:00
|
|
|
}
|
2003-12-07 23:02:57 +00:00
|
|
|
ExFreePool(List);
|
|
|
|
}
|
|
|
|
}
|
2002-08-26 23:20:54 +00:00
|
|
|
}
|
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/*
|
|
|
|
* IntInvalidateWindows
|
|
|
|
*
|
|
|
|
* Internal function used by IntRedrawWindow.
|
|
|
|
*/
|
|
|
|
|
|
|
|
VOID FASTCALL
|
2004-01-18 08:29:31 +00:00
|
|
|
IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
|
2002-07-04 20:12:28 +00:00
|
|
|
{
|
2003-11-18 20:49:39 +00:00
|
|
|
INT RgnType;
|
2003-11-21 17:01:16 +00:00
|
|
|
BOOL HadPaintMessage, HadNCPaintMessage;
|
|
|
|
BOOL HasPaintMessage, HasNCPaintMessage;
|
2003-11-18 20:49:39 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Clip the given region with window rectangle (or region)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef TODO
|
|
|
|
if (!Window->WindowRegion)
|
|
|
|
#endif
|
|
|
|
{
|
2004-02-21 13:13:27 +00:00
|
|
|
HRGN hRgnWindow;
|
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
|
|
|
|
NtGdiOffsetRgn(hRgnWindow,
|
|
|
|
-Window->WindowRect.left,
|
|
|
|
-Window->WindowRect.top);
|
2004-02-21 13:13:27 +00:00
|
|
|
RgnType = NtGdiCombineRgn(hRgn, hRgn, hRgnWindow, RGN_AND);
|
2003-11-21 17:01:16 +00:00
|
|
|
NtGdiDeleteObject(hRgnWindow);
|
2003-11-18 20:49:39 +00:00
|
|
|
}
|
|
|
|
#ifdef TODO
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RgnType = NtGdiCombineRgn(hRgn, hRgn, Window->WindowRegion, RGN_AND);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
2003-11-21 17:01:16 +00:00
|
|
|
* Save current state of pending updates
|
2003-11-18 20:49:39 +00:00
|
|
|
*/
|
|
|
|
|
2004-02-04 23:01:07 +00:00
|
|
|
ExAcquireFastMutex(&Window->UpdateLock);
|
2003-11-21 17:01:16 +00:00
|
|
|
HadPaintMessage = Window->UpdateRegion != NULL ||
|
|
|
|
Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT;
|
|
|
|
HadNCPaintMessage = Window->Flags & WINDOWOBJECT_NEED_NCPAINT;
|
2003-11-18 20:49:39 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Update the region and flags
|
|
|
|
*/
|
|
|
|
|
2003-11-21 17:01:16 +00:00
|
|
|
if (Flags & RDW_INVALIDATE && RgnType != NULLREGION)
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
|
|
|
if (Window->UpdateRegion == NULL)
|
|
|
|
{
|
|
|
|
Window->UpdateRegion = NtGdiCreateRectRgn(0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
|
|
|
|
hRgn, RGN_OR) == NULLREGION)
|
|
|
|
{
|
|
|
|
NtGdiDeleteObject(Window->UpdateRegion);
|
|
|
|
Window->UpdateRegion = NULL;
|
|
|
|
}
|
2002-08-26 23:20:54 +00:00
|
|
|
|
|
|
|
if (Flags & RDW_FRAME)
|
2003-11-18 20:49:39 +00:00
|
|
|
Window->Flags |= WINDOWOBJECT_NEED_NCPAINT;
|
2002-08-26 23:20:54 +00:00
|
|
|
if (Flags & RDW_ERASE)
|
2003-11-18 20:49:39 +00:00
|
|
|
Window->Flags |= WINDOWOBJECT_NEED_ERASEBKGND;
|
|
|
|
|
2002-08-26 23:20:54 +00:00
|
|
|
Flags |= RDW_FRAME;
|
2003-11-18 20:49:39 +00:00
|
|
|
}
|
|
|
|
|
2003-11-21 17:01:16 +00:00
|
|
|
if (Flags & RDW_VALIDATE && RgnType != NULLREGION)
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
|
|
|
if (Window->UpdateRegion != NULL)
|
|
|
|
{
|
|
|
|
if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
|
|
|
|
hRgn, RGN_DIFF) == NULLREGION)
|
|
|
|
{
|
|
|
|
NtGdiDeleteObject(Window->UpdateRegion);
|
|
|
|
Window->UpdateRegion = NULL;
|
|
|
|
}
|
|
|
|
}
|
2002-08-26 23:20:54 +00:00
|
|
|
|
2003-11-21 17:01:16 +00:00
|
|
|
if (Window->UpdateRegion == NULL)
|
|
|
|
Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
|
2002-08-26 23:20:54 +00:00
|
|
|
if (Flags & RDW_NOFRAME)
|
2003-11-18 20:49:39 +00:00
|
|
|
Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
|
2002-08-26 23:20:54 +00:00
|
|
|
if (Flags & RDW_NOERASE)
|
2003-11-18 20:49:39 +00:00
|
|
|
Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Flags & RDW_INTERNALPAINT)
|
|
|
|
{
|
|
|
|
Window->Flags |= WINDOWOBJECT_NEED_INTERNALPAINT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Flags & RDW_NOINTERNALPAINT)
|
|
|
|
{
|
|
|
|
Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
|
|
|
|
}
|
|
|
|
|
2003-12-27 15:09:51 +00:00
|
|
|
/*
|
|
|
|
* Split the nonclient update region.
|
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
2004-02-21 13:13:27 +00:00
|
|
|
HRGN hRgnWindow, hRgnNonClient;
|
|
|
|
|
|
|
|
hRgnWindow = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
|
|
|
|
NtGdiOffsetRgn(hRgnWindow,
|
|
|
|
-Window->WindowRect.left,
|
|
|
|
-Window->WindowRect.top);
|
|
|
|
|
|
|
|
hRgnNonClient = NtGdiCreateRectRgn(0, 0, 0, 0);
|
|
|
|
if (NtGdiCombineRgn(hRgnNonClient, Window->UpdateRegion,
|
|
|
|
hRgnWindow, RGN_DIFF) == NULLREGION)
|
|
|
|
{
|
|
|
|
NtGdiDeleteObject(hRgnNonClient);
|
|
|
|
hRgnNonClient = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove the nonclient region from the standard update region.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (NtGdiCombineRgn(Window->UpdateRegion, Window->UpdateRegion,
|
|
|
|
hRgnWindow, RGN_AND) == NULLREGION)
|
|
|
|
{
|
|
|
|
NtGdiDeleteObject(Window->UpdateRegion);
|
|
|
|
Window->UpdateRegion = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Window->NCUpdateRegion == NULL)
|
|
|
|
{
|
|
|
|
Window->NCUpdateRegion = hRgnNonClient;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NtGdiCombineRgn(Window->NCUpdateRegion, Window->NCUpdateRegion,
|
|
|
|
hRgnNonClient, RGN_OR);
|
|
|
|
}
|
|
|
|
|
|
|
|
NtGdiDeleteObject(hRgnWindow);
|
2003-12-27 15:09:51 +00:00
|
|
|
}
|
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/*
|
|
|
|
* Process children if needed
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
|
|
|
|
((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
|
|
|
|
{
|
|
|
|
HWND *List, *phWnd;
|
|
|
|
PWINDOW_OBJECT Child;
|
|
|
|
|
|
|
|
if ((List = IntWinListChildren(Window)))
|
|
|
|
{
|
|
|
|
for (phWnd = List; *phWnd; ++phWnd)
|
|
|
|
{
|
|
|
|
Child = IntGetWindowObject(*phWnd);
|
2003-12-18 21:42:38 +00:00
|
|
|
if(!Child)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2003-12-27 15:09:51 +00:00
|
|
|
if (Child->Style & WS_VISIBLE)
|
2003-11-21 17:01:16 +00:00
|
|
|
{
|
2003-11-21 21:12:09 +00:00
|
|
|
/*
|
|
|
|
* Recursive call to update children UpdateRegion
|
|
|
|
*/
|
2003-11-21 17:01:16 +00:00
|
|
|
HRGN hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
|
|
|
|
NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
|
|
|
|
NtGdiOffsetRgn(hRgnTemp,
|
|
|
|
Window->WindowRect.left - Child->WindowRect.left,
|
|
|
|
Window->WindowRect.top - Child->WindowRect.top);
|
2004-01-18 08:29:31 +00:00
|
|
|
IntInvalidateWindows(Child, hRgnTemp, Flags);
|
2003-11-21 17:01:16 +00:00
|
|
|
NtGdiDeleteObject(hRgnTemp);
|
|
|
|
}
|
2003-11-18 20:49:39 +00:00
|
|
|
IntReleaseWindowObject(Child);
|
|
|
|
}
|
|
|
|
ExFreePool(List);
|
|
|
|
}
|
|
|
|
}
|
2003-11-21 21:12:09 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Fake post paint messages to window message queue if needed
|
|
|
|
*/
|
2004-02-21 13:13:27 +00:00
|
|
|
|
2003-12-07 23:02:57 +00:00
|
|
|
HasPaintMessage = Window->UpdateRegion != NULL ||
|
2003-11-21 21:12:09 +00:00
|
|
|
Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT;
|
2003-12-07 23:02:57 +00:00
|
|
|
HasNCPaintMessage = Window->Flags & WINDOWOBJECT_NEED_NCPAINT;
|
2003-11-21 21:12:09 +00:00
|
|
|
|
2003-12-07 23:02:57 +00:00
|
|
|
if (HasPaintMessage != HadPaintMessage)
|
|
|
|
{
|
|
|
|
if (HadPaintMessage)
|
|
|
|
MsqDecPaintCountQueue(Window->MessageQueue);
|
|
|
|
else
|
|
|
|
MsqIncPaintCountQueue(Window->MessageQueue);
|
|
|
|
}
|
2003-11-21 21:12:09 +00:00
|
|
|
|
2003-12-07 23:02:57 +00:00
|
|
|
if (HasNCPaintMessage != HadNCPaintMessage)
|
|
|
|
{
|
|
|
|
if (HadNCPaintMessage)
|
|
|
|
MsqDecPaintCountQueue(Window->MessageQueue);
|
|
|
|
else
|
|
|
|
MsqIncPaintCountQueue(Window->MessageQueue);
|
2003-11-21 21:12:09 +00:00
|
|
|
}
|
2004-02-04 23:01:07 +00:00
|
|
|
|
|
|
|
ExReleaseFastMutex(&Window->UpdateLock);
|
2002-07-04 20:12:28 +00:00
|
|
|
}
|
|
|
|
|
2003-11-21 17:01:16 +00:00
|
|
|
/*
|
|
|
|
* IntIsWindowDrawable
|
|
|
|
*
|
|
|
|
* Remarks
|
2003-12-30 16:55:00 +00:00
|
|
|
* Window is drawable when it is visible and all parents are not
|
|
|
|
* minimized.
|
2003-11-21 17:01:16 +00:00
|
|
|
*/
|
2003-11-18 20:49:39 +00:00
|
|
|
|
2003-11-21 17:01:16 +00:00
|
|
|
BOOL FASTCALL
|
|
|
|
IntIsWindowDrawable(PWINDOW_OBJECT Window)
|
|
|
|
{
|
2004-02-24 01:30:58 +00:00
|
|
|
PWINDOW_OBJECT Old, Wnd = Window;
|
2003-12-30 16:55:00 +00:00
|
|
|
|
2004-02-24 01:30:58 +00:00
|
|
|
IntReferenceWindowObject(Wnd);
|
|
|
|
do
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
2003-12-30 16:55:00 +00:00
|
|
|
if (!(Wnd->Style & WS_VISIBLE) ||
|
|
|
|
((Wnd->Style & WS_MINIMIZE) && (Wnd != Window)))
|
2004-02-24 01:30:58 +00:00
|
|
|
{
|
|
|
|
IntReleaseWindowObject(Wnd);
|
2003-11-21 17:01:16 +00:00
|
|
|
return FALSE;
|
2004-02-24 01:30:58 +00:00
|
|
|
}
|
|
|
|
Old = Wnd;
|
|
|
|
Wnd = IntGetParentObject(Wnd);
|
|
|
|
IntReleaseWindowObject(Old);
|
|
|
|
} while(Wnd);
|
2003-11-21 17:01:16 +00:00
|
|
|
|
|
|
|
return TRUE;
|
2003-11-18 20:49:39 +00:00
|
|
|
}
|
2002-07-04 20:12:28 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/*
|
|
|
|
* IntRedrawWindow
|
|
|
|
*
|
|
|
|
* Internal version of NtUserRedrawWindow that takes WINDOW_OBJECT as
|
|
|
|
* first parameter.
|
|
|
|
*/
|
2003-05-26 18:52:37 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
BOOL FASTCALL
|
|
|
|
IntRedrawWindow(PWINDOW_OBJECT Window, const RECT* UpdateRect, HRGN UpdateRgn,
|
|
|
|
ULONG Flags)
|
|
|
|
{
|
|
|
|
HRGN hRgn = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Step 1.
|
|
|
|
* Validation of passed parameters.
|
|
|
|
*/
|
|
|
|
|
2003-11-21 17:01:16 +00:00
|
|
|
if (!IntIsWindowDrawable(Window) ||
|
|
|
|
(Flags & (RDW_VALIDATE | RDW_INVALIDATE)) ==
|
|
|
|
(RDW_VALIDATE | RDW_INVALIDATE))
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Step 2.
|
|
|
|
* Transform the parameters UpdateRgn and UpdateRect into
|
|
|
|
* a region hRgn specified in window coordinates.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (Flags & (RDW_INVALIDATE | RDW_VALIDATE))
|
|
|
|
{
|
|
|
|
if (UpdateRgn != NULL)
|
|
|
|
{
|
|
|
|
hRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
|
|
|
|
NtGdiCombineRgn(hRgn, UpdateRgn, NULL, RGN_COPY);
|
|
|
|
NtGdiOffsetRgn(hRgn,
|
|
|
|
Window->ClientRect.left - Window->WindowRect.left,
|
|
|
|
Window->ClientRect.top - Window->WindowRect.top);
|
|
|
|
} else
|
|
|
|
if (UpdateRect != NULL)
|
|
|
|
{
|
|
|
|
hRgn = UnsafeIntCreateRectRgnIndirect((RECT *)UpdateRect);
|
|
|
|
NtGdiOffsetRgn(hRgn,
|
|
|
|
Window->ClientRect.left - Window->WindowRect.left,
|
|
|
|
Window->ClientRect.top - Window->WindowRect.top);
|
|
|
|
} else
|
|
|
|
if ((Flags & (RDW_INVALIDATE | RDW_FRAME)) == (RDW_INVALIDATE | RDW_FRAME) ||
|
|
|
|
(Flags & (RDW_VALIDATE | RDW_NOFRAME)) == (RDW_VALIDATE | RDW_NOFRAME))
|
|
|
|
{
|
|
|
|
hRgn = UnsafeIntCreateRectRgnIndirect(&Window->WindowRect);
|
|
|
|
NtGdiOffsetRgn(hRgn,
|
|
|
|
-Window->WindowRect.left,
|
|
|
|
-Window->WindowRect.top);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hRgn = UnsafeIntCreateRectRgnIndirect(&Window->ClientRect);
|
|
|
|
NtGdiOffsetRgn(hRgn,
|
|
|
|
-Window->WindowRect.left,
|
|
|
|
-Window->WindowRect.top);
|
|
|
|
}
|
|
|
|
}
|
2002-07-04 20:12:28 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/*
|
|
|
|
* Step 3.
|
|
|
|
* Adjust the window update region depending on hRgn and flags.
|
|
|
|
*/
|
2003-05-26 18:52:37 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
if (Flags & (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT))
|
|
|
|
{
|
2004-01-18 08:29:31 +00:00
|
|
|
IntInvalidateWindows(Window, hRgn, Flags);
|
2003-11-18 20:49:39 +00:00
|
|
|
}
|
2002-07-04 20:12:28 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/*
|
|
|
|
* Step 4.
|
|
|
|
* Repaint and erase windows if needed.
|
|
|
|
*/
|
|
|
|
|
2004-02-21 13:51:13 +00:00
|
|
|
if (Flags & (RDW_ERASENOW | RDW_UPDATENOW))
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
|
|
|
IntPaintWindows(Window, Flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Step 5.
|
|
|
|
* Cleanup ;-)
|
|
|
|
*/
|
|
|
|
|
2004-02-01 08:07:07 +00:00
|
|
|
if (hRgn != NULL)
|
2003-11-25 23:46:23 +00:00
|
|
|
{
|
|
|
|
NtGdiDeleteObject(hRgn);
|
|
|
|
}
|
2003-11-18 20:49:39 +00:00
|
|
|
|
|
|
|
return TRUE;
|
2002-07-04 20:12:28 +00:00
|
|
|
}
|
|
|
|
|
2004-02-21 13:13:27 +00:00
|
|
|
BOOL FASTCALL
|
|
|
|
IntIsWindowDirty(PWINDOW_OBJECT Window)
|
|
|
|
{
|
|
|
|
return (Window->Style & WS_VISIBLE) &&
|
|
|
|
((Window->UpdateRegion != NULL) ||
|
|
|
|
(Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT) ||
|
|
|
|
(Window->Flags & WINDOWOBJECT_NEED_NCPAINT));
|
|
|
|
}
|
|
|
|
|
2002-07-04 20:12:28 +00:00
|
|
|
HWND STDCALL
|
2003-11-18 20:49:39 +00:00
|
|
|
IntFindWindowToRepaint(HWND hWnd, PW32THREAD Thread)
|
2002-07-04 20:12:28 +00:00
|
|
|
{
|
2003-11-18 20:49:39 +00:00
|
|
|
PWINDOW_OBJECT Window;
|
|
|
|
PWINDOW_OBJECT Child;
|
|
|
|
HWND hFoundWnd = NULL;
|
|
|
|
|
2004-01-17 15:18:25 +00:00
|
|
|
Window = IntGetWindowObject(hWnd);
|
|
|
|
if (Window == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2004-02-21 13:13:27 +00:00
|
|
|
if (IntIsWindowDirty(Window) &&
|
2004-01-17 15:18:25 +00:00
|
|
|
IntWndBelongsToThread(Window, Thread))
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
2004-01-17 15:18:25 +00:00
|
|
|
IntReleaseWindowObject(Window);
|
|
|
|
return hWnd;
|
|
|
|
}
|
2002-07-04 20:12:28 +00:00
|
|
|
|
2004-02-24 01:30:58 +00:00
|
|
|
IntLockRelatives(Window);
|
2004-02-22 16:56:14 +00:00
|
|
|
for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
2004-02-21 13:13:27 +00:00
|
|
|
if (IntIsWindowDirty(Child) &&
|
|
|
|
IntWndBelongsToThread(Child, Thread))
|
2003-08-11 19:14:16 +00:00
|
|
|
{
|
2004-01-17 15:18:25 +00:00
|
|
|
hFoundWnd = Child->Self;
|
|
|
|
break;
|
2003-08-11 19:14:16 +00:00
|
|
|
}
|
2004-01-17 15:18:25 +00:00
|
|
|
}
|
2004-02-24 01:30:58 +00:00
|
|
|
IntUnLockRelatives(Window);
|
2003-08-11 19:14:16 +00:00
|
|
|
|
2004-01-17 15:18:25 +00:00
|
|
|
if (hFoundWnd == NULL)
|
|
|
|
{
|
2004-02-21 23:30:18 +00:00
|
|
|
HWND *List;
|
|
|
|
INT i;
|
|
|
|
|
|
|
|
List = IntWinListChildren(Window);
|
|
|
|
if (List != NULL)
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
2004-02-21 23:30:18 +00:00
|
|
|
for (i = 0; List[i]; i++)
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
2004-02-21 23:30:18 +00:00
|
|
|
hFoundWnd = IntFindWindowToRepaint(List[i], Thread);
|
2004-01-17 15:18:25 +00:00
|
|
|
if (hFoundWnd != NULL)
|
|
|
|
break;
|
2003-11-18 20:49:39 +00:00
|
|
|
}
|
2004-02-21 23:30:18 +00:00
|
|
|
ExFreePool(List);
|
2003-11-18 20:49:39 +00:00
|
|
|
}
|
2004-01-17 15:18:25 +00:00
|
|
|
}
|
2003-05-26 18:52:37 +00:00
|
|
|
|
2004-01-17 15:18:25 +00:00
|
|
|
IntReleaseWindowObject(Window);
|
2002-07-04 20:12:28 +00:00
|
|
|
|
2004-01-17 15:18:25 +00:00
|
|
|
return hFoundWnd;
|
2002-07-04 20:12:28 +00:00
|
|
|
}
|
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
BOOL FASTCALL
|
2003-12-06 20:58:27 +00:00
|
|
|
IntGetPaintMessage(HWND hWnd, PW32THREAD Thread, MSG *Message,
|
2003-11-21 17:01:16 +00:00
|
|
|
BOOL Remove)
|
2003-09-09 09:39:21 +00:00
|
|
|
{
|
2003-11-18 20:49:39 +00:00
|
|
|
PWINDOW_OBJECT Window;
|
2003-11-21 17:01:16 +00:00
|
|
|
PUSER_MESSAGE_QUEUE MessageQueue = (PUSER_MESSAGE_QUEUE)Thread->MessageQueue;
|
|
|
|
|
|
|
|
if (!MessageQueue->PaintPosted)
|
|
|
|
return FALSE;
|
2003-11-18 20:49:39 +00:00
|
|
|
|
2003-12-06 20:58:27 +00:00
|
|
|
if (hWnd)
|
|
|
|
Message->hwnd = IntFindWindowToRepaint(hWnd, PsGetWin32Thread());
|
2003-11-18 20:49:39 +00:00
|
|
|
else
|
2004-01-12 00:07:34 +00:00
|
|
|
Message->hwnd = IntFindWindowToRepaint(IntGetDesktopWindow(), PsGetWin32Thread());
|
2003-11-18 20:49:39 +00:00
|
|
|
|
|
|
|
if (Message->hwnd == NULL)
|
2003-11-20 21:21:29 +00:00
|
|
|
{
|
2003-11-30 20:03:47 +00:00
|
|
|
#if 0
|
2003-11-20 21:21:29 +00:00
|
|
|
DPRINT1("PAINTING BUG: Thread marked as containing dirty windows, but no dirty windows found!\n");
|
2004-01-12 00:07:34 +00:00
|
|
|
#endif
|
2004-02-04 23:01:07 +00:00
|
|
|
ExAcquireFastMutex(&MessageQueue->Lock);
|
2003-11-30 20:03:47 +00:00
|
|
|
MessageQueue->PaintPosted = 0;
|
|
|
|
MessageQueue->PaintCount = 0;
|
2004-02-04 23:01:07 +00:00
|
|
|
ExReleaseFastMutex(&MessageQueue->Lock);
|
2003-11-18 20:49:39 +00:00
|
|
|
return FALSE;
|
2003-11-20 21:21:29 +00:00
|
|
|
}
|
2003-11-18 20:49:39 +00:00
|
|
|
|
|
|
|
Window = IntGetWindowObject(Message->hwnd);
|
|
|
|
if (Window != NULL)
|
|
|
|
{
|
2004-02-04 23:01:07 +00:00
|
|
|
ExAcquireFastMutex(&Window->UpdateLock);
|
2003-11-18 20:49:39 +00:00
|
|
|
if (Window->Flags & WINDOWOBJECT_NEED_NCPAINT)
|
|
|
|
{
|
|
|
|
Message->message = WM_NCPAINT;
|
2003-12-27 15:09:51 +00:00
|
|
|
Message->wParam = (WPARAM)Window->NCUpdateRegion;
|
2003-11-18 20:49:39 +00:00
|
|
|
Message->lParam = 0;
|
2003-12-27 15:09:51 +00:00
|
|
|
if (Remove)
|
|
|
|
{
|
2004-02-21 13:13:27 +00:00
|
|
|
IntValidateParent(Window, Window->NCUpdateRegion);
|
2003-12-27 15:09:51 +00:00
|
|
|
Window->NCUpdateRegion = NULL;
|
|
|
|
Window->Flags &= ~WINDOWOBJECT_NEED_NCPAINT;
|
|
|
|
MsqDecPaintCountQueue(Window->MessageQueue);
|
|
|
|
}
|
2003-11-18 20:49:39 +00:00
|
|
|
} else
|
|
|
|
{
|
|
|
|
Message->message = WM_PAINT;
|
|
|
|
Message->wParam = Message->lParam = 0;
|
2003-11-21 17:01:16 +00:00
|
|
|
if (Remove && Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT)
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
|
|
|
Window->Flags &= ~WINDOWOBJECT_NEED_INTERNALPAINT;
|
|
|
|
if (Window->UpdateRegion == NULL)
|
|
|
|
{
|
|
|
|
MsqDecPaintCountQueue(Window->MessageQueue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-02-04 23:01:07 +00:00
|
|
|
ExReleaseFastMutex(&Window->UpdateLock);
|
2003-11-18 20:49:39 +00:00
|
|
|
|
|
|
|
IntReleaseWindowObject(Window);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
2003-09-09 09:39:21 +00:00
|
|
|
}
|
|
|
|
|
2003-12-08 18:21:25 +00:00
|
|
|
HWND FASTCALL
|
|
|
|
IntFixCaret(HWND hWnd, LPRECT lprc, UINT flags)
|
|
|
|
{
|
2004-02-03 17:53:55 +00:00
|
|
|
PDESKTOP_OBJECT Desktop;
|
|
|
|
PTHRDCARETINFO CaretInfo;
|
|
|
|
HWND hWndCaret;
|
|
|
|
|
|
|
|
Desktop = PsGetCurrentThread()->Win32Thread->Desktop;
|
|
|
|
CaretInfo = ((PUSER_MESSAGE_QUEUE)Desktop->ActiveMessageQueue)->CaretInfo;
|
|
|
|
hWndCaret = CaretInfo->hWnd;
|
|
|
|
if (hWndCaret == hWnd ||
|
|
|
|
((flags & SW_SCROLLCHILDREN) && IntIsChildWindow(hWnd, hWndCaret)))
|
2003-12-08 18:21:25 +00:00
|
|
|
{
|
|
|
|
POINT pt, FromOffset, ToOffset, Offset;
|
2004-02-03 17:53:55 +00:00
|
|
|
RECT rcCaret;
|
2003-12-08 18:21:25 +00:00
|
|
|
|
2004-02-03 17:53:55 +00:00
|
|
|
pt.x = CaretInfo->Pos.x;
|
|
|
|
pt.y = CaretInfo->Pos.y;
|
|
|
|
IntGetClientOrigin(hWndCaret, &FromOffset);
|
2003-12-23 21:33:25 +00:00
|
|
|
IntGetClientOrigin(hWnd, &ToOffset);
|
2003-12-08 18:21:25 +00:00
|
|
|
Offset.x = FromOffset.x - ToOffset.x;
|
|
|
|
Offset.y = FromOffset.y - ToOffset.y;
|
2004-02-03 17:53:55 +00:00
|
|
|
rcCaret.left = pt.x;
|
|
|
|
rcCaret.top = pt.y;
|
|
|
|
rcCaret.right = pt.x + CaretInfo->Size.cx;
|
|
|
|
rcCaret.bottom = pt.y + CaretInfo->Size.cy;
|
|
|
|
if (NtGdiIntersectRect(lprc, lprc, &rcCaret))
|
2003-12-08 18:21:25 +00:00
|
|
|
{
|
|
|
|
NtUserHideCaret(0);
|
|
|
|
lprc->left = pt.x;
|
|
|
|
lprc->top = pt.y;
|
2004-02-03 17:53:55 +00:00
|
|
|
return hWndCaret;
|
2003-12-08 18:21:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NtUserBeginPaint
|
|
|
|
*
|
|
|
|
* Status
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
|
2002-07-04 20:12:28 +00:00
|
|
|
HDC STDCALL
|
|
|
|
NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* lPs)
|
|
|
|
{
|
2003-11-18 20:49:39 +00:00
|
|
|
PWINDOW_OBJECT Window;
|
|
|
|
|
|
|
|
if (!(Window = IntGetWindowObject(hWnd)))
|
|
|
|
{
|
|
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
NtUserHideCaret(hWnd);
|
|
|
|
|
2004-02-03 17:53:55 +00:00
|
|
|
lPs->hdc = NtUserGetDCEx(hWnd, 0, DCX_INTERSECTUPDATE | DCX_WINDOWPAINT |
|
|
|
|
DCX_USESTYLE);
|
2003-11-18 20:49:39 +00:00
|
|
|
|
|
|
|
if (!lPs->hdc)
|
|
|
|
{
|
2003-12-07 13:14:22 +00:00
|
|
|
IntReleaseWindowObject(Window);
|
2003-11-18 20:49:39 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-02-04 23:01:07 +00:00
|
|
|
ExAcquireFastMutex(&Window->UpdateLock);
|
2003-11-18 20:49:39 +00:00
|
|
|
if (Window->UpdateRegion != NULL)
|
|
|
|
{
|
2002-08-27 23:29:40 +00:00
|
|
|
MsqDecPaintCountQueue(Window->MessageQueue);
|
2003-12-28 10:56:20 +00:00
|
|
|
IntValidateParent(Window, Window->UpdateRegion);
|
2004-02-03 17:53:55 +00:00
|
|
|
NtGdiGetRgnBox(Window->UpdateRegion, &lPs->rcPaint);
|
|
|
|
NtGdiOffsetRect(&lPs->rcPaint,
|
|
|
|
Window->WindowRect.left - Window->ClientRect.left,
|
|
|
|
Window->WindowRect.top - Window->ClientRect.top);
|
2003-11-18 20:49:39 +00:00
|
|
|
NtGdiDeleteObject(Window->UpdateRegion);
|
|
|
|
Window->UpdateRegion = NULL;
|
|
|
|
}
|
2004-02-03 17:53:55 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
NtUserGetClientRect(Window, &lPs->rcPaint);
|
|
|
|
}
|
2004-02-04 23:01:07 +00:00
|
|
|
ExReleaseFastMutex(&Window->UpdateLock);
|
2003-11-18 20:49:39 +00:00
|
|
|
|
|
|
|
if (Window->Flags & WINDOWOBJECT_NEED_ERASEBKGND)
|
|
|
|
{
|
|
|
|
Window->Flags &= ~WINDOWOBJECT_NEED_ERASEBKGND;
|
2003-12-26 22:52:12 +00:00
|
|
|
lPs->fErase = !IntSendMessage(hWnd, WM_ERASEBKGND, (WPARAM)lPs->hdc, 0);
|
2003-11-18 20:49:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lPs->fErase = FALSE;
|
|
|
|
}
|
2002-07-04 20:12:28 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
IntReleaseWindowObject(Window);
|
2003-08-04 16:55:36 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
return lPs->hdc;
|
|
|
|
}
|
2002-07-04 20:12:28 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/*
|
|
|
|
* NtUserEndPaint
|
|
|
|
*
|
|
|
|
* Status
|
|
|
|
* @implemented
|
|
|
|
*/
|
2002-07-04 20:12:28 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
BOOL STDCALL
|
|
|
|
NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* lPs)
|
|
|
|
{
|
|
|
|
NtUserReleaseDC(hWnd, lPs->hdc);
|
|
|
|
NtUserShowCaret(hWnd);
|
|
|
|
|
|
|
|
return TRUE;
|
2002-07-04 20:12:28 +00:00
|
|
|
}
|
2003-03-27 02:25:14 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/*
|
|
|
|
* NtUserInvalidateRect
|
|
|
|
*
|
|
|
|
* Status
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
|
|
|
|
DWORD STDCALL
|
|
|
|
NtUserInvalidateRect(HWND hWnd, CONST RECT *Rect, BOOL Erase)
|
2003-03-27 02:25:14 +00:00
|
|
|
{
|
2003-11-18 20:49:39 +00:00
|
|
|
return NtUserRedrawWindow(hWnd, Rect, 0, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
|
2003-03-27 02:25:14 +00:00
|
|
|
}
|
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/*
|
|
|
|
* NtUserInvalidateRgn
|
|
|
|
*
|
|
|
|
* Status
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
|
|
|
|
DWORD STDCALL
|
|
|
|
NtUserInvalidateRgn(HWND hWnd, HRGN Rgn, BOOL Erase)
|
2003-05-26 18:52:37 +00:00
|
|
|
{
|
2003-11-18 20:49:39 +00:00
|
|
|
return NtUserRedrawWindow(hWnd, NULL, Rgn, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
|
2003-05-26 18:52:37 +00:00
|
|
|
}
|
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/*
|
|
|
|
* NtUserValidateRgn
|
|
|
|
*
|
|
|
|
* Status
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
|
|
|
|
BOOL STDCALL
|
|
|
|
NtUserValidateRgn(HWND hWnd, HRGN hRgn)
|
2003-05-26 18:52:37 +00:00
|
|
|
{
|
2003-11-18 20:49:39 +00:00
|
|
|
return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN);
|
2003-05-26 18:52:37 +00:00
|
|
|
}
|
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
/*
|
|
|
|
* NtUserUpdateWindow
|
|
|
|
*
|
|
|
|
* Status
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
|
|
|
|
BOOL STDCALL
|
|
|
|
NtUserUpdateWindow(HWND hWnd)
|
2003-03-27 02:25:14 +00:00
|
|
|
{
|
2003-11-18 20:49:39 +00:00
|
|
|
return NtUserRedrawWindow(hWnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NtUserGetUpdateRgn
|
|
|
|
*
|
|
|
|
* Status
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
|
|
|
|
INT STDCALL
|
|
|
|
NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
|
|
|
|
{
|
|
|
|
PWINDOW_OBJECT Window;
|
|
|
|
int RegionType;
|
|
|
|
|
|
|
|
if (!(Window = IntGetWindowObject(hWnd)))
|
|
|
|
{
|
|
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
|
|
return ERROR;
|
|
|
|
}
|
2003-03-27 02:25:14 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
if (Window->UpdateRegion == NULL)
|
|
|
|
{
|
2003-08-19 11:48:50 +00:00
|
|
|
RegionType = (NtGdiSetRectRgn(hRgn, 0, 0, 0, 0) ? NULLREGION : ERROR);
|
2003-11-18 20:49:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-08-19 11:48:50 +00:00
|
|
|
RegionType = NtGdiCombineRgn(hRgn, Window->UpdateRegion, hRgn, RGN_COPY);
|
2003-11-18 20:49:39 +00:00
|
|
|
NtGdiOffsetRgn(
|
|
|
|
hRgn,
|
|
|
|
Window->WindowRect.left - Window->ClientRect.left,
|
|
|
|
Window->WindowRect.top - Window->ClientRect.top);
|
|
|
|
}
|
|
|
|
|
|
|
|
IntReleaseWindowObject(Window);
|
|
|
|
|
|
|
|
if (bErase && RegionType != NULLREGION && RegionType != ERROR)
|
|
|
|
{
|
|
|
|
NtUserRedrawWindow(hWnd, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
|
|
|
|
}
|
2003-08-04 16:55:36 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
return RegionType;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NtUserGetUpdateRect
|
|
|
|
*
|
|
|
|
* Status
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
|
|
|
|
BOOL STDCALL
|
|
|
|
NtUserGetUpdateRect(HWND hWnd, LPRECT lpRect, BOOL fErase)
|
|
|
|
{
|
|
|
|
HRGN hRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
|
2003-03-27 02:25:14 +00:00
|
|
|
|
2003-11-18 20:49:39 +00:00
|
|
|
if (!lpRect)
|
|
|
|
{
|
|
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NtUserGetUpdateRgn(hWnd, hRgn, fErase);
|
|
|
|
NtGdiGetRgnBox(hRgn, lpRect);
|
2004-02-01 08:07:07 +00:00
|
|
|
NtGdiDeleteObject(hRgn);
|
2003-11-18 20:49:39 +00:00
|
|
|
|
|
|
|
return lpRect->left < lpRect->right && lpRect->top < lpRect->bottom;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NtUserRedrawWindow
|
|
|
|
*
|
|
|
|
* Status
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
|
|
|
|
BOOL STDCALL
|
|
|
|
NtUserRedrawWindow(HWND hWnd, CONST RECT *lprcUpdate, HRGN hrgnUpdate,
|
|
|
|
UINT flags)
|
|
|
|
{
|
|
|
|
RECT SafeUpdateRect;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PWINDOW_OBJECT Wnd;
|
|
|
|
|
2003-11-21 17:01:16 +00:00
|
|
|
if (!(Wnd = IntGetWindowObject(hWnd ? hWnd : IntGetDesktopWindow())))
|
2003-11-18 20:49:39 +00:00
|
|
|
{
|
|
|
|
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lprcUpdate != NULL)
|
|
|
|
{
|
|
|
|
Status = MmCopyFromCaller(&SafeUpdateRect, (PRECT)lprcUpdate,
|
|
|
|
sizeof(RECT));
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
2004-02-21 22:22:26 +00:00
|
|
|
IntReleaseWindowObject(Wnd);
|
2003-11-18 20:49:39 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = IntRedrawWindow(Wnd, NULL == lprcUpdate ? NULL : &SafeUpdateRect,
|
|
|
|
hrgnUpdate, flags);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* IntRedrawWindow fails only in case that flags are invalid */
|
|
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
2004-02-21 22:22:26 +00:00
|
|
|
IntReleaseWindowObject(Wnd);
|
2003-11-18 20:49:39 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2004-02-21 22:22:26 +00:00
|
|
|
IntReleaseWindowObject(Wnd);
|
2003-11-18 20:49:39 +00:00
|
|
|
return TRUE;
|
2003-03-27 02:25:14 +00:00
|
|
|
}
|
2003-05-26 18:52:37 +00:00
|
|
|
|
2003-12-08 18:21:25 +00:00
|
|
|
/*
|
|
|
|
* NtUserScrollDC
|
|
|
|
*
|
|
|
|
* Status
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
|
|
|
|
DWORD STDCALL
|
|
|
|
NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
|
|
|
|
const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate)
|
|
|
|
{
|
|
|
|
RECT rSrc, rClipped_src, rClip, rDst, offset;
|
2004-01-10 21:59:05 +00:00
|
|
|
PDC DC;
|
2003-12-08 18:21:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute device clipping region (in device coordinates).
|
|
|
|
*/
|
|
|
|
|
2004-01-10 21:59:05 +00:00
|
|
|
DC = DC_LockDc(hDC);
|
|
|
|
if (NULL == DC)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
2003-12-08 18:21:25 +00:00
|
|
|
if (lprcScroll)
|
|
|
|
rSrc = *lprcScroll;
|
|
|
|
else
|
2003-12-13 12:12:41 +00:00
|
|
|
IntGdiGetClipBox(hDC, &rSrc);
|
2004-01-10 21:59:05 +00:00
|
|
|
IntLPtoDP(DC, (LPPOINT)&rSrc, 2);
|
2003-12-08 18:21:25 +00:00
|
|
|
|
|
|
|
if (lprcClip)
|
|
|
|
rClip = *lprcClip;
|
|
|
|
else
|
2003-12-13 12:12:41 +00:00
|
|
|
IntGdiGetClipBox(hDC, &rClip);
|
2004-01-10 21:59:05 +00:00
|
|
|
IntLPtoDP(DC, (LPPOINT)&rClip, 2);
|
2003-12-08 18:21:25 +00:00
|
|
|
|
|
|
|
NtGdiIntersectRect(&rClipped_src, &rSrc, &rClip);
|
|
|
|
|
|
|
|
rDst = rClipped_src;
|
|
|
|
NtGdiSetRect(&offset, 0, 0, dx, dy);
|
2004-01-10 21:59:05 +00:00
|
|
|
IntLPtoDP(DC, (LPPOINT)&offset, 2);
|
2003-12-08 18:21:25 +00:00
|
|
|
NtGdiOffsetRect(&rDst, offset.right - offset.left, offset.bottom - offset.top);
|
|
|
|
NtGdiIntersectRect(&rDst, &rDst, &rClip);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy bits, if possible.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (rDst.bottom > rDst.top && rDst.right > rDst.left)
|
|
|
|
{
|
|
|
|
RECT rDst_lp = rDst, rSrc_lp = rDst;
|
|
|
|
|
|
|
|
NtGdiOffsetRect(&rSrc_lp, offset.left - offset.right, offset.top - offset.bottom);
|
2004-02-03 17:53:55 +00:00
|
|
|
IntDPtoLP(DC, (LPPOINT)&rDst_lp, 2);
|
|
|
|
IntDPtoLP(DC, (LPPOINT)&rSrc_lp, 2);
|
|
|
|
DC_UnlockDc(hDC);
|
2003-12-08 18:21:25 +00:00
|
|
|
|
|
|
|
if (!NtGdiBitBlt(hDC, rDst_lp.left, rDst_lp.top, rDst_lp.right - rDst_lp.left,
|
|
|
|
rDst_lp.bottom - rDst_lp.top, hDC, rSrc_lp.left, rSrc_lp.top,
|
|
|
|
SRCCOPY))
|
|
|
|
return FALSE;
|
|
|
|
}
|
2004-02-03 17:53:55 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
DC_UnlockDc(hDC);
|
|
|
|
}
|
2003-12-08 18:21:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute update areas. This is the clipped source or'ed with the
|
|
|
|
* unclipped source translated minus the clipped src translated (rDst)
|
|
|
|
* all clipped to rClip.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (hrgnUpdate || lprcUpdate)
|
|
|
|
{
|
|
|
|
HRGN hRgn = hrgnUpdate, hRgn2;
|
|
|
|
|
|
|
|
if (hRgn)
|
|
|
|
NtGdiSetRectRgn(hRgn, rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom);
|
|
|
|
else
|
|
|
|
hRgn = NtGdiCreateRectRgn(rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom);
|
|
|
|
|
2004-02-03 17:53:55 +00:00
|
|
|
hRgn2 = UnsafeIntCreateRectRgnIndirect(&rSrc);
|
2003-12-08 18:21:25 +00:00
|
|
|
NtGdiOffsetRgn(hRgn2, offset.right - offset.left, offset.bottom - offset.top);
|
|
|
|
NtGdiCombineRgn(hRgn, hRgn, hRgn2, RGN_OR);
|
|
|
|
|
|
|
|
NtGdiSetRectRgn(hRgn2, rDst.left, rDst.top, rDst.right, rDst.bottom);
|
|
|
|
NtGdiCombineRgn(hRgn, hRgn, hRgn2, RGN_DIFF);
|
|
|
|
|
|
|
|
NtGdiSetRectRgn(hRgn2, rClip.left, rClip.top, rClip.right, rClip.bottom);
|
|
|
|
NtGdiCombineRgn(hRgn, hRgn, hRgn2, RGN_AND);
|
|
|
|
|
|
|
|
if (lprcUpdate)
|
|
|
|
{
|
|
|
|
NtGdiGetRgnBox(hRgn, lprcUpdate);
|
|
|
|
|
|
|
|
/* Put the lprcUpdate in logical coordinate */
|
|
|
|
NtGdiDPtoLP(hDC, (LPPOINT)lprcUpdate, 2);
|
|
|
|
}
|
|
|
|
if (!hrgnUpdate)
|
|
|
|
NtGdiDeleteObject(hRgn);
|
|
|
|
NtGdiDeleteObject(hRgn2);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NtUserScrollWindowEx
|
|
|
|
*
|
|
|
|
* Status
|
2003-12-23 18:19:07 +00:00
|
|
|
* @implemented
|
2003-12-08 18:21:25 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
DWORD STDCALL
|
|
|
|
NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *rect,
|
|
|
|
const RECT *clipRect, HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags)
|
|
|
|
{
|
|
|
|
RECT rc, cliprc, caretrc;
|
|
|
|
INT Result;
|
|
|
|
PWINDOW_OBJECT Window;
|
|
|
|
HDC hDC;
|
|
|
|
HRGN hrgnTemp;
|
|
|
|
HWND hwndCaret;
|
|
|
|
BOOL bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
|
|
|
|
BOOL bOwnRgn = TRUE;
|
|
|
|
|
|
|
|
Window = IntGetWindowObject(hWnd);
|
|
|
|
if (!Window || !IntIsWindowDrawable(Window))
|
|
|
|
{
|
|
|
|
IntReleaseWindowObject(Window);
|
|
|
|
return ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
IntGetClientRect(Window, &rc);
|
|
|
|
if (rect)
|
|
|
|
NtGdiIntersectRect(&rc, &rc, rect);
|
|
|
|
|
|
|
|
if (clipRect)
|
|
|
|
NtGdiIntersectRect(&cliprc, &rc, clipRect);
|
|
|
|
else
|
|
|
|
cliprc = rc;
|
|
|
|
|
|
|
|
if (cliprc.right <= cliprc.left || cliprc.bottom <= cliprc.top ||
|
|
|
|
(dx == 0 && dy == 0))
|
|
|
|
{
|
|
|
|
return NULLREGION;
|
|
|
|
}
|
|
|
|
|
|
|
|
caretrc = rc;
|
|
|
|
hwndCaret = IntFixCaret(hWnd, &caretrc, flags);
|
|
|
|
|
|
|
|
if (hrgnUpdate)
|
|
|
|
bOwnRgn = FALSE;
|
|
|
|
else if (bUpdate)
|
|
|
|
hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0);
|
|
|
|
|
2004-02-03 17:53:55 +00:00
|
|
|
hDC = NtUserGetDCEx(hWnd, 0, DCX_CACHE | DCX_USESTYLE);
|
2003-12-08 18:21:25 +00:00
|
|
|
if (hDC)
|
|
|
|
{
|
|
|
|
NtUserScrollDC(hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate);
|
|
|
|
NtUserReleaseDC(hWnd, hDC);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Take into account the fact that some damage may have occurred during
|
|
|
|
* the scroll.
|
|
|
|
*/
|
|
|
|
|
|
|
|
hrgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
|
|
|
|
Result = NtUserGetUpdateRgn(hWnd, hrgnTemp, FALSE);
|
|
|
|
if (Result != NULLREGION)
|
|
|
|
{
|
2004-02-03 17:53:55 +00:00
|
|
|
HRGN hrgnClip = UnsafeIntCreateRectRgnIndirect(&cliprc);
|
2003-12-08 18:21:25 +00:00
|
|
|
NtGdiOffsetRgn(hrgnTemp, dx, dy);
|
|
|
|
NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnClip, RGN_AND);
|
|
|
|
NtUserRedrawWindow(hWnd, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE);
|
|
|
|
NtGdiDeleteObject(hrgnClip);
|
|
|
|
}
|
|
|
|
NtGdiDeleteObject(hrgnTemp);
|
|
|
|
|
|
|
|
if (flags & SW_SCROLLCHILDREN)
|
|
|
|
{
|
|
|
|
HWND *List = IntWinListChildren(Window);
|
|
|
|
if (List)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
RECT r, dummy;
|
|
|
|
POINT ClientOrigin;
|
|
|
|
|
|
|
|
for (i = 0; List[i]; i++)
|
|
|
|
{
|
|
|
|
NtUserGetWindowRect(List[i], &r);
|
2003-12-23 21:33:25 +00:00
|
|
|
IntGetClientOrigin(hWnd, &ClientOrigin);
|
2003-12-08 18:21:25 +00:00
|
|
|
r.left -= ClientOrigin.x;
|
|
|
|
r.top -= ClientOrigin.y;
|
|
|
|
r.right -= ClientOrigin.x;
|
|
|
|
r.bottom -= ClientOrigin.y;
|
|
|
|
if (!rect || NtGdiIntersectRect(&dummy, &r, &rc))
|
|
|
|
WinPosSetWindowPos(List[i], 0, r.left + dx, r.top + dy, 0, 0,
|
|
|
|
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
|
|
|
|
SWP_NOREDRAW);
|
|
|
|
}
|
|
|
|
ExFreePool(List);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & (SW_INVALIDATE | SW_ERASE))
|
|
|
|
NtUserRedrawWindow(hWnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
|
|
|
|
((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
|
|
|
|
((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0));
|
|
|
|
|
|
|
|
if (bOwnRgn && hrgnUpdate)
|
|
|
|
NtGdiDeleteObject(hrgnUpdate);
|
|
|
|
|
|
|
|
if (hwndCaret)
|
|
|
|
{
|
|
|
|
IntSetCaretPos(caretrc.left + dx, caretrc.top + dy);
|
|
|
|
NtUserShowCaret(hwndCaret);
|
|
|
|
}
|
|
|
|
|
|
|
|
IntReleaseWindowObject(Window);
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2003-05-18 17:16:18 +00:00
|
|
|
/* EOF */
|