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