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