xref: /reactos/win32ss/user/ntuser/winpos.c (revision 633d2e6d)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS kernel
4  * PURPOSE:     Windows
5  * PROGRAMER:   Casper S. Hornstrup (chorns@users.sourceforge.net)
6  *              Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
7  */
8 
9 #include <win32k.h>
10 #include <immdev.h>
11 DBG_DEFAULT_CHANNEL(UserWinpos);
12 
13 /* GLOBALS *******************************************************************/
14 
15 #define MINMAX_NOSWP  (0x00010000)
16 
17 #define SWP_EX_NOCOPY 0x0001
18 #define SWP_EX_PAINTSELF 0x0002
19 
20 #define  SWP_AGG_NOGEOMETRYCHANGE \
21     (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER)
22 #define  SWP_AGG_NOPOSCHANGE \
23     (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
24 #define  SWP_AGG_STATUSFLAGS \
25     (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
26 #define SWP_AGG_NOCLIENTCHANGE \
27     (SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
28 
29 #define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1)
30 #define PLACE_MIN               0x0001
31 #define PLACE_MAX               0x0002
32 #define PLACE_RECT              0x0004
33 
34 /* FUNCTIONS *****************************************************************/
35 
36 #if DBG
37 /***********************************************************************
38  *           dump_winpos_flags
39  */
dump_winpos_flags(UINT flags)40 static void dump_winpos_flags(UINT flags)
41 {
42     static const DWORD dumped_flags = (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW |
43                                        SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW |
44                                        SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOOWNERZORDER |
45                                        SWP_NOSENDCHANGING | SWP_DEFERERASE | SWP_ASYNCWINDOWPOS |
46                                        SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_STATECHANGED);
47     TRACE("flags:");
48     if(flags & SWP_NOSIZE) TRACE(" SWP_NOSIZE");
49     if(flags & SWP_NOMOVE) TRACE(" SWP_NOMOVE");
50     if(flags & SWP_NOZORDER) TRACE(" SWP_NOZORDER");
51     if(flags & SWP_NOREDRAW) TRACE(" SWP_NOREDRAW");
52     if(flags & SWP_NOACTIVATE) TRACE(" SWP_NOACTIVATE");
53     if(flags & SWP_FRAMECHANGED) TRACE(" SWP_FRAMECHANGED");
54     if(flags & SWP_SHOWWINDOW) TRACE(" SWP_SHOWWINDOW");
55     if(flags & SWP_HIDEWINDOW) TRACE(" SWP_HIDEWINDOW");
56     if(flags & SWP_NOCOPYBITS) TRACE(" SWP_NOCOPYBITS");
57     if(flags & SWP_NOOWNERZORDER) TRACE(" SWP_NOOWNERZORDER");
58     if(flags & SWP_NOSENDCHANGING) TRACE(" SWP_NOSENDCHANGING");
59     if(flags & SWP_DEFERERASE) TRACE(" SWP_DEFERERASE");
60     if(flags & SWP_ASYNCWINDOWPOS) TRACE(" SWP_ASYNCWINDOWPOS");
61     if(flags & SWP_NOCLIENTSIZE) TRACE(" SWP_NOCLIENTSIZE");
62     if(flags & SWP_NOCLIENTMOVE) TRACE(" SWP_NOCLIENTMOVE");
63     if(flags & SWP_STATECHANGED) TRACE(" SWP_STATECHANGED");
64 
65     if(flags & ~dumped_flags) TRACE(" %08x", flags & ~dumped_flags);
66     TRACE("\n");
67 }
68 #endif
69 
70 BOOL FASTCALL
IntGetClientOrigin(PWND Window OPTIONAL,LPPOINT Point)71 IntGetClientOrigin(PWND Window OPTIONAL, LPPOINT Point)
72 {
73    Window = Window ? Window : UserGetDesktopWindow();
74    if (Window == NULL)
75    {
76       Point->x = Point->y = 0;
77       return FALSE;
78    }
79    Point->x = Window->rcClient.left;
80    Point->y = Window->rcClient.top;
81 
82    return TRUE;
83 }
84 
85 /*!
86  * Internal function.
87  * Returns client window rectangle relative to the upper-left corner of client area.
88  *
89  * \note Does not check the validity of the parameters
90 */
91 VOID FASTCALL
IntGetClientRect(PWND Wnd,RECTL * Rect)92 IntGetClientRect(PWND Wnd, RECTL *Rect)
93 {
94    ASSERT( Wnd );
95    ASSERT( Rect );
96    if (Wnd->style & WS_MINIMIZED)
97    {
98       Rect->left = Rect->top = 0;
99       Rect->right = UserGetSystemMetrics(SM_CXMINIMIZED);
100       Rect->bottom = UserGetSystemMetrics(SM_CYMINIMIZED);
101       return;
102    }
103    if (!UserIsDesktopWindow(Wnd))
104    {
105       *Rect = Wnd->rcClient;
106       RECTL_vOffsetRect(Rect, -Wnd->rcClient.left, -Wnd->rcClient.top);
107    }
108    else
109    {
110       Rect->left = Rect->top = 0;
111       Rect->right  = Wnd->rcClient.right;
112       Rect->bottom = Wnd->rcClient.bottom;
113    /* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
114       Rect->right  = UserGetSystemMetrics(SM_CXSCREEN);
115       Rect->bottom = UserGetSystemMetrics(SM_CYSCREEN);
116    */
117    }
118 }
119 
120 BOOL FASTCALL
IntGetWindowRect(PWND Wnd,RECTL * Rect)121 IntGetWindowRect(PWND Wnd, RECTL *Rect)
122 {
123    ASSERT( Wnd );
124    ASSERT( Rect );
125    if (!Wnd) return FALSE;
126    if (!UserIsDesktopWindow(Wnd))
127    {
128        *Rect = Wnd->rcWindow;
129    }
130    else
131    {
132        Rect->left = Rect->top = 0;
133        Rect->right = Wnd->rcWindow.right;
134        Rect->bottom = Wnd->rcWindow.bottom;
135 /* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
136        Rect->right = GetSystemMetrics(SM_CXSCREEN);
137        Rect->bottom = GetSystemMetrics(SM_CYSCREEN);
138 */   }
139    return TRUE;
140 }
141 
142 
143 INT FASTCALL
IntMapWindowPoints(PWND FromWnd,PWND ToWnd,LPPOINT lpPoints,UINT cPoints)144 IntMapWindowPoints(PWND FromWnd, PWND ToWnd, LPPOINT lpPoints, UINT cPoints)
145 {
146     BOOL mirror_from, mirror_to;
147     POINT Delta;
148     UINT i;
149     int Change = 1;
150 
151     /* Note: Desktop Top and Left is always 0! */
152     Delta.x = Delta.y = 0;
153     mirror_from = mirror_to = FALSE;
154 
155     if (FromWnd && !UserIsDesktopWindow(FromWnd))
156     {
157        if (FromWnd->ExStyle & WS_EX_LAYOUTRTL)
158        {
159           mirror_from = TRUE;
160           Change = -Change;
161           Delta.x = -FromWnd->rcClient.right;
162        }
163        else
164           Delta.x = FromWnd->rcClient.left;
165        Delta.y = FromWnd->rcClient.top;
166     }
167 
168     if (ToWnd && !UserIsDesktopWindow(ToWnd))
169     {
170        if (ToWnd->ExStyle & WS_EX_LAYOUTRTL)
171        {
172           mirror_to = TRUE;
173           Change = -Change;
174           Delta.x += Change * ToWnd->rcClient.right;
175        }
176        else
177           Delta.x -= Change * ToWnd->rcClient.left;
178        Delta.y -= ToWnd->rcClient.top;
179     }
180 
181     for (i = 0; i != cPoints; i++)
182     {
183         lpPoints[i].x += Delta.x;
184         lpPoints[i].x *= Change;
185         lpPoints[i].y += Delta.y;
186     }
187 
188     if ((mirror_from || mirror_to) && cPoints == 2)  /* special case for rectangle */
189     {
190        int tmp = min(lpPoints[0].x, lpPoints[1].x);
191        lpPoints[1].x = max(lpPoints[0].x, lpPoints[1].x);
192        lpPoints[0].x = tmp;
193     }
194 
195     return MAKELONG(LOWORD(Delta.x), LOWORD(Delta.y));
196 }
197 
198 BOOL FASTCALL
IntClientToScreen(PWND Wnd,LPPOINT lpPoint)199 IntClientToScreen(PWND Wnd, LPPOINT lpPoint)
200 {
201    if (Wnd && Wnd->fnid != FNID_DESKTOP )
202    {
203       if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
204          lpPoint->x = Wnd->rcClient.right - lpPoint->x;
205       else
206          lpPoint->x += Wnd->rcClient.left;
207       lpPoint->y += Wnd->rcClient.top;
208    }
209    return TRUE;
210 }
211 
212 BOOL FASTCALL
IntScreenToClient(PWND Wnd,LPPOINT lpPoint)213 IntScreenToClient(PWND Wnd, LPPOINT lpPoint)
214 {
215     if (Wnd && Wnd->fnid != FNID_DESKTOP )
216     {
217        if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
218           lpPoint->x = Wnd->rcClient.right - lpPoint->x;
219        else
220           lpPoint->x -= Wnd->rcClient.left;
221        lpPoint->y -= Wnd->rcClient.top;
222     }
223     return TRUE;
224 }
225 
IsChildVisible(PWND pWnd)226 BOOL FASTCALL IsChildVisible(PWND pWnd)
227 {
228     do
229     {
230         if ( (pWnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD ||
231             !(pWnd = pWnd->spwndParent) )
232            return TRUE;
233     }
234     while (pWnd->style & WS_VISIBLE);
235     return FALSE;
236 }
237 
IntGetLastTopMostWindow(VOID)238 PWND FASTCALL IntGetLastTopMostWindow(VOID)
239 {
240     PWND pWnd;
241     PDESKTOP rpdesk = gptiCurrent->rpdesk;
242 
243     if ( rpdesk &&
244         (pWnd = rpdesk->pDeskInfo->spwnd->spwndChild) &&
245          pWnd->ExStyle & WS_EX_TOPMOST)
246     {
247         for (;;)
248         {
249            if (!pWnd->spwndNext) break;
250            if (!(pWnd->spwndNext->ExStyle & WS_EX_TOPMOST)) break;
251            pWnd = pWnd->spwndNext;
252         }
253         return pWnd;
254     }
255     return NULL;
256 }
257 
258 VOID
SelectWindowRgn(PWND Window,HRGN hRgnClip)259 SelectWindowRgn(PWND Window, HRGN hRgnClip)
260 {
261     if (Window->hrgnClip)
262     {
263         /* Delete no longer needed region handle */
264         IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
265         GreDeleteObject(Window->hrgnClip);
266         Window->hrgnClip = NULL;
267     }
268 
269     if (hRgnClip > HRGN_WINDOW)
270     {
271         /*if (!UserIsDesktopWindow(Window))
272         {
273             NtGdiOffsetRgn(hRgnClip, Window->rcWindow.left, Window->rcWindow.top);
274         }*/
275         /* Set public ownership */
276         IntGdiSetRegionOwner(hRgnClip, GDI_OBJ_HMGR_PUBLIC);
277 
278         Window->hrgnClip = hRgnClip;
279     }
280 }
281 
282 //
283 // This helps with CORE-6129 forcing modal dialog active when another app is minimized or closed.
284 //
ActivateOtherWindowMin(PWND Wnd)285 BOOL FASTCALL ActivateOtherWindowMin(PWND Wnd)
286 {
287     BOOL ActivePrev, FindTopWnd;
288     PWND pWndTopMost, pWndChild, pWndSetActive, pWndTemp, pWndDesk;
289     USER_REFERENCE_ENTRY Ref;
290     PTHREADINFO pti = gptiCurrent;
291 
292     //ERR("AOWM 1 %p\n", UserHMGetHandle(Wnd));
293     ActivePrev = (pti->MessageQueue->spwndActivePrev != NULL);
294     FindTopWnd = TRUE;
295 
296     if ((pWndTopMost = IntGetLastTopMostWindow()))
297        pWndChild = pWndTopMost->spwndNext;
298     else
299        pWndChild = Wnd->spwndParent->spwndChild;
300 
301     for (;;)
302     {
303        if ( ActivePrev )
304           pWndSetActive = pti->MessageQueue->spwndActivePrev;
305        else
306           pWndSetActive = pWndChild;
307 
308        pWndTemp = NULL;
309 
310        while(pWndSetActive)
311        {
312           if ( VerifyWnd(pWndSetActive) &&
313               !(pWndSetActive->ExStyle & WS_EX_NOACTIVATE) &&
314                (pWndSetActive->style & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE &&
315                (!(pWndSetActive->style & WS_ICONIC) /* FIXME MinMax pos? */ ) )
316           {
317              if (!(pWndSetActive->ExStyle & WS_EX_TOOLWINDOW) )
318              {
319                 UserRefObjectCo(pWndSetActive, &Ref);
320                 //ERR("ActivateOtherWindowMin Set FG 1\n");
321                 co_IntSetForegroundWindow(pWndSetActive);
322                 UserDerefObjectCo(pWndSetActive);
323                 //ERR("AOWM 2 Exit Good %p\n", UserHMGetHandle(pWndSetActive));
324                 return TRUE;
325              }
326              if (!pWndTemp ) pWndTemp = pWndSetActive;
327           }
328           if ( ActivePrev )
329           {
330              ActivePrev = FALSE;
331              pWndSetActive = pWndChild;
332           }
333           else
334              pWndSetActive = pWndSetActive->spwndNext;
335        }
336 
337        if ( !FindTopWnd ) break;
338        FindTopWnd = FALSE;
339 
340        if ( pWndChild )
341        {
342           pWndChild = pWndChild->spwndParent->spwndChild;
343           continue;
344        }
345 
346        if (!(pWndDesk = IntGetThreadDesktopWindow(pti)))
347        {
348           pWndChild = NULL;
349           continue;
350        }
351        pWndChild = pWndDesk->spwndChild;
352     }
353 
354     if ((pWndSetActive = pWndTemp))
355     {
356        UserRefObjectCo(pWndSetActive, &Ref);
357        //ERR("ActivateOtherWindowMin Set FG 2\n");
358        co_IntSetForegroundWindow(pWndSetActive);
359        UserDerefObjectCo(pWndSetActive);
360        //ERR("AOWM 3 Exit Good %p\n", UserHMGetHandle(pWndSetActive));
361        return TRUE;
362     }
363     //ERR("AOWM 4 Bad\n");
364     return FALSE;
365 }
366 
367 /*******************************************************************
368  *         can_activate_window
369  *
370  * Check if we can activate the specified window.
371  */
372 static
can_activate_window(PWND Wnd OPTIONAL)373 BOOL FASTCALL can_activate_window( PWND Wnd OPTIONAL)
374 {
375     LONG style;
376 
377     if (!Wnd) return FALSE;
378 
379     style = Wnd->style;
380     if (!(style & WS_VISIBLE)) return FALSE;
381     if (style & WS_MINIMIZE) return FALSE;
382     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
383     if (Wnd->ExStyle & WS_EX_NOACTIVATE) return FALSE;
384     return TRUE;
385     /* FIXME: This window could be disable because the child that closed
386               was a popup. */
387     //return !(style & WS_DISABLED);
388 }
389 
390 
391 /*******************************************************************
392  *         WinPosActivateOtherWindow
393  *
394  *  Activates window other than pWnd.
395  */
396 VOID FASTCALL
co_WinPosActivateOtherWindow(PWND Wnd)397 co_WinPosActivateOtherWindow(PWND Wnd)
398 {
399    PWND WndTo = NULL;
400    USER_REFERENCE_ENTRY Ref;
401 
402    ASSERT_REFS_CO(Wnd);
403 
404    if (IntIsDesktopWindow(Wnd))
405    {
406       //ERR("WinPosActivateOtherWindow Set Focus Msg Q No window!\n");
407       IntSetFocusMessageQueue(NULL);
408       return;
409    }
410 
411    /* If this is popup window, try to activate the owner first. */
412    if ((Wnd->style & WS_POPUP) && (WndTo = Wnd->spwndOwner))
413    {
414       TRACE("WPAOW Popup with Owner\n");
415       WndTo = UserGetAncestor( WndTo, GA_ROOT );
416       if (can_activate_window(WndTo)) goto done;
417    }
418 
419    /* Pick a next top-level window. */
420    /* FIXME: Search for non-tooltip windows first. */
421    WndTo = Wnd;
422    for (;;)
423    {
424       if (!(WndTo = WndTo->spwndNext))  break;
425       if (can_activate_window( WndTo )) goto done;
426    }
427 
428    /*
429       Fixes wine win.c:test_SetParent last ShowWindow test after popup dies.
430       Check for previous active window to bring to top.
431    */
432    if (Wnd)
433    {
434       WndTo = Wnd->head.pti->MessageQueue->spwndActivePrev;
435       if (can_activate_window( WndTo )) goto done;
436    }
437 
438    // Find any window to bring to top. Works Okay for wine since it does not see X11 windows.
439    WndTo = UserGetDesktopWindow();
440    if ((WndTo == NULL) || (WndTo->spwndChild == NULL))
441    {
442       //ERR("WinPosActivateOtherWindow No window!\n");
443       return;
444    }
445    WndTo = WndTo->spwndChild;
446    for (;;)
447    {
448       if (WndTo == Wnd)
449       {
450          WndTo = NULL;
451          break;
452       }
453       if (can_activate_window( WndTo )) goto done;
454       if (!(WndTo = WndTo->spwndNext))  break;
455    }
456 
457 done:
458    if (WndTo) UserRefObjectCo(WndTo, &Ref);
459 
460    if (gpqForeground && (!gpqForeground->spwndActive || Wnd == gpqForeground->spwndActive))
461    {
462       /* ReactOS can pass WndTo = NULL to co_IntSetForegroundWindow and returns FALSE. */
463       //ERR("WinPosActivateOtherWindow Set FG 0x%p hWnd %p\n", WndTo, WndTo ? UserHMGetHandle(WndTo) : NULL);
464       if (co_IntSetForegroundWindow(WndTo))
465       {
466          if (WndTo) UserDerefObjectCo(WndTo);
467          return;
468       }
469    }
470    //ERR("WinPosActivateOtherWindow Set Active  0x%p\n",WndTo);
471    if (!UserSetActiveWindow(WndTo))  /* Ok for WndTo to be NULL here */
472    {
473       //ERR("WPAOW SA 1\n");
474       UserSetActiveWindow(NULL);
475    }
476    if (WndTo) UserDerefObjectCo(WndTo);
477 }
478 
479 VOID FASTCALL
WinPosInitInternalPos(PWND Wnd,RECTL * RestoreRect)480 WinPosInitInternalPos(PWND Wnd, RECTL *RestoreRect)
481 {
482    POINT Size;
483    RECTL Rect = *RestoreRect;
484 
485    if (Wnd->spwndParent && !UserIsDesktopWindow(Wnd->spwndParent))
486    {
487       RECTL_vOffsetRect(&Rect,
488                         -Wnd->spwndParent->rcClient.left,
489                         -Wnd->spwndParent->rcClient.top);
490    }
491 
492    Size.x = Rect.left;
493    Size.y = Rect.top;
494 
495    if (!Wnd->InternalPosInitialized)
496    {
497       // FIXME: Use check point Atom..
498       Wnd->InternalPos.flags = 0;
499       Wnd->InternalPos.MaxPos.x  = Wnd->InternalPos.MaxPos.y  = -1;
500       Wnd->InternalPos.IconPos.x = Wnd->InternalPos.IconPos.y = -1;
501       Wnd->InternalPos.NormalRect = Rect;
502       Wnd->InternalPosInitialized = TRUE;
503    }
504 
505    if (Wnd->style & WS_MINIMIZE)
506    {
507       Wnd->InternalPos.IconPos = Size;
508       Wnd->InternalPos.flags |= WPF_MININIT;
509    }
510    else if (Wnd->style & WS_MAXIMIZE)
511    {
512       Wnd->InternalPos.flags |= WPF_MAXINIT;
513 
514       if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd )
515       {
516          if (Wnd->state & WNDS_MAXIMIZESTOMONITOR)
517          {
518             Wnd->InternalPos.flags &= ~WPF_MAXINIT;
519             Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1;
520          }
521          else
522          {
523             RECTL WorkArea;
524             PMONITOR pmonitor = UserMonitorFromRect(&Rect, MONITOR_DEFAULTTOPRIMARY );
525             // FIXME: support DPI aware, rcWorkDPI/Real etc..
526             WorkArea = pmonitor->rcMonitor;
527 
528             if (Wnd->style & WS_MAXIMIZEBOX)
529             {  // Support (Wnd->state & WNDS_HASCAPTION) || pmonitor->cFullScreen too.
530                if ((Wnd->style & WS_CAPTION) == WS_CAPTION || !(Wnd->style & (WS_CHILD | WS_POPUP)))
531                {
532                   WorkArea = pmonitor->rcWork;
533                   //ERR("rcWork\n");
534                }
535             }
536 
537             Wnd->InternalPos.MaxPos.x = Rect.left - WorkArea.left;
538             Wnd->InternalPos.MaxPos.y = Rect.top  - WorkArea.top;
539 
540             /*ERR("WinPosIP 2 X %d = R.l %d - W.l %d | Y %d = R.t %d - W.t %d\n",
541                                          Wnd->InternalPos.MaxPos.x,
542                                          Rect.left, WorkArea.left,
543                                          Wnd->InternalPos.MaxPos.y,
544                                          Rect.top, WorkArea.top);*/
545          }
546       }
547       else
548          Wnd->InternalPos.MaxPos = Size;
549    }
550    else
551    {
552       /* Lie about the snap; Windows does this so applications don't save their
553        * position as a snap but rather the unsnapped "real" position. */
554       if (!IntIsWindowSnapped(Wnd) ||
555           RECTL_bIsEmptyRect(&Wnd->InternalPos.NormalRect))
556       {
557          Wnd->InternalPos.NormalRect = Rect;
558       }
559    }
560 }
561 
562 BOOL
563 FASTCALL
IntGetWindowPlacement(PWND Wnd,WINDOWPLACEMENT * lpwndpl)564 IntGetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *lpwndpl)
565 {
566    if (!Wnd) return FALSE;
567 
568    if(lpwndpl->length != sizeof(WINDOWPLACEMENT))
569    {
570       ERR("length mismatch: %u\n", lpwndpl->length);
571       return FALSE;
572    }
573 
574    lpwndpl->flags = 0;
575 
576    WinPosInitInternalPos(Wnd, &Wnd->rcWindow);
577 
578    lpwndpl->showCmd = SW_HIDE;
579 
580    if ( Wnd->style & WS_MINIMIZE )
581       lpwndpl->showCmd = SW_SHOWMINIMIZED;
582    else
583       lpwndpl->showCmd = ( Wnd->style & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
584 
585    lpwndpl->rcNormalPosition = Wnd->InternalPos.NormalRect;
586 
587    if (Wnd->InternalPos.flags & WPF_MININIT) // Return if it was set!
588    {
589       lpwndpl->ptMinPosition.x = Wnd->InternalPos.IconPos.x;
590       lpwndpl->ptMinPosition.y = Wnd->InternalPos.IconPos.y;
591    }
592    else
593       lpwndpl->ptMinPosition.x = lpwndpl->ptMinPosition.y = -1;
594 
595    if ( Wnd->InternalPos.flags & WPF_MAXINIT && // Return if set and not maximized to monitor!
596         !(Wnd->state & WNDS_MAXIMIZESTOMONITOR))
597    {
598       lpwndpl->ptMaxPosition.x = Wnd->InternalPos.MaxPos.x;
599       lpwndpl->ptMaxPosition.y = Wnd->InternalPos.MaxPos.y;
600    }
601    else
602       lpwndpl->ptMaxPosition.x = lpwndpl->ptMaxPosition.y = -1;
603 
604    if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd &&
605        !(Wnd->ExStyle & WS_EX_TOOLWINDOW))
606    {
607       PMONITOR pmonitor = UserMonitorFromRect(&lpwndpl->rcNormalPosition, MONITOR_DEFAULTTOPRIMARY );
608 
609       // FIXME: support DPI aware, rcWorkDPI/Real etc..
610       if (Wnd->InternalPos.flags & WPF_MININIT)
611       {
612          lpwndpl->ptMinPosition.x -= (pmonitor->rcWork.left - pmonitor->rcMonitor.left);
613          lpwndpl->ptMinPosition.y -= (pmonitor->rcWork.top - pmonitor->rcMonitor.top);
614       }
615       RECTL_vOffsetRect(&lpwndpl->rcNormalPosition,
616                          pmonitor->rcMonitor.left - pmonitor->rcWork.left,
617                          pmonitor->rcMonitor.top  - pmonitor->rcWork.top);
618    }
619 
620    if ( Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED || Wnd->style & WS_MAXIMIZE )
621       lpwndpl->flags |= WPF_RESTORETOMAXIMIZED;
622 
623    if ( ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD) && Wnd->InternalPos.flags & WPF_SETMINPOSITION)
624       lpwndpl->flags |= WPF_SETMINPOSITION;
625 
626    return TRUE;
627 }
628 
629 /* make sure the specified rect is visible on screen */
make_rect_onscreen(RECT * rect)630 static void make_rect_onscreen( RECT *rect )
631 {
632     PMONITOR pmonitor = UserMonitorFromRect( rect, MONITOR_DEFAULTTONEAREST ); // Wine uses this.
633 
634     //  FIXME: support DPI aware, rcWorkDPI/Real etc..
635     if (!pmonitor) return;
636     /* FIXME: map coordinates from rcWork to rcMonitor */
637     if (rect->right <= pmonitor->rcWork.left)
638     {
639         rect->right += pmonitor->rcWork.left - rect->left;
640         rect->left = pmonitor->rcWork.left;
641     }
642     else if (rect->left >= pmonitor->rcWork.right)
643     {
644         rect->left += pmonitor->rcWork.right - rect->right;
645         rect->right = pmonitor->rcWork.right;
646     }
647     if (rect->bottom <= pmonitor->rcWork.top)
648     {
649         rect->bottom += pmonitor->rcWork.top - rect->top;
650         rect->top = pmonitor->rcWork.top;
651     }
652     else if (rect->top >= pmonitor->rcWork.bottom)
653     {
654         rect->top += pmonitor->rcWork.bottom - rect->bottom;
655         rect->bottom = pmonitor->rcWork.bottom;
656     }
657 }
658 
659 /* make sure the specified point is visible on screen */
make_point_onscreen(POINT * pt)660 static void make_point_onscreen( POINT *pt )
661 {
662     RECT rect;
663 
664     RECTL_vSetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 );
665     make_rect_onscreen( &rect );
666     pt->x = rect.left;
667     pt->y = rect.top;
668 }
669 
670 BOOL FASTCALL
IntSetWindowPlacement(PWND Wnd,WINDOWPLACEMENT * wpl,UINT Flags)671 IntSetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *wpl, UINT Flags)
672 {
673    BOOL sAsync;
674    UINT SWP_Flags;
675 
676    if ( Flags & PLACE_MIN) make_point_onscreen( &wpl->ptMinPosition );
677    if ( Flags & PLACE_MAX) make_point_onscreen( &wpl->ptMaxPosition );
678    if ( Flags & PLACE_RECT) make_rect_onscreen( &wpl->rcNormalPosition );
679 
680    if (!Wnd || Wnd == Wnd->head.rpdesk->pDeskInfo->spwnd) return FALSE;
681 
682    if ( Flags & PLACE_MIN ) Wnd->InternalPos.IconPos = wpl->ptMinPosition;
683    if ( Flags & PLACE_MAX ) Wnd->InternalPos.MaxPos = wpl->ptMaxPosition;
684    if ( Flags & PLACE_RECT) Wnd->InternalPos.NormalRect = wpl->rcNormalPosition;
685 
686    SWP_Flags = SWP_NOZORDER | SWP_NOACTIVATE | ((wpl->flags & WPF_ASYNCWINDOWPLACEMENT) ? SWP_ASYNCWINDOWPOS : 0);
687 
688    if (Wnd->style & WS_MINIMIZE )
689    {
690       if (Flags & PLACE_MIN || Wnd->InternalPos.flags & WPF_SETMINPOSITION)
691       {
692          co_WinPosSetWindowPos(Wnd, HWND_TOP,
693                                wpl->ptMinPosition.x, wpl->ptMinPosition.y, 0, 0,
694                                SWP_NOSIZE | SWP_Flags);
695          Wnd->InternalPos.flags |= WPF_MININIT;
696       }
697    }
698    else if (Wnd->style & WS_MAXIMIZE )
699    {
700       if (Flags & PLACE_MAX)
701       {
702          co_WinPosSetWindowPos(Wnd, HWND_TOP,
703                                wpl->ptMaxPosition.x, wpl->ptMaxPosition.y, 0, 0,
704                                SWP_NOSIZE | SWP_Flags);
705          Wnd->InternalPos.flags |= WPF_MAXINIT;
706       }
707    }
708    else if (Flags & PLACE_RECT)
709    {
710       co_WinPosSetWindowPos(Wnd, HWND_TOP,
711                             wpl->rcNormalPosition.left, wpl->rcNormalPosition.top,
712                             wpl->rcNormalPosition.right - wpl->rcNormalPosition.left,
713                             wpl->rcNormalPosition.bottom - wpl->rcNormalPosition.top,
714                             SWP_Flags);
715    }
716 
717    sAsync = (Wnd->head.pti->MessageQueue != gptiCurrent->MessageQueue && wpl->flags & WPF_ASYNCWINDOWPLACEMENT);
718 
719    if ( sAsync )
720       co_IntSendMessageNoWait( UserHMGetHandle(Wnd), WM_ASYNC_SHOWWINDOW, wpl->showCmd, 0 );
721    else
722       co_WinPosShowWindow(Wnd, wpl->showCmd);
723 
724    if ( Wnd->style & WS_MINIMIZE && !sAsync )
725    {
726       if ( wpl->flags & WPF_SETMINPOSITION )
727          Wnd->InternalPos.flags |= WPF_SETMINPOSITION;
728 
729       if ( wpl->flags & WPF_RESTORETOMAXIMIZED )
730          Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
731    }
732    return TRUE;
733 }
734 
735 UINT
736 FASTCALL
co_WinPosArrangeIconicWindows(PWND parent)737 co_WinPosArrangeIconicWindows(PWND parent)
738 {
739    RECTL rectParent;
740    PWND Child;
741    INT x, y, xspacing, yspacing, sx, sy;
742 
743    ASSERT_REFS_CO(parent);
744 
745    IntGetClientRect( parent, &rectParent );
746    // FIXME: Support Minimize Metrics gspv.mm.iArrange.
747    // Default: ARW_BOTTOMLEFT
748    x = rectParent.left;
749    y = rectParent.bottom;
750 
751    xspacing = UserGetSystemMetrics(SM_CXMINIMIZED);
752    yspacing = UserGetSystemMetrics(SM_CYMINIMIZED);
753 
754    Child = parent->spwndChild;
755    while(Child)
756    {
757       if((Child->style & WS_MINIMIZE) != 0 )
758       {
759          USER_REFERENCE_ENTRY Ref;
760          UserRefObjectCo(Child, &Ref);
761 
762          sx = x + UserGetSystemMetrics(SM_CXBORDER);
763          sy = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
764 
765          Child->InternalPos.IconPos.x = sx;
766          Child->InternalPos.IconPos.y = sy;
767          Child->InternalPos.flags |= WPF_MININIT;
768 
769          co_WinPosSetWindowPos( Child, 0, sx, sy, xspacing, yspacing, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_ASYNCWINDOWPOS);
770 
771          UserDerefObjectCo(Child);
772 
773          if (x <= rectParent.right - xspacing)
774             x += xspacing;
775          else
776          {
777             x = rectParent.left;
778             y -= yspacing;
779          }
780       }
781       Child = Child->spwndNext;
782    }
783    return yspacing;
784 }
785 
786 static VOID FASTCALL
WinPosFindIconPos(PWND Window,POINT * Pos)787 WinPosFindIconPos(PWND Window, POINT *Pos)
788 {
789    RECT rectParent;
790    PWND pwndChild, pwndParent;
791    int x, y, xspacing, yspacing;
792 
793    pwndParent = Window->spwndParent;
794    if (UserIsDesktopWindow(pwndParent))
795    {
796       ERR("FIXME: Parent is Desktop, Min off screen!\n");
797       /* FIXME: ReactOS doesn't support iconic minimize to desktop */
798       Pos->x = Pos->y = -32000;
799       Window->InternalPos.flags |= WPF_MININIT;
800       Window->InternalPos.IconPos.x = Pos->x;
801       Window->InternalPos.IconPos.y = Pos->y;
802       return;
803    }
804 
805    IntGetClientRect( pwndParent, &rectParent );
806    // FIXME: Support Minimize Metrics gspv.mm.iArrange.
807    // Default: ARW_BOTTOMLEFT
808    x = rectParent.left;
809    y = rectParent.bottom;
810 
811    xspacing = UserGetSystemMetrics(SM_CXMINIMIZED);
812    yspacing = UserGetSystemMetrics(SM_CYMINIMIZED);
813 
814    // Set to default position when minimized.
815    Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
816    Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
817 
818    for (pwndChild = pwndParent->spwndChild; pwndChild; pwndChild = pwndChild->spwndNext)
819    {
820         if (pwndChild == Window) continue;
821 
822         if ((pwndChild->style & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE) )
823         {
824             continue;
825         }
826 
827         if ( pwndChild->InternalPos.IconPos.x != Pos->x && pwndChild->InternalPos.IconPos.y != Pos->y )
828         {
829            break;
830         }
831         if (x <= rectParent.right - xspacing)
832             x += xspacing;
833         else
834         {
835             x = rectParent.left;
836             y -= yspacing;
837         }
838         Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
839         Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
840    }
841 
842    Window->InternalPos.IconPos.x = Pos->x;
843    Window->InternalPos.IconPos.y = Pos->y;
844    Window->InternalPos.flags |= WPF_MININIT;
845    TRACE("Position is set! X:%d Y:%d\n",Pos->x,Pos->y);
846    return;
847 }
848 
849 BOOL
UserHasWindowEdge(DWORD Style,DWORD ExStyle)850 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
851 {
852    if (Style & WS_MINIMIZE)
853       return TRUE;
854    if (ExStyle & WS_EX_DLGMODALFRAME)
855       return TRUE;
856    if (ExStyle & WS_EX_STATICEDGE)
857       return FALSE;
858    if (Style & WS_THICKFRAME)
859       return TRUE;
860    Style &= WS_CAPTION;
861    if (Style == WS_DLGFRAME || Style == WS_CAPTION)
862       return TRUE;
863    return FALSE;
864 }
865 
866 VOID FASTCALL
IntGetWindowBorderMeasures(PWND Wnd,UINT * cx,UINT * cy)867 IntGetWindowBorderMeasures(PWND Wnd, UINT *cx, UINT *cy)
868 {
869    if(HAS_DLGFRAME(Wnd->style, Wnd->ExStyle) && !(Wnd->style & WS_MINIMIZE))
870    {
871       *cx = UserGetSystemMetrics(SM_CXDLGFRAME);
872       *cy = UserGetSystemMetrics(SM_CYDLGFRAME);
873    }
874    else
875    {
876       if(HAS_THICKFRAME(Wnd->style, Wnd->ExStyle)&& !(Wnd->style & WS_MINIMIZE))
877       {
878          *cx = UserGetSystemMetrics(SM_CXFRAME);
879          *cy = UserGetSystemMetrics(SM_CYFRAME);
880       }
881       else if(HAS_THINFRAME(Wnd->style, Wnd->ExStyle))
882       {
883          *cx = UserGetSystemMetrics(SM_CXBORDER);
884          *cy = UserGetSystemMetrics(SM_CYBORDER);
885       }
886       else
887       {
888          *cx = *cy = 0;
889       }
890    }
891 }
892 
893 VOID
UserGetWindowBorders(DWORD Style,DWORD ExStyle,SIZE * Size,BOOL WithClient)894 UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
895 {
896    DWORD Border = 0;
897 
898    if (UserHasWindowEdge(Style, ExStyle))
899       Border += 2;
900    else if ((ExStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE)
901       Border += 1; /* for the outer frame always present */
902    if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
903       Border += 2;
904    if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
905       Border ++; /* The other border */
906    Size->cx = Size->cy = Border;
907    if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE)) /* The resize border */
908    {
909       Size->cx += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME);
910       Size->cy += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME);
911    }
912    Size->cx *= UserGetSystemMetrics(SM_CXBORDER);
913    Size->cy *= UserGetSystemMetrics(SM_CYBORDER);
914 }
915 
916 //
917 // Fix CORE-5177
918 // See winetests:user32:win.c:wine_AdjustWindowRectEx,
919 // Simplified version.
920 //
IntGetWindowBorders(DWORD Style,DWORD ExStyle)921 DWORD IntGetWindowBorders(DWORD Style, DWORD ExStyle)
922 {
923     DWORD adjust = 0;
924 
925     if ( ExStyle & WS_EX_WINDOWEDGE )      // 1st
926         adjust = 2; /* outer */
927     else if ( ExStyle & WS_EX_STATICEDGE ) // 2nd
928         adjust = 1; /* for the outer frame always present */
929 
930     if (ExStyle & WS_EX_CLIENTEDGE)
931        adjust += 2;
932 
933     if ( Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME )
934         adjust++; /* The other border */
935 
936     return adjust;
937 }
938 
939 UINT FASTCALL
co_WinPosGetMinMaxInfo(PWND Window,POINT * MaxSize,POINT * MaxPos,POINT * MinTrack,POINT * MaxTrack)940 co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
941                        POINT* MinTrack, POINT* MaxTrack)
942 {
943     MINMAXINFO MinMax;
944     PMONITOR monitor;
945     INT xinc, yinc;
946     LONG style = Window->style;
947     LONG adjustedStyle;
948     LONG exstyle = Window->ExStyle;
949     RECT rc;
950     DWORD adjust;
951 
952     ASSERT_REFS_CO(Window);
953 
954     /* Compute default values */
955 
956     rc = Window->rcWindow;
957     MinMax.ptReserved.x = rc.left;
958     MinMax.ptReserved.y = rc.top;
959 
960     if ((style & WS_CAPTION) == WS_CAPTION)
961         adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
962     else
963         adjustedStyle = style;
964 
965     if (Window->spwndParent)
966         IntGetClientRect(Window->spwndParent, &rc);
967 
968     adjust = IntGetWindowBorders(adjustedStyle, exstyle);
969 
970     // Handle special case while maximized. CORE-15893
971     if ((adjustedStyle & WS_THICKFRAME) && !(adjustedStyle & WS_CHILD) && !(adjustedStyle & WS_MINIMIZE))
972          adjust += 1;
973 
974     xinc = yinc = adjust;
975 
976     if ((adjustedStyle & WS_THICKFRAME) && (adjustedStyle & WS_CHILD) && !(adjustedStyle & WS_MINIMIZE))
977     {
978         xinc += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME);
979         yinc += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME);
980     }
981 
982     RECTL_vInflateRect( &rc,
983                         xinc * UserGetSystemMetrics(SM_CXBORDER),
984                         yinc * UserGetSystemMetrics(SM_CYBORDER) );
985 
986     xinc = -rc.left;
987     yinc = -rc.top;
988 
989     MinMax.ptMaxSize.x = rc.right - rc.left;
990     MinMax.ptMaxSize.y = rc.bottom - rc.top;
991     if (style & (WS_DLGFRAME | WS_BORDER))
992     {
993         MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
994         MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
995     }
996     else
997     {
998         MinMax.ptMinTrackSize.x = 2 * xinc;
999         MinMax.ptMinTrackSize.y = 2 * yinc;
1000     }
1001     MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK);
1002     MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK);
1003     MinMax.ptMaxPosition.x = -xinc;
1004     MinMax.ptMaxPosition.y = -yinc;
1005 
1006     if (!EMPTYPOINT(Window->InternalPos.MaxPos)) MinMax.ptMaxPosition = Window->InternalPos.MaxPos;
1007 
1008     co_IntSendMessage(UserHMGetHandle(Window), WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
1009 
1010     /* if the app didn't change the values, adapt them for the current monitor */
1011     if ((monitor = UserGetPrimaryMonitor()))
1012     {
1013         RECT rc_work;
1014 
1015         rc_work = monitor->rcMonitor;
1016 
1017         if (style & WS_MAXIMIZEBOX)
1018         {
1019             if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
1020                rc_work = monitor->rcWork;
1021         }
1022 
1023         if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
1024             MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
1025         {
1026             MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
1027             MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
1028         }
1029         if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
1030         {
1031             MinMax.ptMaxPosition.x = rc_work.left - xinc;
1032             MinMax.ptMaxPosition.y = rc_work.top - yinc;
1033         }
1034         if (MinMax.ptMaxSize.x >= (monitor->rcMonitor.right - monitor->rcMonitor.left) &&
1035             MinMax.ptMaxSize.y >= (monitor->rcMonitor.bottom - monitor->rcMonitor.top) )
1036         {
1037             Window->state |= WNDS_MAXIMIZESTOMONITOR;
1038         }
1039         else
1040             Window->state &= ~WNDS_MAXIMIZESTOMONITOR;
1041     }
1042 
1043 
1044     MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
1045                                   MinMax.ptMinTrackSize.x);
1046     MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
1047                                   MinMax.ptMinTrackSize.y);
1048 
1049     if (MaxSize)
1050        *MaxSize = MinMax.ptMaxSize;
1051     if (MaxPos)
1052        *MaxPos = MinMax.ptMaxPosition;
1053     if (MinTrack)
1054        *MinTrack = MinMax.ptMinTrackSize;
1055     if (MaxTrack)
1056        *MaxTrack = MinMax.ptMaxTrackSize;
1057 
1058     return 0; // FIXME: What does it return? Wine returns MINMAXINFO.
1059 }
1060 
1061 static
1062 BOOL
IntValidateParent(PWND Child,PREGION ValidateRgn)1063 IntValidateParent(PWND Child, PREGION ValidateRgn)
1064 {
1065    PWND ParentWnd = Child->spwndParent;
1066 
1067    while (ParentWnd)
1068    {
1069       if (ParentWnd->style & WS_CLIPCHILDREN)
1070          break;
1071 
1072       if (ParentWnd->hrgnUpdate != 0)
1073       {
1074          IntInvalidateWindows( ParentWnd,
1075                                ValidateRgn,
1076                                RDW_VALIDATE | RDW_NOCHILDREN);
1077       }
1078 
1079       ParentWnd = ParentWnd->spwndParent;
1080    }
1081 
1082    return TRUE;
1083 }
1084 
1085 static
1086 VOID FASTCALL
FixClientRect(PRECTL ClientRect,PRECTL WindowRect)1087 FixClientRect(PRECTL ClientRect, PRECTL WindowRect)
1088 {
1089    if (ClientRect->left < WindowRect->left)
1090    {
1091       ClientRect->left = WindowRect->left;
1092    }
1093    else if (WindowRect->right < ClientRect->left)
1094    {
1095       ClientRect->left = WindowRect->right;
1096    }
1097    if (ClientRect->right < WindowRect->left)
1098    {
1099       ClientRect->right = WindowRect->left;
1100    }
1101    else if (WindowRect->right < ClientRect->right)
1102    {
1103       ClientRect->right = WindowRect->right;
1104    }
1105    if (ClientRect->top < WindowRect->top)
1106    {
1107       ClientRect->top = WindowRect->top;
1108    }
1109    else if (WindowRect->bottom < ClientRect->top)
1110    {
1111       ClientRect->top = WindowRect->bottom;
1112    }
1113    if (ClientRect->bottom < WindowRect->top)
1114    {
1115       ClientRect->bottom = WindowRect->top;
1116    }
1117    else if (WindowRect->bottom < ClientRect->bottom)
1118    {
1119       ClientRect->bottom = WindowRect->bottom;
1120    }
1121 }
1122 /***********************************************************************
1123  *           get_valid_rects
1124  *
1125  * Compute the valid rects from the old and new client rect and WVR_* flags.
1126  * Helper for WM_NCCALCSIZE handling.
1127  */
1128 static
1129 VOID FASTCALL
get_valid_rects(RECTL * old_client,RECTL * new_client,UINT flags,RECTL * valid)1130 get_valid_rects( RECTL *old_client, RECTL *new_client, UINT flags, RECTL *valid )
1131 {
1132     int cx, cy;
1133 
1134     if (flags & WVR_REDRAW)
1135     {
1136         RECTL_vSetEmptyRect( &valid[0] );
1137         RECTL_vSetEmptyRect( &valid[1] );
1138         return;
1139     }
1140 
1141     if (flags & WVR_VALIDRECTS)
1142     {
1143         if (!RECTL_bIntersectRect( &valid[0], &valid[0], new_client ) ||
1144             !RECTL_bIntersectRect( &valid[1], &valid[1], old_client ))
1145         {
1146             RECTL_vSetEmptyRect( &valid[0] );
1147             RECTL_vSetEmptyRect( &valid[1] );
1148             return;
1149         }
1150         flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
1151     }
1152     else
1153     {
1154         valid[0] = *new_client;
1155         valid[1] = *old_client;
1156     }
1157 
1158     /* make sure the rectangles have the same size */
1159     cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
1160     cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
1161 
1162     if (flags & WVR_ALIGNBOTTOM)
1163     {
1164         valid[0].top = valid[0].bottom - cy;
1165         valid[1].top = valid[1].bottom - cy;
1166     }
1167     else
1168     {
1169         valid[0].bottom = valid[0].top + cy;
1170         valid[1].bottom = valid[1].top + cy;
1171     }
1172     if (flags & WVR_ALIGNRIGHT)
1173     {
1174         valid[0].left = valid[0].right - cx;
1175         valid[1].left = valid[1].right - cx;
1176     }
1177     else
1178     {
1179         valid[0].right = valid[0].left + cx;
1180         valid[1].right = valid[1].left + cx;
1181     }
1182 }
1183 
1184 static
1185 LONG FASTCALL
co_WinPosDoNCCALCSize(PWND Window,PWINDOWPOS WinPos,RECTL * WindowRect,RECTL * ClientRect,RECTL * validRects)1186 co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos, RECTL* WindowRect, RECTL* ClientRect, RECTL* validRects)
1187 {
1188    PWND Parent;
1189    UINT wvrFlags = 0;
1190 
1191    ASSERT_REFS_CO(Window);
1192 
1193    /* Send WM_NCCALCSIZE message to get new client area */
1194    if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
1195    {
1196       NCCALCSIZE_PARAMS params;
1197       WINDOWPOS winposCopy;
1198 
1199       params.rgrc[0] = *WindowRect;      // new coordinates of a window that has been moved or resized
1200       params.rgrc[1] = Window->rcWindow; // window before it was moved or resized
1201       params.rgrc[2] = Window->rcClient; // client area before the window was moved or resized
1202 
1203       Parent = Window->spwndParent;
1204       if (0 != (Window->style & WS_CHILD) && Parent)
1205       {
1206          RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left, - Parent->rcClient.top);
1207          RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left, - Parent->rcClient.top);
1208          RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left, - Parent->rcClient.top);
1209       }
1210 
1211       params.lppos = &winposCopy;
1212       winposCopy = *WinPos;
1213 
1214       wvrFlags = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCALCSIZE, TRUE, (LPARAM)&params);
1215 
1216       /* If the application send back garbage, ignore it */
1217       if (params.rgrc[0].left <= params.rgrc[0].right &&
1218           params.rgrc[0].top <= params.rgrc[0].bottom)
1219       {
1220          *ClientRect = params.rgrc[0]; // First rectangle contains the coordinates of the new client rectangle resulting from the move or resize
1221          if ((Window->style & WS_CHILD) && Parent)
1222          {
1223             RECTL_vOffsetRect(ClientRect, Parent->rcClient.left, Parent->rcClient.top);
1224          }
1225          FixClientRect(ClientRect, WindowRect);
1226       }
1227 
1228       if (ClientRect->left != Window->rcClient.left ||
1229           ClientRect->top != Window->rcClient.top)
1230       {
1231          WinPos->flags &= ~SWP_NOCLIENTMOVE;
1232       }
1233 
1234       if (ClientRect->right - ClientRect->left != Window->rcClient.right - Window->rcClient.left)
1235       {
1236          WinPos->flags &= ~SWP_NOCLIENTSIZE;
1237       }
1238       else
1239          wvrFlags &= ~WVR_HREDRAW;
1240 
1241       if (ClientRect->bottom - ClientRect->top != Window->rcClient.bottom - Window->rcClient.top)
1242       {
1243          WinPos->flags &= ~SWP_NOCLIENTSIZE;
1244       }
1245       else
1246          wvrFlags &= ~WVR_VREDRAW;
1247 
1248       validRects[0] = params.rgrc[1]; // second rectangle contains the valid destination rectangle
1249       validRects[1] = params.rgrc[2]; // third rectangle contains the valid source rectangle
1250    }
1251    else
1252    {
1253       if (!(WinPos->flags & SWP_NOMOVE) &&
1254           (ClientRect->left != Window->rcClient.left ||
1255            ClientRect->top != Window->rcClient.top))
1256       {
1257          WinPos->flags &= ~SWP_NOCLIENTMOVE;
1258       }
1259    }
1260 
1261    if (WinPos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
1262    {
1263       RECTL_vSetEmptyRect( &validRects[0] );
1264       RECTL_vSetEmptyRect( &validRects[1] );
1265    }
1266    else get_valid_rects( &Window->rcClient, ClientRect, wvrFlags, validRects );
1267 
1268    return wvrFlags;
1269 }
1270 
1271 static
1272 BOOL FASTCALL
co_WinPosDoWinPosChanging(PWND Window,PWINDOWPOS WinPos,PRECTL WindowRect,PRECTL ClientRect)1273 co_WinPosDoWinPosChanging(PWND Window,
1274                           PWINDOWPOS WinPos,
1275                           PRECTL WindowRect,
1276                           PRECTL ClientRect)
1277 {
1278    ASSERT_REFS_CO(Window);
1279 
1280    /* Send WM_WINDOWPOSCHANGING message */
1281 
1282    if (!(WinPos->flags & SWP_NOSENDCHANGING)
1283           && !((WinPos->flags & SWP_AGG_NOCLIENTCHANGE) && (WinPos->flags & SWP_SHOWWINDOW)))
1284    {
1285       TRACE("Sending WM_WINDOWPOSCHANGING to hwnd %p flags %04x.\n", UserHMGetHandle(Window), WinPos->flags);
1286       co_IntSendMessage(UserHMGetHandle(Window), WM_WINDOWPOSCHANGING, 0, (LPARAM)WinPos);
1287    }
1288 
1289    /* Calculate new position and size */
1290 
1291    *WindowRect = Window->rcWindow;
1292    *ClientRect = (Window->style & WS_MINIMIZE) ? Window->rcWindow : Window->rcClient;
1293 
1294    if (!(WinPos->flags & SWP_NOSIZE))
1295    {
1296       if (Window->style & WS_MINIMIZE)
1297       {
1298          WindowRect->right  = WindowRect->left + UserGetSystemMetrics(SM_CXMINIMIZED);
1299          WindowRect->bottom = WindowRect->top  + UserGetSystemMetrics(SM_CYMINIMIZED);
1300       }
1301       else
1302       {
1303          WindowRect->right = WindowRect->left + WinPos->cx;
1304          WindowRect->bottom = WindowRect->top + WinPos->cy;
1305       }
1306    }
1307 
1308    if (!(WinPos->flags & SWP_NOMOVE))
1309    {
1310       INT X, Y;
1311       PWND Parent;
1312       X = WinPos->x;
1313       Y = WinPos->y;
1314 
1315       Parent = Window->spwndParent;
1316 
1317       // Parent child position issue is in here. SetParent_W7 test CORE-6651.
1318       if (//((Window->style & WS_CHILD) != 0) && <- Fixes wine msg test_SetParent: "rects do not match", the last test.
1319            Parent &&
1320            Parent != Window->head.rpdesk->pDeskInfo->spwnd)
1321       {
1322          TRACE("Not SWP_NOMOVE 1 Parent client offset X %d Y %d\n",X,Y);
1323          X += Parent->rcClient.left;
1324          Y += Parent->rcClient.top;
1325          TRACE("Not SWP_NOMOVE 2 Parent client offset X %d Y %d\n",X,Y);
1326       }
1327 
1328       WindowRect->left    = X;
1329       WindowRect->top     = Y;
1330       WindowRect->right  += X - Window->rcWindow.left;
1331       WindowRect->bottom += Y - Window->rcWindow.top;
1332 
1333       RECTL_vOffsetRect(ClientRect, X - Window->rcWindow.left,
1334                                     Y - Window->rcWindow.top);
1335    }
1336    WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1337 
1338    TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
1339            WinPos->hwnd, WinPos->hwndInsertAfter, WinPos->x, WinPos->y,
1340            WinPos->cx, WinPos->cy, WinPos->flags );
1341    TRACE("WindowRect: %d %d %d %d\n", WindowRect->left,WindowRect->top,WindowRect->right,WindowRect->bottom);
1342    TRACE("ClientRect: %d %d %d %d\n", ClientRect->left,ClientRect->top,ClientRect->right,ClientRect->bottom);
1343 
1344    return TRUE;
1345 }
1346 
1347 /*
1348  * Fix Z order taking into account owned popups -
1349  * basically we need to maintain them above the window that owns them
1350  *
1351  * FIXME: hide/show owned popups when owner visibility changes.
1352  *
1353  * ReactOS: See bug CORE-6129 and CORE-6554.
1354  *
1355  */
1356  ////
1357  // Pass all the win:test_children/popup_zorder tests except "move hwnd_F and its popups down" which is if'ed out.
1358  // Side effect, breaks more of the DeferWindowPos api tests, but wine breaks more!!!!
1359 static
1360 HWND FASTCALL
WinPosDoOwnedPopups(PWND Window,HWND hWndInsertAfter)1361 WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter)
1362 {
1363    HWND *List = NULL;
1364    HWND Owner;
1365    LONG Style;
1366    PWND DesktopWindow, ChildObject;
1367    int i;
1368 
1369    TRACE("(%p) hInsertAfter = %p\n", Window, hWndInsertAfter );
1370 
1371    Style = Window->style;
1372 
1373    if (Style & WS_CHILD)
1374    {
1375       TRACE("Window is child\n");
1376       return hWndInsertAfter;
1377    }
1378 
1379    Owner = (Window->spwndOwner ? UserHMGetHandle(Window->spwndOwner) : NULL);
1380 
1381    if (Owner)
1382    {
1383       /* Make sure this popup stays above the owner */
1384 
1385       if (hWndInsertAfter != HWND_TOPMOST)
1386       {
1387          DesktopWindow = UserGetDesktopWindow();
1388          List = IntWinListChildren(DesktopWindow);
1389 
1390          if (List != NULL)
1391          {
1392             for (i = 0; List[i]; i++)
1393             {
1394                BOOL topmost = FALSE;
1395 
1396                ChildObject = ValidateHwndNoErr(List[i]);
1397                if (ChildObject)
1398                {
1399                   topmost = (ChildObject->ExStyle & WS_EX_TOPMOST) != 0;
1400                }
1401 
1402                if (List[i] == Owner)
1403                {
1404                   /* We found its Owner, so we must handle it here. */
1405                   if (i > 0)
1406                   {
1407                      if (List[i - 1] != UserHMGetHandle(Window))
1408                      {
1409                         /*
1410                          * If the popup to be inserted is not already just
1411                          * before the Owner, insert it there. The modified
1412                          * hWndInsertAfter will be handled below.
1413                          *
1414                          * (NOTE: Do not allow hWndInsertAfter to become equal
1415                          * to the popup's window handle, as this would cause
1416                          * the popup to link to itself).
1417                          */
1418                         hWndInsertAfter = List[i - 1];
1419                      }
1420                      else
1421                      {
1422                         /* If the popup to be inserted is already
1423                          * before the Owner, we are done. */
1424                         ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1425                         return hWndInsertAfter;
1426                      }
1427                   }
1428                   else
1429                   {
1430                      hWndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
1431                   }
1432                   break;
1433                }
1434 
1435                if (hWndInsertAfter == HWND_TOP || hWndInsertAfter ==  HWND_NOTOPMOST)
1436                {
1437                   if (!topmost) break;
1438                }
1439                else if (List[i] == hWndInsertAfter) break;
1440             }
1441          }
1442          else
1443             return hWndInsertAfter;
1444       }
1445    }
1446 
1447    if (hWndInsertAfter == HWND_BOTTOM)
1448    {
1449       ERR("Window is HWND_BOTTOM hwnd %p\n",hWndInsertAfter);
1450       if (List) ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1451       goto done;
1452    }
1453 
1454    if (!List)
1455    {
1456       DesktopWindow = UserGetDesktopWindow();
1457       List = IntWinListChildren(DesktopWindow);
1458    }
1459 
1460    if (List != NULL)
1461    {
1462       i = 0;
1463 
1464       if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1465       {
1466          if (hWndInsertAfter == HWND_NOTOPMOST || !(Window->ExStyle & WS_EX_TOPMOST))
1467          {
1468             TRACE("skip all the topmost windows\n");
1469             /* skip all the topmost windows */
1470             while (List[i] &&
1471                    (ChildObject = ValidateHwndNoErr(List[i])) &&
1472                    (ChildObject->ExStyle & WS_EX_TOPMOST)) i++;
1473          }
1474       }
1475       else if (hWndInsertAfter != HWND_TOPMOST)
1476       {
1477         /* skip windows that are already placed correctly */
1478         for (i = 0; List[i]; i++)
1479         {
1480             if (List[i] == hWndInsertAfter) break;
1481             if (List[i] == UserHMGetHandle(Window))
1482             {
1483                ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1484                goto done;  /* nothing to do if window is moving backwards in z-order */
1485             }
1486         }
1487       }
1488 
1489       for (; List[i]; i++)
1490       {
1491          PWND Wnd;
1492          USER_REFERENCE_ENTRY Ref;
1493 
1494          if (List[i] == UserHMGetHandle(Window))
1495             break;
1496 
1497          if (!(Wnd = ValidateHwndNoErr(List[i])))
1498             continue;
1499 
1500          Owner = (Wnd->spwndOwner ? UserHMGetHandle(Wnd->spwndOwner) : NULL);
1501 
1502          if (Owner != UserHMGetHandle(Window)) continue;
1503 
1504          UserRefObjectCo(Wnd, &Ref);
1505          TRACE( "moving %p owned by %p after %p\n", List[i], UserHMGetHandle(Window), hWndInsertAfter );
1506          co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
1507                                SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING| SWP_DEFERERASE);
1508 
1509          UserDerefObjectCo(Wnd);
1510          hWndInsertAfter = List[i];
1511       }
1512       ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1513    }
1514 done:
1515    return hWndInsertAfter;
1516 }
1517 ////
1518 
1519 /***********************************************************************
1520  *      WinPosInternalMoveWindow
1521  *
1522  * Update WindowRect and ClientRect of Window and all of its children
1523  * We keep both WindowRect and ClientRect in screen coordinates internally
1524  */
1525 static
1526 VOID FASTCALL
WinPosInternalMoveWindow(PWND Window,INT MoveX,INT MoveY)1527 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
1528 {
1529    PWND Child;
1530 
1531    ASSERT(Window != Window->spwndChild);
1532    TRACE("InternalMoveWin  X %d Y %d\n", MoveX, MoveY);
1533 
1534    Window->rcWindow.left += MoveX;
1535    Window->rcWindow.right += MoveX;
1536    Window->rcWindow.top += MoveY;
1537    Window->rcWindow.bottom += MoveY;
1538 
1539    Window->rcClient.left += MoveX;
1540    Window->rcClient.right += MoveX;
1541    Window->rcClient.top += MoveY;
1542    Window->rcClient.bottom += MoveY;
1543 
1544    for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
1545    {
1546       WinPosInternalMoveWindow(Child, MoveX, MoveY);
1547    }
1548 }
1549 
1550 /*
1551  * WinPosFixupSWPFlags
1552  *
1553  * Fix redundant flags and values in the WINDOWPOS structure.
1554  */
1555 static
1556 BOOL FASTCALL
WinPosFixupFlags(WINDOWPOS * WinPos,PWND Wnd)1557 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
1558 {
1559    PWND Parent;
1560    POINT pt;
1561 
1562    /* Finally make sure that all coordinates are valid */
1563    if (WinPos->x < -32768) WinPos->x = -32768;
1564    else if (WinPos->x > 32767) WinPos->x = 32767;
1565    if (WinPos->y < -32768) WinPos->y = -32768;
1566    else if (WinPos->y > 32767) WinPos->y = 32767;
1567 
1568    WinPos->cx = max(WinPos->cx, 0);
1569    WinPos->cy = max(WinPos->cy, 0);
1570 
1571    Parent = UserGetAncestor( Wnd, GA_PARENT );
1572    if (!IntIsWindowVisible( Parent ) &&
1573       /* Fix B : wine msg test_SetParent:WmSetParentSeq_2:25 wParam bits! */
1574        (WinPos->flags & SWP_AGG_STATUSFLAGS) == SWP_AGG_NOPOSCHANGE) WinPos->flags |= SWP_NOREDRAW;
1575 
1576    if (Wnd->style & WS_VISIBLE) WinPos->flags &= ~SWP_SHOWWINDOW;
1577    else
1578    {
1579       WinPos->flags &= ~SWP_HIDEWINDOW;
1580       if (!(WinPos->flags & SWP_SHOWWINDOW)) WinPos->flags |= SWP_NOREDRAW;
1581    }
1582 
1583    /* Check for right size */
1584    if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
1585        Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
1586    {
1587       WinPos->flags |= SWP_NOSIZE;
1588    }
1589 
1590    pt.x = WinPos->x;
1591    pt.y = WinPos->y;
1592    IntClientToScreen( Parent, &pt );
1593    TRACE("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y);
1594    /* Check for right position */
1595    if (Wnd->rcWindow.left == pt.x && Wnd->rcWindow.top == pt.y)
1596    {
1597       //ERR("In right pos\n");
1598       WinPos->flags |= SWP_NOMOVE;
1599    }
1600 
1601    if ( WinPos->hwnd != UserGetForegroundWindow() && (Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1602    {
1603       /* Bring to the top when activating */
1604       if (!(WinPos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) &&
1605            (WinPos->flags & SWP_NOZORDER ||
1606            (WinPos->hwndInsertAfter != HWND_TOPMOST && WinPos->hwndInsertAfter != HWND_NOTOPMOST)))
1607       {
1608          WinPos->flags &= ~SWP_NOZORDER;
1609          WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP);
1610       }
1611    }
1612 
1613    /* Check hwndInsertAfter */
1614    if (!(WinPos->flags & SWP_NOZORDER))
1615    {
1616       /* Fix sign extension */
1617       if (WinPos->hwndInsertAfter == (HWND)0xffff)
1618       {
1619          WinPos->hwndInsertAfter = HWND_TOPMOST;
1620       }
1621       else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
1622       {
1623          WinPos->hwndInsertAfter = HWND_NOTOPMOST;
1624       }
1625 
1626       if (WinPos->hwndInsertAfter == HWND_TOP)
1627       {
1628          /* Keep it topmost when it's already topmost */
1629          if ((Wnd->ExStyle & WS_EX_TOPMOST) != 0)
1630             WinPos->hwndInsertAfter = HWND_TOPMOST;
1631 
1632          if (IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1633          {
1634             WinPos->flags |= SWP_NOZORDER;
1635          }
1636       }
1637       else if (WinPos->hwndInsertAfter == HWND_BOTTOM)
1638       {
1639          if (!(Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDLAST) == WinPos->hwnd)
1640             WinPos->flags |= SWP_NOZORDER;
1641       }
1642       else if (WinPos->hwndInsertAfter == HWND_TOPMOST)
1643       {
1644           if ((Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1645              WinPos->flags |= SWP_NOZORDER;
1646       }
1647       else if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
1648       {
1649          if (!(Wnd->ExStyle & WS_EX_TOPMOST))
1650             WinPos->flags |= SWP_NOZORDER;
1651       }
1652       else /* hwndInsertAfter must be a sibling of the window */
1653       {
1654          PWND InsAfterWnd;
1655 
1656          InsAfterWnd = ValidateHwndNoErr(WinPos->hwndInsertAfter);
1657          if(!InsAfterWnd)
1658          {
1659              return TRUE;
1660          }
1661 
1662          if (InsAfterWnd->spwndParent != Wnd->spwndParent)
1663          {
1664             /* Note from wine User32 Win test_SetWindowPos:
1665                "Returns TRUE also for windows that are not siblings"
1666                "Does not seem to do anything even without passing flags, still returns TRUE"
1667                "Same thing the other way around."
1668                ".. and with these windows."
1669              */
1670             return FALSE;
1671          }
1672          else
1673          {
1674             /*
1675              * We don't need to change the Z order of hwnd if it's already
1676              * inserted after hwndInsertAfter or when inserting hwnd after
1677              * itself.
1678              */
1679             if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
1680                 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == UserHMGetHandle(InsAfterWnd->spwndNext))))
1681             {
1682                WinPos->flags |= SWP_NOZORDER;
1683             }
1684          }
1685       }
1686    }
1687 
1688    return TRUE;
1689 }
1690 
1691 //
1692 // This is a NC HACK fix for forcing painting of non client areas.
1693 // Further troubleshooting in painting.c is required to remove this hack.
1694 // See CORE-7166 & CORE-15934
1695 //
1696 VOID
ForceNCPaintErase(PWND Wnd,HRGN hRgn,PREGION pRgn)1697 ForceNCPaintErase(PWND Wnd, HRGN hRgn, PREGION pRgn)
1698 {
1699    HDC hDC;
1700    PREGION RgnUpdate;
1701    UINT RgnType;
1702    BOOL Create = FALSE;
1703 
1704    if (Wnd->hrgnUpdate == NULL)
1705    {
1706        Wnd->hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0);
1707        IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC);
1708        Create = TRUE;
1709    }
1710 
1711    if (Wnd->hrgnUpdate != HRGN_WINDOW)
1712    {
1713        RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate);
1714        if (RgnUpdate)
1715        {
1716            RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, pRgn, RGN_OR);
1717            REGION_UnlockRgn(RgnUpdate);
1718            if (RgnType == NULLREGION)
1719            {
1720                IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
1721                GreDeleteObject(Wnd->hrgnUpdate);
1722                Wnd->hrgnUpdate = NULL;
1723                Create = FALSE;
1724            }
1725        }
1726    }
1727 
1728    IntSendNCPaint( Wnd, hRgn ); // Region can be deleted by the application.
1729 
1730    if (Wnd->hrgnUpdate)
1731    {
1732        hDC = UserGetDCEx( Wnd,
1733                           Wnd->hrgnUpdate,
1734                           DCX_CACHE|DCX_USESTYLE|DCX_INTERSECTRGN|DCX_KEEPCLIPRGN);
1735 
1736       Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
1737       // Kill the loop, so Clear before we send.
1738       if (!co_IntSendMessage(UserHMGetHandle(Wnd), WM_ERASEBKGND, (WPARAM)hDC, 0))
1739       {
1740           Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND);
1741       }
1742       UserReleaseDC(Wnd, hDC, FALSE);
1743    }
1744 
1745    if (Create)
1746    {
1747       IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
1748       GreDeleteObject(Wnd->hrgnUpdate);
1749       Wnd->hrgnUpdate = NULL;
1750    }
1751 }
1752 
IntImeWindowPosChanged(VOID)1753 static VOID FASTCALL IntImeWindowPosChanged(VOID)
1754 {
1755     HWND *phwnd;
1756     PWND pwndNode, pwndDesktop = UserGetDesktopWindow();
1757     PWINDOWLIST pWL;
1758     USER_REFERENCE_ENTRY Ref;
1759 
1760     if (!pwndDesktop)
1761         return;
1762 
1763     /* Enumerate the windows to get the IME windows (of default and non-default) */
1764     pWL = IntBuildHwndList(pwndDesktop->spwndChild, IACE_LIST, gptiCurrent);
1765     if (!pWL)
1766         return;
1767 
1768     for (phwnd = pWL->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd)
1769     {
1770         if (gptiCurrent->TIF_flags & TIF_INCLEANUP)
1771             break;
1772 
1773         pwndNode = ValidateHwndNoErr(*phwnd);
1774         if (pwndNode == NULL ||
1775             pwndNode->head.pti != gptiCurrent ||
1776             pwndNode->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
1777         {
1778             continue;
1779         }
1780 
1781         /* Now hwndNode is an IME window of the current thread */
1782         UserRefObjectCo(pwndNode, &Ref);
1783         co_IntSendMessage(*phwnd, WM_IME_SYSTEM, IMS_UPDATEIMEUI, 0);
1784         UserDerefObjectCo(pwndNode);
1785     }
1786 
1787     IntFreeHwndList(pWL);
1788 }
1789 
1790 /* x and y are always screen relative */
1791 BOOLEAN FASTCALL
co_WinPosSetWindowPos(PWND Window,HWND WndInsertAfter,INT x,INT y,INT cx,INT cy,UINT flags)1792 co_WinPosSetWindowPos(
1793    PWND Window,
1794    HWND WndInsertAfter,
1795    INT x,
1796    INT y,
1797    INT cx,
1798    INT cy,
1799    UINT flags
1800    )
1801 {
1802    WINDOWPOS WinPos;
1803    RECTL NewWindowRect;
1804    RECTL NewClientRect;
1805    RECTL valid_rects[2];
1806    PREGION VisBefore = NULL;
1807    PREGION VisBeforeJustClient = NULL;
1808    PREGION VisAfter = NULL;
1809    PREGION CopyRgn = NULL;
1810    ULONG WvrFlags = 0;
1811    RECTL OldWindowRect, OldClientRect;
1812    int RgnType;
1813    HDC Dc;
1814    RECTL CopyRect;
1815    PWND Ancestor;
1816    BOOL bPointerInWindow, PosChanged = FALSE;
1817    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1818 
1819    ASSERT_REFS_CO(Window);
1820 
1821    TRACE("pwnd %p, after %p, %d,%d (%dx%d), flags 0x%x\n",
1822          Window, WndInsertAfter, x, y, cx, cy, flags);
1823 #if DBG
1824    dump_winpos_flags(flags);
1825 #endif
1826 
1827    /* FIXME: Get current active window from active queue. Why? since r2915. */
1828 
1829    bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
1830 
1831    WinPos.hwnd = UserHMGetHandle(Window);
1832    WinPos.hwndInsertAfter = WndInsertAfter;
1833    WinPos.x = x;
1834    WinPos.y = y;
1835    WinPos.cx = cx;
1836    WinPos.cy = cy;
1837    WinPos.flags = flags;
1838 
1839    if ( flags & SWP_ASYNCWINDOWPOS )
1840    {
1841       LRESULT lRes;
1842       PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
1843       if ( ppos )
1844       {
1845          WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag.
1846          *ppos = WinPos;
1847          /* Yes it's a pointer inside Win32k! */
1848          lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
1849          /* We handle this the same way as Event Hooks and Hooks. */
1850          if ( !lRes )
1851          {
1852             ExFreePoolWithTag(ppos, USERTAG_SWP);
1853             return FALSE;
1854          }
1855          return TRUE;
1856       }
1857       return FALSE;
1858    }
1859 
1860    co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1861 
1862    /* Does the window still exist? */
1863    if (!IntIsWindow(WinPos.hwnd))
1864    {
1865       TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd);
1866       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1867       return FALSE;
1868    }
1869 
1870    /* Fix up the flags. */
1871    if (!WinPosFixupFlags(&WinPos, Window))
1872    {
1873       // See Note.
1874       return TRUE;
1875    }
1876 
1877    Ancestor = UserGetAncestor(Window, GA_PARENT);
1878    if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER &&
1879          Ancestor && UserHMGetHandle(Ancestor) == IntGetDesktopWindow() )
1880    {
1881       WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
1882    }
1883 
1884    if (!(WinPos.flags & SWP_NOREDRAW))
1885    {
1886       /* Compute the visible region before the window position is changed */
1887       if (!(WinPos.flags & SWP_SHOWWINDOW) &&
1888            (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1889                              SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1890             (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1891       {
1892          VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1893                                               (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1894 
1895          if ( VisBefore != NULL &&
1896               REGION_Complexity(VisBefore) == NULLREGION )
1897          {
1898             REGION_Delete(VisBefore);
1899             VisBefore = NULL;
1900          }
1901          else if(VisBefore)
1902          {
1903             REGION_bOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1904          }
1905 
1906          /* Calculate the non client area for resizes, as this is used in the copy region */
1907          if ((WinPos.flags & (SWP_NOSIZE | SWP_FRAMECHANGED)) != SWP_NOSIZE)
1908          {
1909              VisBeforeJustClient = VIS_ComputeVisibleRegion(Window, TRUE, FALSE,
1910                  (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1911 
1912              if ( VisBeforeJustClient != NULL &&
1913                  REGION_Complexity(VisBeforeJustClient) == NULLREGION )
1914              {
1915                  REGION_Delete(VisBeforeJustClient);
1916                  VisBeforeJustClient = NULL;
1917              }
1918              else if(VisBeforeJustClient)
1919              {
1920                  REGION_bOffsetRgn(VisBeforeJustClient, -Window->rcWindow.left, -Window->rcWindow.top);
1921              }
1922          }
1923       }
1924    }
1925 
1926    //// HACK 3
1927    if (Window->hrgnNewFrame)
1928    {
1929        SelectWindowRgn( Window, Window->hrgnNewFrame ); // Should be PSMWP->acvr->hrgnClip
1930        Window->hrgnNewFrame = NULL;
1931    }
1932 
1933    WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects);
1934 
1935 //   ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags,
1936 //      valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom,
1937 //      valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom);
1938 
1939    /* Validate link windows. (also take into account shell window in hwndShellWindow) */
1940    if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1941    {
1942       IntLinkHwnd(Window, WinPos.hwndInsertAfter);
1943    }
1944 
1945    OldWindowRect = Window->rcWindow;
1946    OldClientRect = Window->rcClient;
1947 
1948    if (NewClientRect.left != OldClientRect.left ||
1949        NewClientRect.top  != OldClientRect.top)
1950    {
1951       // Move child window if their parent is moved. Keep Child window relative to Parent...
1952       WinPosInternalMoveWindow(Window,
1953                                NewClientRect.left - OldClientRect.left,
1954                                NewClientRect.top - OldClientRect.top);
1955       PosChanged = TRUE;
1956    }
1957 
1958    Window->rcWindow = NewWindowRect;
1959    Window->rcClient = NewClientRect;
1960 
1961    /* erase parent when hiding or resizing child */
1962    if (WinPos.flags & SWP_HIDEWINDOW)
1963    {
1964       /* Clear the update region */
1965       co_UserRedrawWindow( Window,
1966                            NULL,
1967                            0,
1968                            RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1969 
1970       if (UserIsDesktopWindow(Window->spwndParent))
1971          co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)UserHMGetHandle(Window), 0);
1972 
1973       Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE );
1974       Window->head.pti->cVisWindows--;
1975       IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1976    }
1977    else if (WinPos.flags & SWP_SHOWWINDOW)
1978    {
1979       if (Window->style & WS_CHILD)
1980       {
1981          if ((Window->style & WS_POPUP) && (Window->ExStyle & WS_EX_APPWINDOW))
1982          {
1983             co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)UserHMGetHandle(Window), 0);
1984             if (!(WinPos.flags & SWP_NOACTIVATE))
1985                UpdateShellHook(Window);
1986          }
1987       }
1988       else if ((Window->ExStyle & WS_EX_APPWINDOW) ||
1989           (!(Window->ExStyle & WS_EX_TOOLWINDOW) && !Window->spwndOwner &&
1990            (!Window->spwndParent || UserIsDesktopWindow(Window->spwndParent))))
1991       {
1992          if (!UserIsDesktopWindow(Window))
1993          {
1994             co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)UserHMGetHandle(Window), 0);
1995             if (!(WinPos.flags & SWP_NOACTIVATE))
1996                UpdateShellHook(Window);
1997          }
1998       }
1999 
2000       Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
2001       Window->head.pti->cVisWindows++;
2002       IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2003    }
2004    else
2005    {
2006       IntCheckFullscreen(Window);
2007    }
2008 
2009    if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
2010    {
2011       NtGdiOffsetRgn(Window->hrgnUpdate,
2012                      NewWindowRect.left - OldWindowRect.left,
2013                      NewWindowRect.top - OldWindowRect.top);
2014    }
2015 
2016    DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
2017 
2018    // Change or update, set send non-client paint flag.
2019    if ( Window->style & WS_VISIBLE &&
2020        (WinPos.flags & SWP_STATECHANGED || (!(Window->state2 & WNDS2_WIN31COMPAT) && WinPos.flags & SWP_NOREDRAW ) ) )
2021    {
2022       TRACE("Set WNDS_SENDNCPAINT %p\n",Window);
2023       Window->state |= WNDS_SENDNCPAINT;
2024    }
2025 
2026    if (!(WinPos.flags & SWP_NOREDRAW) && ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE))
2027    {
2028       /* Determine the new visible region */
2029       VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
2030                                           (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
2031 
2032       if ( VisAfter != NULL &&
2033            REGION_Complexity(VisAfter) == NULLREGION )
2034       {
2035          REGION_Delete(VisAfter);
2036          VisAfter = NULL;
2037       }
2038       else if(VisAfter)
2039       {
2040          REGION_bOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
2041       }
2042 
2043       /*
2044        * Determine which pixels can be copied from the old window position
2045        * to the new. Those pixels must be visible in both the old and new
2046        * position. Also, check the class style to see if the windows of this
2047        * class need to be completely repainted on (horizontal/vertical) size
2048        * change.
2049        */
2050       if (VisBefore != NULL &&
2051           VisAfter != NULL &&
2052           !(WvrFlags & WVR_REDRAW) &&
2053           !(WinPos.flags & SWP_NOCOPYBITS) &&
2054           !(Window->ExStyle & WS_EX_TRANSPARENT))
2055       {
2056 
2057          /*
2058           * If this is (also) a window resize, the whole nonclient area
2059           * needs to be repainted. So we limit the copy to the client area,
2060           * 'cause there is no use in copying it (would possibly cause
2061           * "flashing" too). However, if the copy region is already empty,
2062           * we don't have to crop (can't take anything away from an empty
2063           * region...)
2064           */
2065 
2066          CopyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2067          if ((WinPos.flags & SWP_NOSIZE) && (WinPos.flags & SWP_NOCLIENTSIZE))
2068             RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
2069          else if (VisBeforeJustClient != NULL)
2070          {
2071             RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND);
2072          }
2073 
2074          /* Now use in copying bits which are in the update region. */
2075          if (Window->hrgnUpdate != NULL)
2076          {
2077             PREGION RgnUpdate = REGION_LockRgn(Window->hrgnUpdate);
2078             if (RgnUpdate)
2079             {
2080                 REGION_bOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
2081                 IntGdiCombineRgn(CopyRgn, CopyRgn, RgnUpdate, RGN_DIFF);
2082                 REGION_bOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
2083                 REGION_UnlockRgn(RgnUpdate);
2084             }
2085          }
2086 
2087          /*
2088           * Now, get the bounding box of the copy region. If it's empty
2089           * there's nothing to copy. Also, it's no use copying bits onto
2090           * themselves.
2091           */
2092          if (REGION_GetRgnBox(CopyRgn, &CopyRect) == NULLREGION)
2093          {
2094             /* Nothing to copy, clean up */
2095             REGION_Delete(CopyRgn);
2096             CopyRgn = NULL;
2097          }
2098          else if ( OldWindowRect.left != NewWindowRect.left ||
2099                    OldWindowRect.top != NewWindowRect.top ||
2100                   (WinPos.flags & SWP_FRAMECHANGED) )
2101          {
2102              HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
2103              PREGION DcRgnObj = REGION_LockRgn(DcRgn);
2104 
2105           /*
2106            * Small trick here: there is no function to bitblt a region. So
2107            * we set the region as the clipping region, take the bounding box
2108            * of the region and bitblt that. Since nothing outside the clipping
2109            * region is copied, this has the effect of bitblt'ing the region.
2110            *
2111            * Since NtUserGetDCEx takes ownership of the clip region, we need
2112            * to create a copy of CopyRgn and pass that. We need CopyRgn later
2113            */
2114             IntGdiCombineRgn(DcRgnObj, CopyRgn, NULL, RGN_COPY);
2115             REGION_bOffsetRgn(DcRgnObj, NewWindowRect.left, NewWindowRect.top);
2116             REGION_UnlockRgn(DcRgnObj);
2117             Dc = UserGetDCEx( Window,
2118                               DcRgn,
2119                               DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN); // DCX_WINDOW will set first, go read WinDC.c.
2120             NtGdiBitBlt( Dc,
2121                          CopyRect.left, CopyRect.top,
2122                          CopyRect.right - CopyRect.left,
2123                          CopyRect.bottom - CopyRect.top,
2124                          Dc,
2125                          CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
2126                          CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
2127                          SRCCOPY,
2128                          0,
2129                          0);
2130 
2131             UserReleaseDC(Window, Dc, FALSE);
2132             IntValidateParent(Window, CopyRgn);
2133             GreDeleteObject(DcRgn);
2134          }
2135       }
2136       else
2137       {
2138          CopyRgn = NULL;
2139       }
2140 
2141       /* We need to redraw what wasn't visible before or force a redraw */
2142       if (VisAfter != NULL)
2143       {
2144          PREGION DirtyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2145          if (DirtyRgn)
2146          {
2147              if (CopyRgn != NULL)
2148              {
2149                 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
2150              }
2151              else
2152              {
2153                 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
2154              }
2155 
2156              if (RgnType != ERROR && RgnType != NULLREGION) // Regions moved.
2157              {
2158             /* old code
2159                 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2160                 IntInvalidateWindows( Window,
2161                                       DirtyRgn,
2162                    RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2163              }
2164              GreDeleteObject(DirtyRgn);
2165              */
2166 
2167                 PWND Parent = Window->spwndParent;
2168 
2169                 REGION_bOffsetRgn( DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2170 
2171                 if ( (Window->style & WS_CHILD) && (Parent) && !(Parent->style & WS_CLIPCHILDREN))
2172                 {
2173                    IntInvalidateWindows( Parent, DirtyRgn, RDW_ERASE | RDW_INVALIDATE);
2174                    co_IntPaintWindows(Parent, RDW_NOCHILDREN, FALSE);
2175                 }
2176                 IntInvalidateWindows(Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2177              }
2178              else if (RgnType != ERROR && RgnType == NULLREGION) // Must be the same. See CORE-7166 & CORE-15934, NC HACK fix.
2179              {
2180                 if ( !PosChanged &&
2181                      !(WinPos.flags & SWP_DEFERERASE) &&
2182                       (WinPos.flags & SWP_FRAMECHANGED) )
2183                 {
2184                     PWND pwnd = Window;
2185                     PWND Parent = Window->spwndParent;
2186 
2187                     if ( pwnd->style & WS_CHILD ) // Fix ProgMan menu bar drawing.
2188                     {
2189                         TRACE("SWP_FRAMECHANGED win child %p Parent %p\n",pwnd,Parent);
2190                         pwnd = Parent ? Parent : pwnd;
2191                     }
2192 
2193                     if ( !(pwnd->style & WS_CHILD) )
2194                     {
2195                         /*
2196                          * Check if we have these specific windows style bits set/reset.
2197                          * FIXME: There may be other combinations of styles that need this handling as well.
2198                          * This fixes the ReactOS Calculator buttons disappearing in CORE-16827.
2199                          */
2200                         if ((Window->style & WS_CLIPSIBLINGS) && !(Window->style & (WS_POPUP | WS_CLIPCHILDREN | WS_SIZEBOX)))
2201                         {
2202                             IntSendNCPaint(pwnd, HRGN_WINDOW); // Paint the whole frame.
2203                         }
2204                         else  // Use region handling
2205                         {
2206                             HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
2207                             PREGION DcRgnObj = REGION_LockRgn(DcRgn);
2208                             TRACE("SWP_FRAMECHANGED win %p hRgn %p\n",pwnd, DcRgn);
2209                             IntGdiCombineRgn(DcRgnObj, VisBefore, NULL, RGN_COPY);
2210                             REGION_UnlockRgn(DcRgnObj);
2211                             ForceNCPaintErase(pwnd, DcRgn, DcRgnObj);
2212                             GreDeleteObject(DcRgn);
2213                         }
2214                     }
2215                 }
2216              }
2217              REGION_Delete(DirtyRgn);
2218          }
2219       }
2220 
2221       /* Expose what was covered before but not covered anymore */
2222       if (VisBefore != NULL)
2223       {
2224          PREGION ExposedRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2225          if (ExposedRgn)
2226          {
2227              RgnType = IntGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
2228              REGION_bOffsetRgn(ExposedRgn,
2229                                OldWindowRect.left - NewWindowRect.left,
2230                                OldWindowRect.top  - NewWindowRect.top);
2231 
2232              if (VisAfter != NULL)
2233                 RgnType = IntGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
2234 
2235              if (RgnType != ERROR && RgnType != NULLREGION)
2236              {
2237                 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
2238              }
2239              REGION_Delete(ExposedRgn);
2240          }
2241       }
2242    }
2243 
2244    if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2245    {
2246       if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2247       {
2248          co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
2249       }
2250       else
2251       {
2252          //ERR("SetWindowPos Set FG Window!\n");
2253          if ( pti->MessageQueue->spwndActive != Window ||
2254               pti->MessageQueue != gpqForeground )
2255          {
2256             //ERR("WPSWP : set active window\n");
2257             if (!(Window->state & WNDS_BEINGACTIVATED)) // Inside SAW?
2258             {
2259                co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
2260             }
2261          }
2262       }
2263    }
2264 
2265    if ( !PosChanged &&
2266          (WinPos.flags & SWP_FRAMECHANGED) &&
2267         !(WinPos.flags & SWP_DEFERERASE) &&    // Prevent sending WM_SYNCPAINT message.
2268          VisAfter )
2269    {
2270        PWND Parent = Window->spwndParent;
2271        if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
2272        {
2273            TRACE("SWP_FRAMECHANGED Parent %p WS_CLIPCHILDREN %p\n",Parent,Window);
2274            UserSyncAndPaintWindows(Parent, RDW_CLIPCHILDREN); // NC should redraw here, see NC HACK fix.
2275        }
2276    }
2277 
2278    // Fix wine msg test_SetFocus, prevents sending WM_WINDOWPOSCHANGED.
2279    if ( VisBefore == NULL &&
2280         VisBeforeJustClient == NULL &&
2281        !(Window->ExStyle & WS_EX_TOPMOST) &&
2282         (WinPos.flags & SWP_AGG_STATUSFLAGS) == (SWP_AGG_NOPOSCHANGE & ~SWP_NOZORDER))
2283    {
2284       TRACE("No drawing, set no Z order and no redraw!\n");
2285       WinPos.flags |= SWP_NOZORDER|SWP_NOREDRAW;
2286    }
2287 
2288    if (VisBefore != NULL)
2289    {
2290       REGION_Delete(VisBefore);
2291       VisBefore = NULL;
2292    }
2293    if (VisBeforeJustClient != NULL)
2294    {
2295       REGION_Delete(VisBeforeJustClient);
2296       VisBeforeJustClient = NULL;
2297    }
2298    if (VisAfter != NULL)
2299    {
2300       REGION_Delete(VisAfter);
2301       VisAfter = NULL;
2302    }
2303    if (CopyRgn != NULL)
2304    {
2305       REGION_Delete(CopyRgn);
2306       CopyRgn = NULL;
2307    }
2308 
2309    if(!(flags & SWP_DEFERERASE))
2310    {
2311        /* erase parent when hiding or resizing child */
2312        if ((flags & SWP_HIDEWINDOW) ||
2313          (!(flags & SWP_SHOWWINDOW) &&
2314           (WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE))
2315        {
2316            PWND Parent = Window->spwndParent;
2317            if (!Parent || UserIsDesktopWindow(Parent)) Parent = Window;
2318            UserSyncAndPaintWindows( Parent, RDW_ERASENOW);
2319        }
2320 
2321        /* Give newly shown windows a chance to redraw */
2322        if(((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2323                 && !(flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW))
2324        {
2325            UserSyncAndPaintWindows( Window, RDW_ERASENOW);
2326        }
2327    }
2328 
2329    /* And last, send the WM_WINDOWPOSCHANGED message */
2330 
2331    TRACE("\tstatus hwnd %p flags = %04x\n", Window ? UserHMGetHandle(Window) : NULL, WinPos.flags & SWP_AGG_STATUSFLAGS);
2332 
2333    if (((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2334             && !((flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW)))
2335    {
2336       /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2337          and always contains final window position.
2338        */
2339       WinPos.x = NewWindowRect.left;
2340       WinPos.y = NewWindowRect.top;
2341       WinPos.cx = NewWindowRect.right - NewWindowRect.left;
2342       WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
2343       TRACE("WM_WINDOWPOSCHANGED hwnd %p Flags %04x\n",WinPos.hwnd,WinPos.flags);
2344       co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
2345    }
2346 
2347    if ( WinPos.flags & SWP_FRAMECHANGED  || WinPos.flags & SWP_STATECHANGED ||
2348       !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
2349    {
2350       PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
2351       if (pWnd)
2352          IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2353    }
2354 
2355    /* Send WM_IME_SYSTEM:IMS_UPDATEIMEUI to the IME windows if necessary */
2356    if ((WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE)) != (SWP_NOMOVE | SWP_NOSIZE))
2357    {
2358       if (IS_IMM_MODE())
2359           IntImeWindowPosChanged();
2360    }
2361 
2362    if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
2363    {
2364       /* Generate mouse move message */
2365       MSG msg;
2366       msg.message = WM_MOUSEMOVE;
2367       msg.wParam = UserGetMouseButtonsState();
2368       msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2369       msg.pt = gpsi->ptCursor;
2370       co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2371    }
2372 
2373    return TRUE;
2374 }
2375 
2376 LRESULT FASTCALL
co_WinPosGetNonClientSize(PWND Window,RECT * WindowRect,RECT * ClientRect)2377 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
2378 {
2379    LRESULT Result;
2380 
2381    ASSERT_REFS_CO(Window);
2382 
2383    *ClientRect = *WindowRect;
2384    Result = co_IntSendMessageNoWait(UserHMGetHandle(Window), WM_NCCALCSIZE, FALSE, (LPARAM)ClientRect);
2385 
2386    FixClientRect(ClientRect, WindowRect);
2387 
2388    return Result;
2389 }
2390 
2391 void FASTCALL
co_WinPosSendSizeMove(PWND Wnd)2392 co_WinPosSendSizeMove(PWND Wnd)
2393 {
2394     RECTL Rect;
2395     LPARAM lParam;
2396     WPARAM wParam = SIZE_RESTORED;
2397 
2398     IntGetClientRect(Wnd, &Rect);
2399     lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
2400 
2401     Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
2402 
2403     if (Wnd->style & WS_MAXIMIZE)
2404     {
2405         wParam = SIZE_MAXIMIZED;
2406     }
2407     else if (Wnd->style & WS_MINIMIZE)
2408     {
2409         wParam = SIZE_MINIMIZED;
2410         lParam = 0;
2411     }
2412 
2413     co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
2414 
2415     if (UserIsDesktopWindow(Wnd->spwndParent))
2416        lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
2417     else
2418        lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
2419 
2420     co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
2421 
2422     IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
2423 }
2424 
2425 UINT FASTCALL
co_WinPosMinMaximize(PWND Wnd,UINT ShowFlag,RECT * NewPos)2426 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
2427 {
2428    POINT Size;
2429    WINDOWPLACEMENT wpl;
2430    LONG old_style;
2431    UINT SwpFlags = 0;
2432 
2433    ASSERT_REFS_CO(Wnd);
2434 
2435    wpl.length = sizeof(wpl);
2436    IntGetWindowPlacement( Wnd, &wpl );
2437 
2438    if (co_HOOK_CallHooks(WH_CBT, HCBT_MINMAX, (WPARAM)UserHMGetHandle(Wnd), ShowFlag))
2439    {
2440       ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
2441       return SWP_NOSIZE | SWP_NOMOVE;
2442    }
2443       if (Wnd->style & WS_MINIMIZE)
2444       {
2445          switch (ShowFlag)
2446          {
2447          case SW_MINIMIZE:
2448          case SW_SHOWMINNOACTIVE:
2449          case SW_SHOWMINIMIZED:
2450          case SW_FORCEMINIMIZE:
2451              return SWP_NOSIZE | SWP_NOMOVE;
2452          }
2453          if (!co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_QUERYOPEN, 0, 0))
2454          {
2455             return(SWP_NOSIZE | SWP_NOMOVE);
2456          }
2457          SwpFlags |= SWP_NOCOPYBITS;
2458       }
2459       switch (ShowFlag)
2460       {
2461          case SW_MINIMIZE:
2462          case SW_SHOWMINNOACTIVE:
2463          case SW_SHOWMINIMIZED:
2464          case SW_FORCEMINIMIZE:
2465             {
2466                //ERR("MinMaximize Minimize\n");
2467                if (Wnd->style & WS_MAXIMIZE)
2468                {
2469                   Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
2470                }
2471                else
2472                {
2473                   Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2474                }
2475 
2476                old_style = IntSetStyle( Wnd, WS_MINIMIZE, WS_MAXIMIZE );
2477 
2478                co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOINTERNALPAINT);
2479 
2480                if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION))
2481                   Wnd->InternalPos.flags &= ~WPF_MININIT;
2482 
2483                WinPosFindIconPos(Wnd, &wpl.ptMinPosition);
2484 
2485                if (!(old_style & WS_MINIMIZE))
2486                {
2487                   SwpFlags |= SWP_STATECHANGED;
2488                   IntShowOwnedPopups(Wnd, FALSE);
2489                }
2490 
2491                RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
2492                              wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
2493                              wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
2494                SwpFlags |= SWP_NOCOPYBITS;
2495                break;
2496             }
2497 
2498          case SW_MAXIMIZE:
2499             {
2500                //ERR("MinMaximize Maximize\n");
2501                IntSetSnapEdge(Wnd, HTNOWHERE); /* Mark as not snapped (for Win+Left,Up,Down) */
2502                if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE))
2503                {
2504                   SwpFlags = SWP_NOSIZE | SWP_NOMOVE;
2505                   break;
2506                }
2507                co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2508 
2509                /*ERR("Maximize: %d,%d %dx%d\n",
2510                       wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
2511                 */
2512                old_style = IntSetStyle( Wnd, WS_MAXIMIZE, WS_MINIMIZE );
2513                /*if (old_style & WS_MINIMIZE)
2514                {
2515                   IntShowOwnedPopups(Wnd, TRUE);
2516                }*/
2517 
2518                if (!(old_style & WS_MAXIMIZE)) SwpFlags |= SWP_STATECHANGED;
2519                RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2520                               //wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2521                               Size.x, Size.y);
2522                break;
2523             }
2524 
2525          case SW_SHOWNOACTIVATE:
2526             Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2527             /* fall through */
2528          case SW_SHOWNORMAL:
2529          case SW_RESTORE:
2530          case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
2531             {
2532                //ERR("MinMaximize Restore\n");
2533                old_style = IntSetStyle( Wnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
2534                if (old_style & WS_MINIMIZE)
2535                {
2536                   IntShowOwnedPopups(Wnd, TRUE);
2537 
2538                   if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED)
2539                   {
2540                      co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2541                      IntSetStyle( Wnd, WS_MAXIMIZE, 0 );
2542                      SwpFlags |= SWP_STATECHANGED;
2543                      RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2544                                     wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2545                      break;
2546                   }
2547                   else
2548                   {
2549                      *NewPos = wpl.rcNormalPosition;
2550                      if (ShowFlag != SW_SHOWNORMAL && ShowFlag != SW_SHOWDEFAULT)
2551                      {
2552                         UINT edge = IntGetWindowSnapEdge(Wnd);
2553                         if (edge)
2554                            co_IntCalculateSnapPosition(Wnd, edge, NewPos);
2555                      }
2556                      NewPos->right -= NewPos->left;
2557                      NewPos->bottom -= NewPos->top;
2558                      break;
2559                   }
2560                }
2561                else
2562                {
2563                   if (!(old_style & WS_MAXIMIZE))
2564                   {
2565                      break;
2566                   }
2567                   SwpFlags |= SWP_STATECHANGED;
2568                   Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2569                   *NewPos = wpl.rcNormalPosition;
2570                   NewPos->right -= NewPos->left;
2571                   NewPos->bottom -= NewPos->top;
2572                   break;
2573                }
2574             }
2575       }
2576    return SwpFlags;
2577 }
2578 
2579 /*
2580    ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits!
2581    Win: xxxShowWindow
2582  */
2583 BOOLEAN FASTCALL
co_WinPosShowWindow(PWND Wnd,INT Cmd)2584 co_WinPosShowWindow(PWND Wnd, INT Cmd)
2585 {
2586    BOOLEAN WasVisible;
2587    UINT Swp = 0, EventMsg = 0;
2588    RECTL NewPos = {0, 0, 0, 0};
2589    BOOLEAN ShowFlag;
2590    LONG style;
2591    PWND Parent;
2592    PTHREADINFO pti;
2593    //HRGN VisibleRgn;
2594    BOOL ShowOwned = FALSE;
2595    BOOL FirstTime = FALSE;
2596    ASSERT_REFS_CO(Wnd);
2597    //KeRosDumpStackFrames(NULL, 20);
2598    pti = PsGetCurrentThreadWin32Thread();
2599    WasVisible = (Wnd->style & WS_VISIBLE) != 0;
2600    style = Wnd->style;
2601 
2602    TRACE("co_WinPosShowWindow START hwnd %p Cmd %d usicmd %u\n",
2603          UserHMGetHandle(Wnd), Cmd, pti->ppi->usi.wShowWindow);
2604 
2605    if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2606    {
2607       if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2608       {
2609          if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
2610          {
2611             if (Wnd->spwndOwner == NULL)
2612             {
2613                if ( Cmd == SW_SHOWNORMAL || Cmd == SW_SHOW)
2614                {
2615                     Cmd = SW_SHOWDEFAULT;
2616                }
2617                FirstTime = TRUE;
2618                TRACE("co_WPSW FT 1\n");
2619             }
2620          }
2621       }
2622    }
2623 
2624    if ( Cmd == SW_SHOWDEFAULT )
2625    {
2626       if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2627       {
2628          Cmd = pti->ppi->usi.wShowWindow;
2629          FirstTime = TRUE;
2630          TRACE("co_WPSW FT 2\n");
2631       }
2632    }
2633 
2634    if (FirstTime)
2635    {
2636       pti->ppi->usi.dwFlags &= ~(STARTF_USEPOSITION|STARTF_USESIZE|STARTF_USESHOWWINDOW);
2637    }
2638 
2639    switch (Cmd)
2640    {
2641       case SW_HIDE:
2642          {
2643             if (!WasVisible)
2644             {
2645                //ERR("co_WinPosShowWindow Exit Bad\n");
2646                return FALSE;
2647             }
2648             Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2649             if (Wnd != pti->MessageQueue->spwndActive)
2650                Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2651             break;
2652          }
2653 
2654       case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2655       case SW_SHOWMINNOACTIVE:
2656          Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2657          /* Fall through. */
2658       case SW_SHOWMINIMIZED:
2659       case SW_MINIMIZE: /* CORE-15669: SW_MINIMIZE also shows */
2660          Swp |= SWP_SHOWWINDOW;
2661          {
2662             Swp |= SWP_NOACTIVATE;
2663             if (!(style & WS_MINIMIZE))
2664             {
2665                IntShowOwnedPopups(Wnd, FALSE );
2666                // Fix wine Win test_SetFocus todo #1 & #2,
2667                if (Cmd == SW_SHOWMINIMIZED)
2668                {
2669                   //ERR("co_WinPosShowWindow Set focus 1\n");
2670                   if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2671                      co_UserSetFocus(Wnd->spwndParent);
2672                   else
2673                      co_UserSetFocus(0);
2674                }
2675 
2676                Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2677 
2678                EventMsg = EVENT_SYSTEM_MINIMIZESTART;
2679             }
2680             else
2681             {
2682                if (WasVisible)
2683                {
2684                   //ERR("co_WinPosShowWindow Exit Good\n");
2685                   return TRUE;
2686                }
2687                Swp |= SWP_NOSIZE | SWP_NOMOVE;
2688             }
2689             break;
2690          }
2691 
2692       case SW_SHOWMAXIMIZED:
2693          {
2694             Swp |= SWP_SHOWWINDOW;
2695             if (!(style & WS_MAXIMIZE))
2696             {
2697                ShowOwned = TRUE;
2698 
2699                Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos);
2700 
2701                EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2702             }
2703             else
2704             {
2705                if (WasVisible)
2706                {
2707                   //ERR("co_WinPosShowWindow Exit Good 1\n");
2708                   return TRUE;
2709                }
2710                Swp |= SWP_NOSIZE | SWP_NOMOVE;
2711             }
2712             break;
2713          }
2714 
2715       case SW_SHOWNA:
2716          Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2717          if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
2718          break;
2719       case SW_SHOW:
2720          if (WasVisible) return(TRUE); // Nothing to do!
2721          Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2722          /* Don't activate the topmost window. */
2723          if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2724          break;
2725 
2726       case SW_SHOWNOACTIVATE:
2727          Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2728          /* Fall through. */
2729       case SW_SHOWNORMAL:
2730       case SW_SHOWDEFAULT:
2731       case SW_RESTORE:
2732          if (!WasVisible) Swp |= SWP_SHOWWINDOW;
2733          if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2734          {
2735             Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2736             if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2737          }
2738          else
2739          {
2740             if (WasVisible)
2741             {
2742                //ERR("co_WinPosShowWindow Exit Good 3\n");
2743                return TRUE;
2744             }
2745             Swp |= SWP_NOSIZE | SWP_NOMOVE;
2746          }
2747          if ( style & WS_CHILD &&
2748              !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2749              !(Swp & SWP_STATECHANGED))
2750             Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2751          break;
2752 
2753       default:
2754          //ERR("co_WinPosShowWindow Exit Good 4\n");
2755          return FALSE;
2756    }
2757 
2758    ShowFlag = (Cmd != SW_HIDE);
2759 
2760    if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
2761    {
2762       co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SHOWWINDOW, ShowFlag, 0);
2763 #if 0 // Fix wine msg test_SetParent:WmSetParentSeq_1:2
2764       if (!(Wnd->state2 & WNDS2_WIN31COMPAT)) // <------------- XP sets this bit!
2765          co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SETVISIBLE, ShowFlag, 0);
2766 #endif
2767       if (!VerifyWnd(Wnd)) return WasVisible;
2768    }
2769 
2770    /* We can't activate a child window */
2771    if ((Wnd->style & WS_CHILD) &&
2772        !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2773        Cmd != SW_SHOWNA)
2774    {
2775       //ERR("SWP Child No active and ZOrder\n");
2776       Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2777    }
2778 
2779 #if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works.
2780       // Breaks startup and shutdown active window...
2781    if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
2782         Wnd->pcls->style & CS_SAVEBITS &&
2783         ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
2784    {
2785       ERR("WinPosShowWindow Set active\n");
2786       //UserSetActiveWindow(Wnd);
2787       co_IntSetForegroundWindow(Wnd); // HACK
2788       Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2789    }
2790 #endif
2791 
2792    if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
2793    {
2794        TRACE("Child is Vis %s or State changed %s. ShowFlag %s Swp %04x\n",
2795              (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
2796              (ShowFlag ? "TRUE" : "FALSE"),LOWORD(Swp));
2797    co_WinPosSetWindowPos( Wnd,
2798                           0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
2799                           NewPos.left,
2800                           NewPos.top,
2801                           NewPos.right, // NewPos.right - NewPos.left, when minimized and restore, the window becomes smaller.
2802                           NewPos.bottom,// NewPos.bottom - NewPos.top,
2803                           LOWORD(Swp));
2804    }
2805    else
2806    {
2807       TRACE("Parent Vis?\n");
2808       /* if parent is not visible simply toggle WS_VISIBLE and return */
2809       if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
2810       else IntSetStyle( Wnd, 0, WS_VISIBLE );
2811    }
2812 
2813    if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2814 
2815    if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
2816 
2817    if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
2818    {
2819       if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue()  )
2820       {
2821           if (UserIsDesktopWindow(Wnd->spwndParent))
2822           {
2823               if (!ActivateOtherWindowMin(Wnd))
2824               {
2825                 co_WinPosActivateOtherWindow(Wnd);
2826               }
2827           }
2828           else
2829           {
2830               co_WinPosActivateOtherWindow(Wnd);
2831           }
2832       }
2833 
2834       /* Revert focus to parent */
2835       if (Wnd == pti->MessageQueue->spwndFocus)
2836       {
2837          Parent = Wnd->spwndParent;
2838          if (UserIsDesktopWindow(Wnd->spwndParent))
2839              Parent = 0;
2840          co_UserSetFocus(Parent);
2841       }
2842       // Hide, just return.
2843       if (Cmd == SW_HIDE) return WasVisible;
2844    }
2845 
2846    /* FIXME: Check for window destruction. */
2847 
2848    if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
2849        !(Wnd->state2 & WNDS2_INDESTROY))
2850    {
2851         co_WinPosSendSizeMove(Wnd);
2852    }
2853 
2854    /* if previous state was minimized Windows sets focus to the window */
2855    if (style & WS_MINIMIZE)
2856    {
2857       co_UserSetFocus(Wnd);
2858       // Fix wine Win test_SetFocus todo #3,
2859       if (!(style & WS_CHILD)) co_IntSendMessage(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
2860    }
2861    //ERR("co_WinPosShowWindow EXIT\n");
2862    return WasVisible;
2863 }
2864 
2865 static PWND
co_WinPosSearchChildren(IN PWND ScopeWin,IN POINT * Point,IN OUT USHORT * HitTest,IN BOOL Ignore)2866 co_WinPosSearchChildren(
2867    IN PWND ScopeWin,
2868    IN POINT *Point,
2869    IN OUT USHORT *HitTest,
2870    IN BOOL Ignore
2871    )
2872 {
2873     HWND *List, *phWnd;
2874     PWND pwndChild = NULL;
2875 
2876     /* not visible */
2877     if (!(ScopeWin->style & WS_VISIBLE))
2878     {
2879         return NULL;
2880     }
2881 
2882     /* not in window or in window region */
2883     if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2884     {
2885         return NULL;
2886     }
2887 
2888     /* transparent */
2889     if ((ScopeWin->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
2890     {
2891         return NULL;
2892     }
2893 
2894     if (!Ignore && (ScopeWin->style & WS_DISABLED))
2895     {   /* disabled child */
2896         if ((ScopeWin->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return NULL;
2897         /* process the hit error */
2898         *HitTest = HTERROR;
2899         return ScopeWin;
2900     }
2901 
2902     /* not minimized and check if point is inside the window */
2903     if (!(ScopeWin->style & WS_MINIMIZE) &&
2904          RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2905     {
2906         UserReferenceObject(ScopeWin);
2907 
2908         List = IntWinListChildren(ScopeWin);
2909         if (List)
2910         {
2911             for (phWnd = List; *phWnd; ++phWnd)
2912             {
2913                 if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
2914                 {
2915                     continue;
2916                 }
2917 
2918                 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
2919 
2920                 if (pwndChild != NULL)
2921                 {
2922                     /* We found a window. Don't send any more WM_NCHITTEST messages */
2923                     ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2924                     UserDereferenceObject(ScopeWin);
2925                     return pwndChild;
2926                 }
2927             }
2928             ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2929         }
2930         UserDereferenceObject(ScopeWin);
2931     }
2932 
2933     if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
2934     {
2935        *HitTest = (USHORT)co_IntSendMessage(UserHMGetHandle(ScopeWin), WM_NCHITTEST, 0, MAKELONG(Point->x, Point->y));
2936 
2937        if ((*HitTest) == (USHORT)HTTRANSPARENT)
2938        {
2939            return NULL;
2940        }
2941     }
2942     else
2943     {
2944        if (*HitTest == HTNOWHERE && pwndChild == NULL) *HitTest = HTCLIENT;
2945     }
2946 
2947     return ScopeWin;
2948 }
2949 
2950 PWND APIENTRY
co_WinPosWindowFromPoint(IN PWND ScopeWin,IN POINT * WinPoint,IN OUT USHORT * HitTest,IN BOOL Ignore)2951 co_WinPosWindowFromPoint(
2952    IN PWND ScopeWin,
2953    IN POINT *WinPoint,
2954    IN OUT USHORT* HitTest,
2955    IN BOOL Ignore)
2956 {
2957    PWND Window;
2958    POINT Point = *WinPoint;
2959    USER_REFERENCE_ENTRY Ref;
2960 
2961    if( ScopeWin == NULL )
2962    {
2963        ScopeWin = UserGetDesktopWindow();
2964        if(ScopeWin == NULL)
2965            return NULL;
2966    }
2967 
2968    *HitTest = HTNOWHERE;
2969 
2970    ASSERT_REFS_CO(ScopeWin);
2971    UserRefObjectCo(ScopeWin, &Ref);
2972 
2973    Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
2974 
2975    UserDerefObjectCo(ScopeWin);
2976    if (Window)
2977        ASSERT_REFS_CO(Window);
2978    ASSERT_REFS_CO(ScopeWin);
2979 
2980    return Window;
2981 }
2982 
2983 /* Win: _RealChildWindowFromPoint */
2984 PWND FASTCALL
IntRealChildWindowFromPoint(PWND Parent,LONG x,LONG y)2985 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2986 {
2987    POINTL Pt;
2988    HWND *List, *phWnd;
2989    PWND pwndHit = NULL;
2990 
2991    Pt.x = x;
2992    Pt.y = y;
2993 
2994    if (!UserIsDesktopWindow(Parent))
2995    {
2996       Pt.x += Parent->rcClient.left;
2997       Pt.y += Parent->rcClient.top;
2998    }
2999 
3000    if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
3001 
3002    if ((List = IntWinListChildren(Parent)))
3003    {
3004       for (phWnd = List; *phWnd; phWnd++)
3005       {
3006          PWND Child;
3007          if ((Child = ValidateHwndNoErr(*phWnd)))
3008          {
3009             if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
3010             {
3011                if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
3012                    (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
3013                {
3014                   ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3015                   return Child;
3016                }
3017                pwndHit = Child;
3018             }
3019          }
3020       }
3021       ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3022    }
3023    return pwndHit ? pwndHit : Parent;
3024 }
3025 
3026 /* Win: _ChildWindowFromPointEx */
3027 PWND APIENTRY
IntChildWindowFromPointEx(PWND Parent,LONG x,LONG y,UINT uiFlags)3028 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
3029 {
3030    POINTL Pt;
3031    HWND *List, *phWnd;
3032    PWND pwndHit = NULL;
3033 
3034    Pt.x = x;
3035    Pt.y = y;
3036 
3037    if (!UserIsDesktopWindow(Parent))
3038    {
3039       if (Parent->ExStyle & WS_EX_LAYOUTRTL)
3040          Pt.x = Parent->rcClient.right - Pt.x;
3041       else
3042          Pt.x += Parent->rcClient.left;
3043       Pt.y += Parent->rcClient.top;
3044    }
3045 
3046    if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
3047 
3048    if ((List = IntWinListChildren(Parent)))
3049    {
3050       for (phWnd = List; *phWnd; phWnd++)
3051       {
3052          PWND Child;
3053          if ((Child = ValidateHwndNoErr(*phWnd)))
3054          {
3055             if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
3056             {
3057                if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
3058                if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
3059             }
3060 
3061             if (uiFlags & CWP_SKIPTRANSPARENT)
3062             {
3063                if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
3064             }
3065 
3066             if (IntPtInWindow(Child, Pt.x, Pt.y))
3067             {
3068                pwndHit = Child;
3069                break;
3070             }
3071          }
3072       }
3073       ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3074    }
3075    return pwndHit ? pwndHit : Parent;
3076 }
3077 
3078 /* Win: _DeferWindowPos(PSMWP, PWND, PWND, ...) */
3079 HDWP
3080 FASTCALL
IntDeferWindowPos(HDWP hdwp,HWND hwnd,HWND hwndAfter,INT x,INT y,INT cx,INT cy,UINT flags)3081 IntDeferWindowPos( HDWP hdwp,
3082                    HWND hwnd,
3083                    HWND hwndAfter,
3084                    INT x,
3085                    INT y,
3086                    INT cx,
3087                    INT cy,
3088                    UINT flags )
3089 {
3090     PSMWP pDWP;
3091     int i;
3092     HDWP retvalue = hdwp;
3093 
3094     TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3095           hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
3096 
3097     if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
3098                   SWP_NOZORDER | SWP_NOREDRAW |
3099                   SWP_NOACTIVATE | SWP_NOCOPYBITS |
3100                   SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
3101                   SWP_HIDEWINDOW | SWP_FRAMECHANGED))
3102     {
3103        EngSetLastError(ERROR_INVALID_PARAMETER);
3104        return NULL;
3105     }
3106 
3107     if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
3108     {
3109        EngSetLastError(ERROR_INVALID_DWP_HANDLE);
3110        return NULL;
3111     }
3112 
3113     for (i = 0; i < pDWP->ccvr; i++)
3114     {
3115         if (pDWP->acvr[i].pos.hwnd == hwnd)
3116         {
3117               /* Merge with the other changes */
3118             if (!(flags & SWP_NOZORDER))
3119             {
3120                 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
3121             }
3122             if (!(flags & SWP_NOMOVE))
3123             {
3124                 pDWP->acvr[i].pos.x = x;
3125                 pDWP->acvr[i].pos.y = y;
3126             }
3127             if (!(flags & SWP_NOSIZE))
3128             {
3129                 pDWP->acvr[i].pos.cx = cx;
3130                 pDWP->acvr[i].pos.cy = cy;
3131             }
3132             pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
3133                                                SWP_NOZORDER | SWP_NOREDRAW |
3134                                                SWP_NOACTIVATE | SWP_NOCOPYBITS|
3135                                                SWP_NOOWNERZORDER);
3136             pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
3137                                               SWP_FRAMECHANGED);
3138             goto END;
3139         }
3140     }
3141     if (pDWP->ccvr >= pDWP->ccvrAlloc)
3142     {
3143         PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
3144         if (!newpos)
3145         {
3146             retvalue = NULL;
3147             goto END;
3148         }
3149         RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
3150         RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
3151         ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
3152         pDWP->ccvrAlloc *= 2;
3153         pDWP->acvr = newpos;
3154     }
3155     pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
3156     pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
3157     pDWP->acvr[pDWP->ccvr].pos.x = x;
3158     pDWP->acvr[pDWP->ccvr].pos.y = y;
3159     pDWP->acvr[pDWP->ccvr].pos.cx = cx;
3160     pDWP->acvr[pDWP->ccvr].pos.cy = cy;
3161     pDWP->acvr[pDWP->ccvr].pos.flags = flags;
3162     pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
3163     pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
3164     pDWP->ccvr++;
3165 END:
3166     return retvalue;
3167 }
3168 
3169 /* Win: xxxEndDeferWindowPosEx */
IntEndDeferWindowPosEx(HDWP hdwp,BOOL bAsync)3170 BOOL FASTCALL IntEndDeferWindowPosEx(HDWP hdwp, BOOL bAsync)
3171 {
3172     PSMWP pDWP;
3173     PCVR winpos;
3174     BOOL res = TRUE;
3175     int i;
3176 
3177     TRACE("%p\n", hdwp);
3178 
3179     if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
3180     {
3181        EngSetLastError(ERROR_INVALID_DWP_HANDLE);
3182        return FALSE;
3183     }
3184 
3185     for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
3186     {
3187         PWND pwnd;
3188         USER_REFERENCE_ENTRY Ref;
3189 
3190         TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3191                winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
3192                winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
3193 
3194         pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
3195         if (!pwnd)
3196            continue;
3197 
3198         UserRefObjectCo(pwnd, &Ref);
3199 
3200         if (bAsync)
3201         {
3202            LRESULT lRes;
3203            PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
3204            if ( ppos )
3205            {
3206               *ppos = winpos->pos;
3207               /* Yes it's a pointer inside Win32k! */
3208               lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
3209               /* We handle this the same way as Event Hooks and Hooks. */
3210               if ( !lRes )
3211               {
3212                  ExFreePoolWithTag(ppos, USERTAG_SWP);
3213               }
3214            }
3215         }
3216         else
3217            res = co_WinPosSetWindowPos( pwnd,
3218                                         winpos->pos.hwndInsertAfter,
3219                                         winpos->pos.x,
3220                                         winpos->pos.y,
3221                                         winpos->pos.cx,
3222                                         winpos->pos.cy,
3223                                         winpos->pos.flags);
3224 
3225         // Hack to pass tests.... Must have some work to do so clear the error.
3226         if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
3227            EngSetLastError(ERROR_SUCCESS);
3228 
3229         UserDerefObjectCo(pwnd);
3230     }
3231 
3232     ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
3233     UserDereferenceObject(pDWP);
3234     UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
3235     return res;
3236 }
3237 
3238 /*
3239  * @implemented
3240  */
3241 HWND APIENTRY
NtUserChildWindowFromPointEx(HWND hwndParent,LONG x,LONG y,UINT uiFlags)3242 NtUserChildWindowFromPointEx(HWND hwndParent,
3243                              LONG x,
3244                              LONG y,
3245                              UINT uiFlags)
3246 {
3247    PWND pwndParent;
3248    TRACE("Enter NtUserChildWindowFromPointEx\n");
3249    UserEnterExclusive();
3250    if ((pwndParent = UserGetWindowObject(hwndParent)))
3251    {
3252       pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
3253    }
3254    UserLeave();
3255    TRACE("Leave NtUserChildWindowFromPointEx\n");
3256    return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3257 }
3258 
3259 /*
3260  * @implemented
3261  */
3262 BOOL APIENTRY
NtUserEndDeferWindowPosEx(HDWP WinPosInfo,BOOL bAsync)3263 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
3264                           BOOL bAsync)
3265 {
3266    BOOL Ret;
3267    TRACE("Enter NtUserEndDeferWindowPosEx\n");
3268    UserEnterExclusive();
3269    Ret = IntEndDeferWindowPosEx(WinPosInfo, bAsync);
3270    TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
3271    UserLeave();
3272    return Ret;
3273 }
3274 
3275 /*
3276  * @implemented
3277  */
3278 HDWP APIENTRY
NtUserDeferWindowPos(HDWP WinPosInfo,HWND Wnd,HWND WndInsertAfter,int x,int y,int cx,int cy,UINT Flags)3279 NtUserDeferWindowPos(HDWP WinPosInfo,
3280                      HWND Wnd,
3281                      HWND WndInsertAfter,
3282                      int x,
3283                      int y,
3284                      int cx,
3285                      int cy,
3286                      UINT Flags)
3287 {
3288    PWND pWnd, pWndIA;
3289    HDWP Ret = NULL;
3290    UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
3291                 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
3292                 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
3293 
3294    TRACE("Enter NtUserDeferWindowPos\n");
3295    UserEnterExclusive();
3296 
3297    if ( Flags & Tmp )
3298    {
3299       EngSetLastError(ERROR_INVALID_FLAGS);
3300       goto Exit;
3301    }
3302 
3303    pWnd = UserGetWindowObject(Wnd);
3304    if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3305    {
3306       goto Exit;
3307    }
3308 
3309    if ( WndInsertAfter &&
3310         WndInsertAfter != HWND_BOTTOM &&
3311         WndInsertAfter != HWND_TOPMOST &&
3312         WndInsertAfter != HWND_NOTOPMOST )
3313    {
3314       pWndIA = UserGetWindowObject(WndInsertAfter);
3315       if (!pWndIA || UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3316       {
3317          goto Exit;
3318       }
3319    }
3320 
3321    Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
3322 
3323 Exit:
3324    TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
3325    UserLeave();
3326    return Ret;
3327 }
3328 
3329 /*
3330  * @implemented
3331  */
3332 DWORD APIENTRY
NtUserGetInternalWindowPos(HWND hWnd,LPRECT rectWnd,LPPOINT ptIcon)3333 NtUserGetInternalWindowPos( HWND hWnd,
3334                             LPRECT rectWnd,
3335                             LPPOINT ptIcon)
3336 {
3337    PWND Window;
3338    DWORD Ret = 0;
3339    BOOL Hit = FALSE;
3340    WINDOWPLACEMENT wndpl;
3341 
3342    UserEnterShared();
3343 
3344    if (!(Window = UserGetWindowObject(hWnd)))
3345    {
3346       Hit = FALSE;
3347       goto Exit;
3348    }
3349 
3350    _SEH2_TRY
3351    {
3352        if(rectWnd)
3353        {
3354           ProbeForWrite(rectWnd,
3355                         sizeof(RECT),
3356                         1);
3357        }
3358        if(ptIcon)
3359        {
3360           ProbeForWrite(ptIcon,
3361                         sizeof(POINT),
3362                         1);
3363        }
3364 
3365    }
3366    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3367    {
3368        SetLastNtError(_SEH2_GetExceptionCode());
3369        Hit = TRUE;
3370    }
3371    _SEH2_END;
3372 
3373    wndpl.length = sizeof(WINDOWPLACEMENT);
3374 
3375    if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3376    {
3377       _SEH2_TRY
3378       {
3379           if (rectWnd)
3380           {
3381              RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3382           }
3383           if (ptIcon)
3384           {
3385              RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3386           }
3387 
3388       }
3389       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3390       {
3391           SetLastNtError(_SEH2_GetExceptionCode());
3392           Hit = TRUE;
3393       }
3394       _SEH2_END;
3395 
3396       if (!Hit) Ret = wndpl.showCmd;
3397    }
3398 Exit:
3399    UserLeave();
3400    return Ret;
3401 }
3402 
3403 /*
3404  * @implemented
3405  */
3406 BOOL APIENTRY
NtUserGetWindowPlacement(HWND hWnd,WINDOWPLACEMENT * lpwndpl)3407 NtUserGetWindowPlacement(HWND hWnd,
3408                          WINDOWPLACEMENT *lpwndpl)
3409 {
3410    PWND Wnd;
3411    WINDOWPLACEMENT Safepl;
3412    NTSTATUS Status;
3413    BOOL Ret = FALSE;
3414 
3415    TRACE("Enter NtUserGetWindowPlacement\n");
3416    UserEnterShared();
3417 
3418    if (!(Wnd = UserGetWindowObject(hWnd)))
3419       goto Exit; // Return FALSE
3420 
3421    Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3422    if (!NT_SUCCESS(Status))
3423    {
3424       SetLastNtError(Status);
3425       goto Exit; // Return FALSE
3426    }
3427 
3428    // This function doesn't check the length. Just overwrite it
3429    Safepl.length = sizeof(WINDOWPLACEMENT);
3430 
3431    IntGetWindowPlacement(Wnd, &Safepl);
3432 
3433    Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
3434    if (!NT_SUCCESS(Status))
3435    {
3436       SetLastNtError(Status);
3437       goto Exit; // Return FALSE
3438    }
3439 
3440    Ret = TRUE;
3441 
3442 Exit:
3443    TRACE("Leave NtUserGetWindowPlacement, ret=%i\n", Ret);
3444    UserLeave();
3445    return Ret;
3446 }
3447 
3448 DWORD
3449 APIENTRY
NtUserMinMaximize(HWND hWnd,UINT cmd,BOOL Hide)3450 NtUserMinMaximize(
3451     HWND hWnd,
3452     UINT cmd, // Wine SW_ commands
3453     BOOL Hide)
3454 {
3455   PWND pWnd;
3456 
3457   TRACE("Enter NtUserMinMaximize\n");
3458   UserEnterExclusive();
3459 
3460   pWnd = UserGetWindowObject(hWnd);
3461   if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3462   {
3463      goto Exit;
3464   }
3465 
3466   if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
3467   {
3468      EngSetLastError(ERROR_INVALID_PARAMETER);
3469      goto Exit;
3470   }
3471 
3472   cmd |= Hide ? SW_HIDE : 0;
3473 
3474   co_WinPosShowWindow(pWnd, cmd);
3475 
3476 Exit:
3477   TRACE("Leave NtUserMinMaximize\n");
3478   UserLeave();
3479   return 0; // Always NULL?
3480 }
3481 
3482 /*
3483  * @implemented
3484  */
3485 BOOL APIENTRY
NtUserMoveWindow(HWND hWnd,int X,int Y,int nWidth,int nHeight,BOOL bRepaint)3486 NtUserMoveWindow(
3487    HWND hWnd,
3488    int X,
3489    int Y,
3490    int nWidth,
3491    int nHeight,
3492    BOOL bRepaint)
3493 {
3494    return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
3495                              (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
3496                               SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
3497 }
3498 
3499 /*
3500  * @implemented
3501  */
3502 HWND APIENTRY
NtUserRealChildWindowFromPoint(HWND Parent,LONG x,LONG y)3503 NtUserRealChildWindowFromPoint(HWND Parent,
3504                                LONG x,
3505                                LONG y)
3506 {
3507    PWND pwndParent;
3508    TRACE("Enter NtUserRealChildWindowFromPoint\n");
3509    UserEnterShared();
3510    if ((pwndParent = UserGetWindowObject(Parent)))
3511    {
3512       pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y);
3513    }
3514    UserLeave();
3515    TRACE("Leave NtUserRealChildWindowFromPoint\n");
3516    return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3517 }
3518 
3519 /*
3520  * @implemented
3521  */
3522 BOOL APIENTRY
NtUserSetWindowPos(HWND hWnd,HWND hWndInsertAfter,int X,int Y,int cx,int cy,UINT uFlags)3523 NtUserSetWindowPos(
3524    HWND hWnd,
3525    HWND hWndInsertAfter,
3526    int X,
3527    int Y,
3528    int cx,
3529    int cy,
3530    UINT uFlags)
3531 {
3532    PWND Window, pWndIA;
3533    BOOL ret = FALSE;
3534    USER_REFERENCE_ENTRY Ref;
3535 
3536    TRACE("Enter NtUserSetWindowPos\n");
3537    UserEnterExclusive();
3538 
3539    if (!(Window = UserGetWindowObject(hWnd)) ||
3540         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3541    {
3542       ERR("NtUserSetWindowPos bad window handle!\n");
3543       goto Exit; // Return FALSE
3544    }
3545 
3546    if ( hWndInsertAfter != HWND_TOP &&
3547         hWndInsertAfter != HWND_BOTTOM &&
3548         hWndInsertAfter != HWND_TOPMOST &&
3549         hWndInsertAfter != HWND_NOTOPMOST )
3550    {
3551       if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) ||
3552             UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3553       {
3554          ERR("NtUserSetWindowPos bad insert window handle!\n");
3555          goto Exit; // Return FALSE
3556       }
3557    }
3558 
3559    /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3560    if (!(uFlags & SWP_NOMOVE))
3561    {
3562       if (X < -32768) X = -32768;
3563       else if (X > 32767) X = 32767;
3564       if (Y < -32768) Y = -32768;
3565       else if (Y > 32767) Y = 32767;
3566    }
3567    if (!(uFlags & SWP_NOSIZE))
3568    {
3569       if (cx < 0) cx = 0;
3570       else if (cx > 32767) cx = 32767;
3571       if (cy < 0) cy = 0;
3572       else if (cy > 32767) cy = 32767;
3573    }
3574 
3575    UserRefObjectCo(Window, &Ref);
3576    ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
3577    UserDerefObjectCo(Window);
3578 
3579 Exit:
3580    TRACE("Leave NtUserSetWindowPos, ret=%i\n", ret);
3581    UserLeave();
3582    return ret;
3583 }
3584 
3585 /*
3586  * @implemented
3587  */
3588 INT APIENTRY
NtUserSetWindowRgn(HWND hWnd,HRGN hRgn,BOOL bRedraw)3589 NtUserSetWindowRgn(
3590    HWND hWnd,
3591    HRGN hRgn,
3592    BOOL bRedraw)
3593 {
3594    HRGN hrgnCopy = NULL;
3595    PWND Window;
3596    INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
3597    INT Ret = 0;
3598 
3599    TRACE("Enter NtUserSetWindowRgn\n");
3600    UserEnterExclusive();
3601 
3602    if (!(Window = UserGetWindowObject(hWnd)) ||
3603         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3604    {
3605       goto Exit; // Return 0
3606    }
3607 
3608    if (hRgn) // The region will be deleted in user32.
3609    {
3610       if (GreIsHandleValid(hRgn))
3611       {
3612          hrgnCopy = NtGdiCreateRectRgn(0, 0, 0, 0);
3613       /* The coordinates of a window's window region are relative to the
3614          upper-left corner of the window, not the client area of the window. */
3615          NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY);
3616       }
3617       else
3618          goto Exit; // Return 0
3619    }
3620 
3621    //// HACK 1 : Work around the lack of supporting DeferWindowPos.
3622    if (hrgnCopy)
3623    {
3624        Window->hrgnNewFrame = hrgnCopy; // Should be PSMWP->acvr->hrgnClip
3625    }
3626    else
3627    {
3628        Window->hrgnNewFrame = HRGN_WINDOW;
3629    }
3630    //// HACK 2
3631    Ret = (INT)co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags | SWP_NOREDRAW));
3632 
3633 Exit:
3634    TRACE("Leave NtUserSetWindowRgn, ret=%i\n", Ret);
3635    UserLeave();
3636    return Ret;
3637 }
3638 
3639 /*
3640  * @implemented
3641  */
3642 DWORD APIENTRY
NtUserSetInternalWindowPos(HWND hwnd,UINT showCmd,LPRECT lprect,LPPOINT lppt)3643 NtUserSetInternalWindowPos(
3644    HWND    hwnd,
3645    UINT    showCmd,
3646    LPRECT  lprect,
3647    LPPOINT lppt)
3648 {
3649    WINDOWPLACEMENT wndpl;
3650    UINT flags;
3651    PWND Wnd;
3652    RECT rect;
3653    POINT pt = {0};
3654    BOOL Ret = FALSE;
3655    USER_REFERENCE_ENTRY Ref;
3656 
3657    TRACE("Enter NtUserSetWindowPlacement\n");
3658    UserEnterExclusive();
3659 
3660    if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME:
3661         UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd))
3662    {
3663       goto Exit; // Return FALSE
3664    }
3665 
3666    _SEH2_TRY
3667    {
3668       if (lppt)
3669       {
3670          ProbeForRead(lppt, sizeof(POINT), 1);
3671          RtlCopyMemory(&pt, lppt, sizeof(POINT));
3672       }
3673       if (lprect)
3674       {
3675          ProbeForRead(lprect, sizeof(RECT), 1);
3676          RtlCopyMemory(&rect, lprect, sizeof(RECT));
3677       }
3678    }
3679    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3680    {
3681       SetLastNtError(_SEH2_GetExceptionCode());
3682       _SEH2_YIELD(goto Exit); // Return FALSE
3683    }
3684    _SEH2_END
3685 
3686    wndpl.length  = sizeof(wndpl);
3687    wndpl.showCmd = showCmd;
3688    wndpl.flags = flags = 0;
3689 
3690    if ( lppt )
3691    {
3692       flags |= PLACE_MIN;
3693       wndpl.flags |= WPF_SETMINPOSITION;
3694       wndpl.ptMinPosition = pt;
3695    }
3696    if ( lprect )
3697    {
3698       flags |= PLACE_RECT;
3699       wndpl.rcNormalPosition = rect;
3700    }
3701 
3702    UserRefObjectCo(Wnd, &Ref);
3703    IntSetWindowPlacement(Wnd, &wndpl, flags);
3704    UserDerefObjectCo(Wnd);
3705    Ret = TRUE;
3706 
3707 Exit:
3708    TRACE("Leave NtUserSetWindowPlacement, ret=%i\n", Ret);
3709    UserLeave();
3710    return Ret;
3711 }
3712 
3713 /*
3714  * @implemented
3715  */
3716 BOOL APIENTRY
NtUserSetWindowPlacement(HWND hWnd,WINDOWPLACEMENT * lpwndpl)3717 NtUserSetWindowPlacement(HWND hWnd,
3718                          WINDOWPLACEMENT *lpwndpl)
3719 {
3720    PWND Wnd;
3721    WINDOWPLACEMENT Safepl;
3722    UINT Flags;
3723    BOOL Ret = FALSE;
3724    USER_REFERENCE_ENTRY Ref;
3725 
3726    TRACE("Enter NtUserSetWindowPlacement\n");
3727    UserEnterExclusive();
3728 
3729     _SEH2_TRY
3730     {
3731         ProbeForRead(lpwndpl, sizeof(*lpwndpl), 1);
3732         Safepl = *lpwndpl;
3733     }
3734     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3735     {
3736         SetLastNtError(_SEH2_GetExceptionCode());
3737         _SEH2_YIELD(goto Exit); // Return FALSE
3738     }
3739     _SEH2_END
3740 
3741     /* Backwards-compatibility: Win 3.x doesn't check the length */
3742     if (LOWORD(gptiCurrent->dwExpWinVer) < WINVER_WINNT4)
3743         Safepl.length = sizeof(Safepl);
3744 
3745     if (Safepl.length != sizeof(Safepl))
3746     {
3747         EngSetLastError(ERROR_INVALID_PARAMETER);
3748         goto Exit;
3749     }
3750 
3751     Flags = PLACE_MAX | PLACE_RECT;
3752     if (Safepl.flags & WPF_SETMINPOSITION)
3753         Flags |= PLACE_MIN;
3754 
3755     Wnd = UserGetWindowObject(hWnd);
3756     if (!Wnd)
3757         goto Exit; // Return FALSE
3758 
3759     UserRefObjectCo(Wnd, &Ref);
3760     if (!UserIsDesktopWindow(Wnd) && !UserIsMessageWindow(Wnd))
3761         Ret = IntSetWindowPlacement(Wnd, &Safepl, Flags);
3762     UserDerefObjectCo(Wnd);
3763 
3764 Exit:
3765    TRACE("Leave NtUserSetWindowPlacement, ret=%i\n", Ret);
3766    UserLeave();
3767    return Ret;
3768 }
3769 
3770 /*
3771  * @implemented
3772  */
3773 BOOL APIENTRY
NtUserShowWindowAsync(HWND hWnd,LONG nCmdShow)3774 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
3775 {
3776    PWND Window;
3777    LRESULT Result;
3778    BOOL ret = FALSE;
3779    USER_REFERENCE_ENTRY Ref;
3780 
3781    TRACE("Enter NtUserShowWindowAsync\n");
3782    UserEnterExclusive();
3783 
3784    if (!(Window = UserGetWindowObject(hWnd)) ||
3785         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3786    {
3787       goto Exit; // Return FALSE
3788    }
3789 
3790    if ( nCmdShow > SW_MAX )
3791    {
3792       EngSetLastError(ERROR_INVALID_PARAMETER);
3793       goto Exit; // Return FALSE
3794    }
3795 
3796    UserRefObjectCo(Window, &Ref);
3797    Result = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 );
3798    UserDerefObjectCo(Window);
3799    if (Result != -1 && Result != 0) ret = TRUE;
3800 
3801 Exit:
3802    TRACE("Leave NtUserShowWindowAsync, ret=%i\n", ret);
3803    UserLeave();
3804    return ret;
3805 }
3806 
3807 /*
3808  * @implemented
3809  */
3810 BOOL APIENTRY
NtUserShowWindow(HWND hWnd,LONG nCmdShow)3811 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
3812 {
3813    PWND Window;
3814    BOOL ret = FALSE;
3815    USER_REFERENCE_ENTRY Ref;
3816 
3817    TRACE("Enter NtUserShowWindow hWnd %p SW_ %d\n",hWnd, nCmdShow);
3818    UserEnterExclusive();
3819 
3820    if (!(Window = UserGetWindowObject(hWnd)) ||
3821         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3822    {
3823       goto Exit; // Return FALSE
3824    }
3825 
3826    if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
3827    {
3828       EngSetLastError(ERROR_INVALID_PARAMETER);
3829       goto Exit; // Return FALSE
3830    }
3831 
3832    UserRefObjectCo(Window, &Ref);
3833    ret = co_WinPosShowWindow(Window, nCmdShow);
3834    UserDerefObjectCo(Window);
3835 
3836 Exit:
3837    TRACE("Leave NtUserShowWindow, ret=%i\n", ret);
3838    UserLeave();
3839    return ret;
3840 }
3841 
3842 
3843 /*
3844  *    @implemented
3845  */
3846 HWND APIENTRY
NtUserWindowFromPoint(LONG X,LONG Y)3847 NtUserWindowFromPoint(LONG X, LONG Y)
3848 {
3849    POINT pt;
3850    HWND Ret = NULL;
3851    PWND DesktopWindow, Window;
3852    USHORT hittest;
3853    USER_REFERENCE_ENTRY Ref;
3854 
3855    TRACE("Enter NtUserWindowFromPoint\n");
3856    UserEnterExclusive();
3857 
3858    if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
3859    {
3860       //PTHREADINFO pti;
3861 
3862       pt.x = X;
3863       pt.y = Y;
3864 
3865       // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window.
3866       // It is possible this referencing is useless, though it should not hurt...
3867       UserRefObjectCo(DesktopWindow, &Ref);
3868 
3869       //pti = PsGetCurrentThreadWin32Thread();
3870       Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest, FALSE);
3871       if (Window)
3872       {
3873          Ret = UserHMGetHandle(Window);
3874       }
3875 
3876       UserDerefObjectCo(DesktopWindow);
3877    }
3878 
3879    TRACE("Leave NtUserWindowFromPoint, ret=%p\n", Ret);
3880    UserLeave();
3881    return Ret;
3882 }
3883 
3884 /* Windows 10 (1903?)
3885 BOOL APIENTRY
3886 NtUserIsWindowArranged(HWND hWnd)
3887 {
3888     PWND pwnd = UserGetWindowObject(hWnd);
3889     return pwnd && IntIsWindowSnapped(pwnd);
3890 }
3891 */
3892 
3893 UINT FASTCALL
IntGetWindowSnapEdge(PWND Wnd)3894 IntGetWindowSnapEdge(PWND Wnd)
3895 {
3896     if (Wnd->ExStyle2 & WS_EX2_VERTICALLYMAXIMIZEDLEFT) return HTLEFT;
3897     if (Wnd->ExStyle2 & WS_EX2_VERTICALLYMAXIMIZEDRIGHT) return HTRIGHT;
3898     return HTNOWHERE;
3899 }
3900 
3901 VOID FASTCALL
co_IntCalculateSnapPosition(PWND Wnd,UINT Edge,OUT RECT * Pos)3902 co_IntCalculateSnapPosition(PWND Wnd, UINT Edge, OUT RECT *Pos)
3903 {
3904     POINT maxs, mint, maxt;
3905     UINT width, height;
3906     UserSystemParametersInfo(SPI_GETWORKAREA, 0, Pos, 0); /* FIXME: MultiMon of PWND */
3907 
3908     co_WinPosGetMinMaxInfo(Wnd, &maxs, NULL, &mint, &maxt);
3909     width = Pos->right - Pos->left;
3910     width = min(min(max(width / 2, mint.x), maxt.x), width);
3911     height = Pos->bottom - Pos->top;
3912     height = min(max(height, mint.y), maxt.y);
3913 
3914     switch (Edge)
3915     {
3916     case HTTOP: /* Maximized (Calculate RECT snap preview for SC_MOVE) */
3917         height = min(Pos->bottom - Pos->top, maxs.y);
3918         break;
3919     case HTLEFT:
3920         Pos->right = width;
3921         break;
3922     case HTRIGHT:
3923         Pos->left = Pos->right - width;
3924         break;
3925     default:
3926         ERR("Unexpected snap edge %#x\n", Edge);
3927     }
3928     Pos->bottom = Pos->top + height;
3929 }
3930 
3931 VOID FASTCALL
co_IntSnapWindow(PWND Wnd,UINT Edge)3932 co_IntSnapWindow(PWND Wnd, UINT Edge)
3933 {
3934     RECT newPos;
3935     BOOLEAN wasSnapped = IntIsWindowSnapped(Wnd);
3936     UINT normal = !(Wnd->style & (WS_MAXIMIZE | WS_MINIMIZE));
3937     USER_REFERENCE_ENTRY ref;
3938     BOOLEAN hasRef = FALSE;
3939 
3940     if (Edge == HTTOP)
3941     {
3942         co_IntSendMessage(UserHMGetHandle(Wnd), WM_SYSCOMMAND, SC_MAXIMIZE, 0);
3943         return;
3944     }
3945     else if (Edge != HTNOWHERE)
3946     {
3947         UserRefObjectCo(Wnd, &ref);
3948         hasRef = TRUE;
3949         co_IntCalculateSnapPosition(Wnd, Edge, &newPos);
3950         IntSetSnapInfo(Wnd, Edge, (wasSnapped || !normal) ? NULL : &Wnd->rcWindow);
3951     }
3952     else if (wasSnapped)
3953     {
3954         if (!normal)
3955         {
3956             IntSetSnapEdge(Wnd, HTNOWHERE);
3957             return;
3958         }
3959         newPos = Wnd->InternalPos.NormalRect; /* Copy RECT now before it is lost */
3960         IntSetSnapInfo(Wnd, HTNOWHERE, NULL);
3961     }
3962     else
3963     {
3964         return; /* Already unsnapped, do nothing */
3965     }
3966 
3967     TRACE("WindowSnap: %d->%d\n", IntGetWindowSnapEdge(Wnd), Edge);
3968     co_WinPosSetWindowPos(Wnd, HWND_TOP,
3969                           newPos.left,
3970                           newPos.top,
3971                           newPos.right - newPos.left,
3972                           newPos.bottom - newPos.top,
3973                           0);
3974     if (hasRef)
3975         UserDerefObjectCo(Wnd);
3976 }
3977 
3978 VOID FASTCALL
IntSetSnapEdge(PWND Wnd,UINT Edge)3979 IntSetSnapEdge(PWND Wnd, UINT Edge)
3980 {
3981     UINT styleMask = WS_EX2_VERTICALLYMAXIMIZEDLEFT | WS_EX2_VERTICALLYMAXIMIZEDRIGHT;
3982     UINT style = 0;
3983     switch (Edge)
3984     {
3985     case HTNOWHERE:
3986         style = 0;
3987         break;
3988     case HTTOP: /* Maximize throws away the snap */
3989         style = 0;
3990         break;
3991     case HTLEFT:
3992         style = WS_EX2_VERTICALLYMAXIMIZEDLEFT;
3993         break;
3994     case HTRIGHT:
3995         style = WS_EX2_VERTICALLYMAXIMIZEDRIGHT;
3996         break;
3997     default:
3998         ERR("Unexpected snap edge %#x\n", Edge);
3999     }
4000     Wnd->ExStyle2 = (Wnd->ExStyle2 & ~styleMask) | style;
4001 }
4002 
4003 VOID FASTCALL
IntSetSnapInfo(PWND Wnd,UINT Edge,IN const RECT * Pos OPTIONAL)4004 IntSetSnapInfo(PWND Wnd, UINT Edge, IN const RECT *Pos OPTIONAL)
4005 {
4006     RECT r;
4007     IntSetSnapEdge(Wnd, Edge);
4008     if (Edge == HTNOWHERE)
4009     {
4010         RECTL_vSetEmptyRect(&r);
4011         Pos = (Wnd->style & WS_MINIMIZE) ? NULL : &r;
4012     }
4013     if (Pos)
4014     {
4015         Wnd->InternalPos.NormalRect = *Pos;
4016     }
4017 }
4018 
4019 /* EOF */
4020