xref: /reactos/win32ss/user/ntuser/vis.c (revision 1734f297)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * PURPOSE:          Visibility computations
5  * FILE:             win32ss/user/ntuser/vis.c
6  * PROGRAMMER:       Ge van Geldorp (ge@gse.nl)
7  */
8 
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserWinpos);
11 
12 PREGION FASTCALL
13 VIS_ComputeVisibleRegion(
14    PWND Wnd,
15    BOOLEAN ClientArea,
16    BOOLEAN ClipChildren,
17    BOOLEAN ClipSiblings)
18 {
19    PREGION VisRgn, ClipRgn;
20    PWND PreviousWindow, CurrentWindow, CurrentSibling;
21 
22    if (!Wnd || !(Wnd->style & WS_VISIBLE))
23    {
24       return NULL;
25    }
26 
27    VisRgn = NULL;
28 
29    if (ClientArea)
30    {
31       VisRgn = IntSysCreateRectpRgnIndirect(&Wnd->rcClient);
32    }
33    else
34    {
35       VisRgn = IntSysCreateRectpRgnIndirect(&Wnd->rcWindow);
36    }
37 
38    /*
39     * Walk through all parent windows and for each clip the visble region
40     * to the parent's client area and exclude all siblings that are over
41     * our window.
42     */
43 
44    PreviousWindow = Wnd;
45    CurrentWindow = Wnd->spwndParent;
46    while (CurrentWindow)
47    {
48       if (!VerifyWnd(CurrentWindow))
49       {
50          ERR("ATM the Current Window or Parent is dead! %p\n",CurrentWindow);
51          if (VisRgn)
52              REGION_Delete(VisRgn);
53          return NULL;
54       }
55 
56       if (!(CurrentWindow->style & WS_VISIBLE))
57       {
58          if (VisRgn)
59              REGION_Delete(VisRgn);
60          return NULL;
61       }
62 
63       ClipRgn = IntSysCreateRectpRgnIndirect(&CurrentWindow->rcClient);
64       IntGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_AND);
65       REGION_Delete(ClipRgn);
66 
67       if ((PreviousWindow->style & WS_CLIPSIBLINGS) ||
68           (PreviousWindow == Wnd && ClipSiblings))
69       {
70          CurrentSibling = CurrentWindow->spwndChild;
71          while ( CurrentSibling != NULL &&
72                  CurrentSibling != PreviousWindow )
73          {
74             if ((CurrentSibling->style & WS_VISIBLE) &&
75                 !(CurrentSibling->ExStyle & WS_EX_TRANSPARENT))
76             {
77                ClipRgn = IntSysCreateRectpRgnIndirect(&CurrentSibling->rcWindow);
78                /* Combine it with the window region if available */
79                if (CurrentSibling->hrgnClip && !(CurrentSibling->style & WS_MINIMIZE))
80                {
81                   PREGION SiblingClipRgn = REGION_LockRgn(CurrentSibling->hrgnClip);
82                   if (SiblingClipRgn)
83                   {
84                       REGION_bOffsetRgn(ClipRgn, -CurrentSibling->rcWindow.left, -CurrentSibling->rcWindow.top);
85                       IntGdiCombineRgn(ClipRgn, ClipRgn, SiblingClipRgn, RGN_AND);
86                       REGION_bOffsetRgn(ClipRgn, CurrentSibling->rcWindow.left, CurrentSibling->rcWindow.top);
87                       REGION_UnlockRgn(SiblingClipRgn);
88                   }
89                }
90                IntGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF);
91                REGION_Delete(ClipRgn);
92             }
93             CurrentSibling = CurrentSibling->spwndNext;
94          }
95       }
96 
97       PreviousWindow = CurrentWindow;
98       CurrentWindow = CurrentWindow->spwndParent;
99    }
100 
101    if (ClipChildren)
102    {
103       CurrentWindow = Wnd->spwndChild;
104       while (CurrentWindow)
105       {
106          if ((CurrentWindow->style & WS_VISIBLE) &&
107              !(CurrentWindow->ExStyle & WS_EX_TRANSPARENT))
108          {
109             ClipRgn = IntSysCreateRectpRgnIndirect(&CurrentWindow->rcWindow);
110             /* Combine it with the window region if available */
111             if (CurrentWindow->hrgnClip && !(CurrentWindow->style & WS_MINIMIZE))
112             {
113                PREGION CurrentRgnClip = REGION_LockRgn(CurrentWindow->hrgnClip);
114                if (CurrentRgnClip)
115                {
116                    REGION_bOffsetRgn(ClipRgn, -CurrentWindow->rcWindow.left, -CurrentWindow->rcWindow.top);
117                    IntGdiCombineRgn(ClipRgn, ClipRgn, CurrentRgnClip, RGN_AND);
118                    REGION_bOffsetRgn(ClipRgn, CurrentWindow->rcWindow.left, CurrentWindow->rcWindow.top);
119                    REGION_UnlockRgn(CurrentRgnClip);
120                }
121             }
122             IntGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF);
123             REGION_Delete(ClipRgn);
124          }
125          CurrentWindow = CurrentWindow->spwndNext;
126       }
127    }
128 
129    if (Wnd->hrgnClip && !(Wnd->style & WS_MINIMIZE))
130    {
131       PREGION WndRgnClip = REGION_LockRgn(Wnd->hrgnClip);
132       if (WndRgnClip)
133       {
134           REGION_bOffsetRgn(VisRgn, -Wnd->rcWindow.left, -Wnd->rcWindow.top);
135           IntGdiCombineRgn(VisRgn, VisRgn, WndRgnClip, RGN_AND);
136           REGION_bOffsetRgn(VisRgn, Wnd->rcWindow.left, Wnd->rcWindow.top);
137           REGION_UnlockRgn(WndRgnClip);
138       }
139    }
140 
141    return VisRgn;
142 }
143 
144 VOID FASTCALL
145 co_VIS_WindowLayoutChanged(
146    PWND Wnd,
147    PREGION NewlyExposed)
148 {
149    PWND Parent;
150    USER_REFERENCE_ENTRY Ref;
151 
152    ASSERT_REFS_CO(Wnd);
153 
154    Parent = Wnd->spwndParent;
155    if(Parent)
156    {
157        PREGION TempRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
158 
159        if (!TempRgn)
160            return;
161 
162        IntGdiCombineRgn(TempRgn, NewlyExposed, NULL, RGN_COPY);
163        REGION_bOffsetRgn(TempRgn,
164                          Wnd->rcWindow.left - Parent->rcClient.left,
165                          Wnd->rcWindow.top - Parent->rcClient.top);
166 
167        UserRefObjectCo(Parent, &Ref);
168        co_UserRedrawWindow(Parent, NULL, TempRgn,
169                            RDW_FRAME | RDW_ERASE | RDW_INVALIDATE |
170                            RDW_ALLCHILDREN);
171        UserDerefObjectCo(Parent);
172 
173        REGION_Delete(TempRgn);
174    }
175 }
176 
177 /* EOF */
178