/* * 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$ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: Visibility computations * FILE: subsys/win32k/ntuser/vis.c * PROGRAMMER: Ge van Geldorp (ge@gse.nl) */ #include #include #include #include #define NDEBUG #include #include BOOL STATIC FASTCALL VIS_GetVisRect(PDESKTOP_OBJECT Desktop, PWINDOW_OBJECT Window, BOOLEAN ClientArea, RECT* Rect) { PWINDOW_OBJECT DesktopWindow; if (ClientArea) { *Rect = Window->ClientRect; } else { *Rect = Window->WindowRect; } if (0 == (Window->Style & WS_VISIBLE)) { NtGdiSetEmptyRect(Rect); return FALSE; } if (Window->Self == Desktop->DesktopWindow) { return TRUE; } if (0 != (Window->Style & WS_CHILD)) { do { Window = Window->Parent; if (WS_VISIBLE != (Window->Style & (WS_ICONIC | WS_VISIBLE))) { NtGdiSetEmptyRect(Rect); return FALSE; } if (! NtGdiIntersectRect(Rect, Rect, &(Window->ClientRect))) { return FALSE; } } while (0 != (Window->Style & WS_CHILD)); } DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow); if (NULL == DesktopWindow) { ASSERT(FALSE); return FALSE; } if (! NtGdiIntersectRect(Rect, Rect, &(DesktopWindow->ClientRect))) { IntReleaseWindowObject(DesktopWindow); return FALSE; } IntReleaseWindowObject(DesktopWindow); return TRUE; } STATIC BOOL FASTCALL VIS_AddClipRects(PWINDOW_OBJECT Parent, PWINDOW_OBJECT End, HRGN ClipRgn, PRECT Rect) { PWINDOW_OBJECT Child; RECT Intersect; ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock); Child = Parent->FirstChild; while (Child) { if (Child == End) { ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock); return TRUE; } if (Child->Style & WS_VISIBLE) { if (NtGdiIntersectRect(&Intersect, &Child->WindowRect, Rect)) { UnsafeIntUnionRectWithRgn(ClipRgn, &Child->WindowRect); } } Child = Child->NextSibling; } ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock); return FALSE; } HRGN FASTCALL VIS_ComputeVisibleRegion(PDESKTOP_OBJECT Desktop, PWINDOW_OBJECT Window, BOOLEAN ClientArea, BOOLEAN ClipChildren, BOOLEAN ClipSiblings) { HRGN VisRgn; RECT Rect; HRGN ClipRgn; PWINDOW_OBJECT DesktopWindow; INT LeftOffset, TopOffset; DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow); if (NULL == DesktopWindow) { ASSERT(FALSE); return NULL; } if (VIS_GetVisRect(Desktop, Window, ClientArea, &Rect)) { VisRgn = UnsafeIntCreateRectRgnIndirect(&Rect); if (NULL != VisRgn) { if (ClientArea) { LeftOffset = Window->ClientRect.left; TopOffset = Window->ClientRect.top; } else { LeftOffset = Window->WindowRect.left; TopOffset = Window->WindowRect.top; } ClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0); if (ClipRgn != NULL) { if (ClipChildren && Window->FirstChild) { VIS_AddClipRects(Window, NULL, ClipRgn, &Rect); } if (ClipSiblings && 0 != (Window->Style & WS_CHILD)) { VIS_AddClipRects(Window->Parent, Window, ClipRgn, &Rect); } while (0 != (Window->Style & WS_CHILD)) { if (0 != (Window->Style & WS_CLIPSIBLINGS)) { VIS_AddClipRects(Window->Parent, Window, ClipRgn, &Rect); } Window = Window->Parent; } VIS_AddClipRects(DesktopWindow, Window, ClipRgn, &Rect); NtGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF); NtGdiDeleteObject(ClipRgn); NtGdiOffsetRgn(VisRgn, -LeftOffset, -TopOffset); } else { NtGdiDeleteObject(VisRgn); VisRgn = NULL; } } } else { VisRgn = NtGdiCreateRectRgn(0, 0, 0, 0); } IntReleaseWindowObject(DesktopWindow); return VisRgn; } /* FIXME: to be replaced by a normal window proc in CSRSS */ VOID FASTCALL VIS_RepaintDesktop(HWND Desktop, HRGN RepaintRgn) { HDC dc = NtUserGetDC(Desktop); HBRUSH DesktopBrush = NtGdiCreateSolidBrush(RGB(58, 110, 165)); NtGdiFillRgn(dc, RepaintRgn, DesktopBrush); NtGdiDeleteObject(DesktopBrush); NtUserReleaseDC(Desktop, dc); } static VOID FASTCALL GetUncoveredArea(HRGN Uncovered, PWINDOW_OBJECT Parent, PWINDOW_OBJECT TargetChild, BOOL IncludeTarget) { PWINDOW_OBJECT Child; BOOL Passed; HRGN Covered; Passed = FALSE; ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock); Child = Parent->FirstChild; while (! Passed && Child) { if (0 != (Child->Style & WS_VISIBLE) && (Child != TargetChild || IncludeTarget)) { Covered = UnsafeIntCreateRectRgnIndirect(&Child->WindowRect); NtGdiCombineRgn(Uncovered, Uncovered, Covered, RGN_DIFF); NtGdiDeleteObject(Covered); } if (Child == TargetChild) { Passed = TRUE; } Child = Child->NextSibling; } ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock); } VOID FASTCALL VIS_WindowLayoutChanged(PDESKTOP_OBJECT Desktop, PWINDOW_OBJECT Window, HRGN NewlyExposed) { PWINDOW_OBJECT DesktopWindow; PWINDOW_OBJECT Parent; PWINDOW_OBJECT Sibling; PWINDOW_OBJECT TopLevel; HRGN Uncovered; HRGN Repaint; HRGN DirtyRgn; HRGN ExposedWindow; HRGN Covered; INT RgnType; POINT Offset; DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow); Uncovered = UnsafeIntCreateRectRgnIndirect(&DesktopWindow->WindowRect); if (Window->Style & WS_CHILD) { /* Determine our toplevel window */ TopLevel = Window; while (TopLevel->Style & WS_CHILD) { TopLevel = TopLevel->Parent; } GetUncoveredArea(Uncovered, DesktopWindow, TopLevel, FALSE); Parent = Window->Parent; } else { Parent = DesktopWindow; } GetUncoveredArea(Uncovered, Parent, Window, TRUE); ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock); Sibling = Window->NextSibling; while (Sibling) { if (0 != (Sibling->Style & WS_VISIBLE)) { Offset.x = - Sibling->WindowRect.left; Offset.y = - Sibling->WindowRect.top; DirtyRgn = REGION_CropRgn(NULL, Uncovered, &Sibling->WindowRect, &Offset); Offset.x = Window->WindowRect.left - Sibling->WindowRect.left; Offset.y = Window->WindowRect.top - Sibling->WindowRect.top; ExposedWindow = REGION_CropRgn(NULL, NewlyExposed, NULL, &Offset); RgnType = NtGdiCombineRgn(DirtyRgn, DirtyRgn, ExposedWindow, RGN_AND); if (NULLREGION != RgnType && ERROR != RgnType) { PaintRedrawWindow(Sibling, NULL, DirtyRgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN, RDW_EX_XYWINDOW); } Covered = UnsafeIntCreateRectRgnIndirect(&Sibling->WindowRect); NtGdiCombineRgn(Uncovered, Uncovered, Covered, RGN_DIFF); NtGdiDeleteObject(Covered); NtGdiDeleteObject(ExposedWindow); NtGdiDeleteObject(DirtyRgn); } Sibling = Sibling->NextSibling; } ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock); if (Window->Style & WS_CHILD) { Offset.x = - Parent->WindowRect.left; Offset.y = - Parent->WindowRect.top; DirtyRgn = REGION_CropRgn(NULL, Uncovered, &Parent->WindowRect, &Offset); Offset.x = Window->WindowRect.left - Parent->WindowRect.left; Offset.y = Window->WindowRect.top - Parent->WindowRect.top; ExposedWindow = REGION_CropRgn(NULL, NewlyExposed, NULL, &Offset); RgnType = NtGdiCombineRgn(DirtyRgn, DirtyRgn, ExposedWindow, RGN_AND); if (NULLREGION != RgnType && ERROR != RgnType) { PaintRedrawWindow(Parent, NULL, DirtyRgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_NOCHILDREN, RDW_EX_XYWINDOW); } NtGdiDeleteObject(ExposedWindow); NtGdiDeleteObject(DirtyRgn); } else { Repaint = NtGdiCreateRectRgn(0, 0, 0, 0); NtGdiCombineRgn(Repaint, NewlyExposed, NULL, RGN_COPY); NtGdiOffsetRgn(Repaint, Window->WindowRect.left, Window->WindowRect.top); NtGdiCombineRgn(Repaint, Repaint, Uncovered, RGN_AND); VIS_RepaintDesktop(DesktopWindow->Self, Repaint); NtGdiDeleteObject(Repaint); } NtGdiDeleteObject(Uncovered); } /* EOF */