xref: /reactos/win32ss/user/ntuser/winpos.c (revision a1fc312a)
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->ExStyle & WS_EX_APPWINDOW) ||
1908           (!(Window->ExStyle & WS_EX_TOOLWINDOW) && !Window->spwndOwner &&
1909            (!Window->spwndParent || UserIsDesktopWindow(Window->spwndParent))))
1910       {
1911          co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
1912          if (!(WinPos.flags & SWP_NOACTIVATE))
1913             UpdateShellHook(Window);
1914       }
1915 
1916       Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
1917       Window->head.pti->cVisWindows++;
1918       IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1919    }
1920 
1921    if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1922    {
1923       NtGdiOffsetRgn(Window->hrgnUpdate,
1924                      NewWindowRect.left - OldWindowRect.left,
1925                      NewWindowRect.top - OldWindowRect.top);
1926    }
1927 
1928    DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
1929 
1930    // Change or update, set send non-client paint flag.
1931    if ( Window->style & WS_VISIBLE &&
1932        (WinPos.flags & SWP_STATECHANGED || (!(Window->state2 & WNDS2_WIN31COMPAT) && WinPos.flags & SWP_NOREDRAW ) ) )
1933    {
1934       TRACE("Set WNDS_SENDNCPAINT %p\n",Window);
1935       Window->state |= WNDS_SENDNCPAINT;
1936    }
1937 
1938    if (!(WinPos.flags & SWP_NOREDRAW))
1939    {
1940       /* Determine the new visible region */
1941       VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1942                                           (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1943 
1944       if ( VisAfter != NULL &&
1945            REGION_Complexity(VisAfter) == NULLREGION )
1946       {
1947          REGION_Delete(VisAfter);
1948          VisAfter = NULL;
1949       }
1950       else if(VisAfter)
1951       {
1952          REGION_bOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1953       }
1954 
1955       /*
1956        * Determine which pixels can be copied from the old window position
1957        * to the new. Those pixels must be visible in both the old and new
1958        * position. Also, check the class style to see if the windows of this
1959        * class need to be completely repainted on (horizontal/vertical) size
1960        * change.
1961        */
1962       if ( ( VisBefore != NULL &&
1963              VisAfter != NULL &&
1964             !(WinPos.flags & SWP_NOCOPYBITS) &&
1965             ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1966             !(Window->ExStyle & WS_EX_TRANSPARENT) ) )
1967       {
1968 
1969          /*
1970           * If this is (also) a window resize, the whole nonclient area
1971           * needs to be repainted. So we limit the copy to the client area,
1972           * 'cause there is no use in copying it (would possibly cause
1973           * "flashing" too). However, if the copy region is already empty,
1974           * we don't have to crop (can't take anything away from an empty
1975           * region...)
1976           */
1977 
1978          CopyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
1979          if ((WinPos.flags & SWP_NOSIZE) && (WinPos.flags & SWP_NOCLIENTSIZE))
1980             RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1981          else if (VisBeforeJustClient != NULL)
1982          {
1983             RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND);
1984          }
1985 
1986          if (VisBeforeJustClient != NULL)
1987          {
1988              REGION_Delete(VisBeforeJustClient);
1989          }
1990 
1991          /* Now use in copying bits which are in the update region. */
1992          if (Window->hrgnUpdate != NULL)
1993          {
1994             PREGION RgnUpdate = REGION_LockRgn(Window->hrgnUpdate);
1995             if (RgnUpdate)
1996             {
1997                 REGION_bOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1998                 IntGdiCombineRgn(CopyRgn, CopyRgn, RgnUpdate, RGN_DIFF);
1999                 REGION_bOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
2000                 REGION_UnlockRgn(RgnUpdate);
2001             }
2002          }
2003 
2004          /*
2005           * Now, get the bounding box of the copy region. If it's empty
2006           * there's nothing to copy. Also, it's no use copying bits onto
2007           * themselves.
2008           */
2009          if (REGION_GetRgnBox(CopyRgn, &CopyRect) == NULLREGION)
2010          {
2011             /* Nothing to copy, clean up */
2012             REGION_Delete(CopyRgn);
2013             CopyRgn = NULL;
2014          }
2015          else if ( OldWindowRect.left != NewWindowRect.left ||
2016                    OldWindowRect.top != NewWindowRect.top ||
2017                   (WinPos.flags & SWP_FRAMECHANGED) )
2018          {
2019              HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
2020              PREGION DcRgnObj = REGION_LockRgn(DcRgn);
2021 
2022           /*
2023            * Small trick here: there is no function to bitblt a region. So
2024            * we set the region as the clipping region, take the bounding box
2025            * of the region and bitblt that. Since nothing outside the clipping
2026            * region is copied, this has the effect of bitblt'ing the region.
2027            *
2028            * Since NtUserGetDCEx takes ownership of the clip region, we need
2029            * to create a copy of CopyRgn and pass that. We need CopyRgn later
2030            */
2031             IntGdiCombineRgn(DcRgnObj, CopyRgn, NULL, RGN_COPY);
2032             REGION_bOffsetRgn(DcRgnObj, NewWindowRect.left, NewWindowRect.top);
2033             REGION_UnlockRgn(DcRgnObj);
2034             Dc = UserGetDCEx( Window,
2035                               DcRgn,
2036                               DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN); // DCX_WINDOW will set first, go read WinDC.c.
2037             NtGdiBitBlt( Dc,
2038                          CopyRect.left, CopyRect.top,
2039                          CopyRect.right - CopyRect.left,
2040                          CopyRect.bottom - CopyRect.top,
2041                          Dc,
2042                          CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
2043                          CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
2044                          SRCCOPY,
2045                          0,
2046                          0);
2047 
2048             UserReleaseDC(Window, Dc, FALSE);
2049             IntValidateParent(Window, CopyRgn);
2050             GreDeleteObject(DcRgn);
2051          }
2052       }
2053       else
2054       {
2055          CopyRgn = NULL;
2056       }
2057 
2058       /* We need to redraw what wasn't visible before or force a redraw */
2059       if (VisAfter != NULL)
2060       {
2061          PREGION DirtyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2062          if (DirtyRgn)
2063          {
2064              if (CopyRgn != NULL)
2065              {
2066                 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
2067              }
2068              else
2069              {
2070                 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
2071              }
2072 
2073              if (RgnType != ERROR && RgnType != NULLREGION) // Regions moved.
2074              {
2075             /* old code
2076                 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2077                 IntInvalidateWindows( Window,
2078                                       DirtyRgn,
2079                    RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2080              }
2081              GreDeleteObject(DirtyRgn);
2082              */
2083 
2084                 PWND Parent = Window->spwndParent;
2085 
2086                 REGION_bOffsetRgn( DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2087 
2088                 if ( (Window->style & WS_CHILD) && (Parent) && !(Parent->style & WS_CLIPCHILDREN))
2089                 {
2090                    IntInvalidateWindows( Parent, DirtyRgn, RDW_ERASE | RDW_INVALIDATE);
2091                    co_IntPaintWindows(Parent, RDW_NOCHILDREN, FALSE);
2092                 }
2093                 else
2094                 {
2095                    IntInvalidateWindows( Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2096                 }
2097              }
2098              else if ( RgnType != ERROR && RgnType == NULLREGION ) // Must be the same. See CORE-7166 & CORE-15934, NC HACK fix.
2099              {
2100                 if ( !PosChanged &&
2101                      !(WinPos.flags & SWP_DEFERERASE) &&
2102                       (WinPos.flags & SWP_FRAMECHANGED) )
2103                 {
2104                     PWND pwnd = Window;
2105                     PWND Parent = Window->spwndParent;
2106 
2107                     if ( pwnd->style & WS_CHILD ) // Fix ProgMan menu bar drawing.
2108                     {
2109                         TRACE("SWP_FRAMECHANGED win child %p Parent %p\n",pwnd,Parent);
2110                         pwnd = Parent ? Parent : pwnd;
2111                     }
2112 
2113                     if ( !(pwnd->style & WS_CHILD) )
2114                     {
2115                         /*
2116                          * Check if we have these specific windows style bits set/reset.
2117                          * FIXME: There may be other combinations of styles that need this handling as well.
2118                          * This fixes the ReactOS Calculator buttons disappearing in CORE-16827.
2119                          */
2120                         if ((Window->style & WS_CLIPSIBLINGS) && !(Window->style & (WS_POPUP | WS_CLIPCHILDREN | WS_SIZEBOX)))
2121                         {
2122                             IntSendNCPaint(pwnd, HRGN_WINDOW); // Paint the whole frame.
2123                         }
2124                         else  // Use region handling
2125                         {
2126                             HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
2127                             PREGION DcRgnObj = REGION_LockRgn(DcRgn);
2128                             TRACE("SWP_FRAMECHANGED win %p hRgn %p\n",pwnd, DcRgn);
2129                             IntGdiCombineRgn(DcRgnObj, VisBefore, NULL, RGN_COPY);
2130                             REGION_UnlockRgn(DcRgnObj);
2131                             ForceNCPaintErase(pwnd, DcRgn, DcRgnObj);
2132                             GreDeleteObject(DcRgn);
2133                         }
2134                     }
2135                 }
2136              }
2137              REGION_Delete(DirtyRgn);
2138          }
2139       }
2140 
2141       if (CopyRgn != NULL)
2142       {
2143          REGION_Delete(CopyRgn);
2144       }
2145 
2146       /* Expose what was covered before but not covered anymore */
2147       if ( VisBefore != NULL )
2148       {
2149          PREGION ExposedRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2150          if (ExposedRgn)
2151          {
2152              RgnType = IntGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
2153              REGION_bOffsetRgn(ExposedRgn,
2154                                OldWindowRect.left - NewWindowRect.left,
2155                                OldWindowRect.top  - NewWindowRect.top);
2156 
2157              if ( VisAfter != NULL )
2158                 RgnType = IntGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
2159 
2160              if (RgnType != ERROR && RgnType != NULLREGION)
2161              {
2162                 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
2163              }
2164              REGION_Delete(ExposedRgn);
2165          }
2166          REGION_Delete(VisBefore);
2167       }
2168 
2169       if (VisAfter != NULL)
2170       {
2171          REGION_Delete(VisAfter);
2172       }
2173    }
2174 
2175    if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2176    {
2177       if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2178       {
2179          co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
2180       }
2181       else
2182       {
2183          //ERR("SetWindowPos Set FG Window!\n");
2184          if ( pti->MessageQueue->spwndActive != Window ||
2185               pti->MessageQueue != gpqForeground )
2186          {
2187             //ERR("WPSWP : set active window\n");
2188             if (!(Window->state & WNDS_BEINGACTIVATED)) // Inside SAW?
2189             {
2190                co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
2191             }
2192          }
2193       }
2194    }
2195 
2196    if ( !PosChanged &&
2197          (WinPos.flags & SWP_FRAMECHANGED) &&
2198         !(WinPos.flags & SWP_DEFERERASE) &&    // Prevent sending WM_SYNCPAINT message.
2199          VisAfter )
2200    {
2201        PWND Parent = Window->spwndParent;
2202        if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
2203        {
2204            TRACE("SWP_FRAMECHANGED Parent %p WS_CLIPCHILDREN %p\n",Parent,Window);
2205            UserSyncAndPaintWindows( Parent, RDW_CLIPCHILDREN); // NC should redraw here, see NC HACK fix.
2206        }
2207    }
2208 
2209    // Fix wine msg test_SetFocus, prevents sending WM_WINDOWPOSCHANGED.
2210    if ( VisBefore == NULL &&
2211         VisBeforeJustClient == NULL &&
2212        !(Window->ExStyle & WS_EX_TOPMOST) &&
2213         (WinPos.flags & SWP_AGG_STATUSFLAGS) == (SWP_AGG_NOPOSCHANGE & ~SWP_NOZORDER))
2214    {
2215       TRACE("No drawing, set no Z order and no redraw!\n");
2216       WinPos.flags |= SWP_NOZORDER|SWP_NOREDRAW;
2217    }
2218 
2219    if(!(flags & SWP_DEFERERASE))
2220    {
2221        /* erase parent when hiding or resizing child */
2222        if ((flags & SWP_HIDEWINDOW) ||
2223          (!(flags & SWP_SHOWWINDOW) &&
2224           (WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE))
2225        {
2226            PWND Parent = Window->spwndParent;
2227            if (!Parent || UserIsDesktopWindow(Parent)) Parent = Window;
2228            UserSyncAndPaintWindows( Parent, RDW_ERASENOW);
2229        }
2230 
2231        /* Give newly shown windows a chance to redraw */
2232        if(((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2233                 && !(flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW))
2234        {
2235            UserSyncAndPaintWindows( Window, RDW_ERASENOW);
2236        }
2237    }
2238 
2239    /* And last, send the WM_WINDOWPOSCHANGED message */
2240 
2241    TRACE("\tstatus hwnd %p flags = %04x\n",Window?Window->head.h:NULL,WinPos.flags & SWP_AGG_STATUSFLAGS);
2242 
2243    if (((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2244             && !((flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW)))
2245    {
2246       /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2247          and always contains final window position.
2248        */
2249       WinPos.x = NewWindowRect.left;
2250       WinPos.y = NewWindowRect.top;
2251       WinPos.cx = NewWindowRect.right - NewWindowRect.left;
2252       WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
2253       TRACE("WM_WINDOWPOSCHANGED hwnd %p Flags %04x\n",WinPos.hwnd,WinPos.flags);
2254       co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
2255    }
2256 
2257    if ( WinPos.flags & SWP_FRAMECHANGED  || WinPos.flags & SWP_STATECHANGED ||
2258       !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
2259    {
2260       PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
2261       if (pWnd)
2262          IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2263    }
2264 
2265    if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
2266    {
2267       /* Generate mouse move message */
2268       MSG msg;
2269       msg.message = WM_MOUSEMOVE;
2270       msg.wParam = UserGetMouseButtonsState();
2271       msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2272       msg.pt = gpsi->ptCursor;
2273       co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2274    }
2275 
2276    return TRUE;
2277 }
2278 
2279 LRESULT FASTCALL
2280 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
2281 {
2282    LRESULT Result;
2283 
2284    ASSERT_REFS_CO(Window);
2285 
2286    *ClientRect = *WindowRect;
2287    Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
2288 
2289    FixClientRect(ClientRect, WindowRect);
2290 
2291    return Result;
2292 }
2293 
2294 void FASTCALL
2295 co_WinPosSendSizeMove(PWND Wnd)
2296 {
2297     RECTL Rect;
2298     LPARAM lParam;
2299     WPARAM wParam = SIZE_RESTORED;
2300 
2301     IntGetClientRect(Wnd, &Rect);
2302     lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
2303 
2304     Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
2305 
2306     if (Wnd->style & WS_MAXIMIZE)
2307     {
2308         wParam = SIZE_MAXIMIZED;
2309     }
2310     else if (Wnd->style & WS_MINIMIZE)
2311     {
2312         wParam = SIZE_MINIMIZED;
2313         lParam = 0;
2314     }
2315 
2316     co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
2317 
2318     if (UserIsDesktopWindow(Wnd->spwndParent))
2319        lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
2320     else
2321        lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
2322 
2323     co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
2324 
2325     IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
2326 }
2327 
2328 UINT FASTCALL
2329 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
2330 {
2331    POINT Size;
2332    WINDOWPLACEMENT wpl;
2333    LONG old_style;
2334    UINT SwpFlags = 0;
2335 
2336    ASSERT_REFS_CO(Wnd);
2337 
2338    wpl.length = sizeof(wpl);
2339    IntGetWindowPlacement( Wnd, &wpl );
2340 
2341    if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
2342    {
2343       ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
2344       return SWP_NOSIZE | SWP_NOMOVE;
2345    }
2346       if (Wnd->style & WS_MINIMIZE)
2347       {
2348          switch (ShowFlag)
2349          {
2350          case SW_MINIMIZE:
2351          case SW_SHOWMINNOACTIVE:
2352          case SW_SHOWMINIMIZED:
2353          case SW_FORCEMINIMIZE:
2354              return SWP_NOSIZE | SWP_NOMOVE;
2355          }
2356          if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
2357          {
2358             return(SWP_NOSIZE | SWP_NOMOVE);
2359          }
2360          SwpFlags |= SWP_NOCOPYBITS;
2361       }
2362       switch (ShowFlag)
2363       {
2364          case SW_MINIMIZE:
2365          case SW_SHOWMINNOACTIVE:
2366          case SW_SHOWMINIMIZED:
2367          case SW_FORCEMINIMIZE:
2368             {
2369                //ERR("MinMaximize Minimize\n");
2370                if (Wnd->style & WS_MAXIMIZE)
2371                {
2372                   Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
2373                }
2374                else
2375                {
2376                   Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2377                }
2378 
2379                old_style = IntSetStyle( Wnd, WS_MINIMIZE, WS_MAXIMIZE );
2380 
2381                co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOINTERNALPAINT);
2382 
2383                if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION))
2384                   Wnd->InternalPos.flags &= ~WPF_MININIT;
2385 
2386                WinPosFindIconPos(Wnd, &wpl.ptMinPosition);
2387 
2388                if (!(old_style & WS_MINIMIZE))
2389                {
2390                   SwpFlags |= SWP_STATECHANGED;
2391                   IntShowOwnedPopups(Wnd, FALSE);
2392                }
2393 
2394                RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
2395                              wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
2396                              wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
2397                SwpFlags |= SWP_NOCOPYBITS;
2398                break;
2399             }
2400 
2401          case SW_MAXIMIZE:
2402             {
2403                //ERR("MinMaximize Maximize\n");
2404                if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE))
2405                {
2406                   SwpFlags = SWP_NOSIZE | SWP_NOMOVE;
2407                   break;
2408                }
2409                co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2410 
2411                /*ERR("Maximize: %d,%d %dx%d\n",
2412                       wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
2413                 */
2414                old_style = IntSetStyle( Wnd, WS_MAXIMIZE, WS_MINIMIZE );
2415                /*if (old_style & WS_MINIMIZE)
2416                {
2417                   IntShowOwnedPopups(Wnd, TRUE);
2418                }*/
2419 
2420                if (!(old_style & WS_MAXIMIZE)) SwpFlags |= SWP_STATECHANGED;
2421                RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2422                               //wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2423                               Size.x, Size.y);
2424                break;
2425             }
2426 
2427          case SW_SHOWNOACTIVATE:
2428             Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2429             /* fall through */
2430          case SW_SHOWNORMAL:
2431          case SW_RESTORE:
2432          case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
2433             {
2434                //ERR("MinMaximize Restore\n");
2435                old_style = IntSetStyle( Wnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
2436                if (old_style & WS_MINIMIZE)
2437                {
2438                   IntShowOwnedPopups(Wnd, TRUE);
2439 
2440                   if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED)
2441                   {
2442                      co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2443                      IntSetStyle( Wnd, WS_MAXIMIZE, 0 );
2444                      SwpFlags |= SWP_STATECHANGED;
2445                      RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2446                                     wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2447                      break;
2448                   }
2449                   else
2450                   {
2451                      *NewPos = wpl.rcNormalPosition;
2452                      NewPos->right -= NewPos->left;
2453                      NewPos->bottom -= NewPos->top;
2454                      break;
2455                   }
2456                }
2457                else
2458                {
2459                   if (!(old_style & WS_MAXIMIZE))
2460                   {
2461                      break;
2462                   }
2463                   SwpFlags |= SWP_STATECHANGED;
2464                   Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2465                   *NewPos = wpl.rcNormalPosition;
2466                   NewPos->right -= NewPos->left;
2467                   NewPos->bottom -= NewPos->top;
2468                   break;
2469                }
2470             }
2471       }
2472    return SwpFlags;
2473 }
2474 
2475 /*
2476    ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits!
2477  */
2478 BOOLEAN FASTCALL
2479 co_WinPosShowWindow(PWND Wnd, INT Cmd)
2480 {
2481    BOOLEAN WasVisible;
2482    UINT Swp = 0, EventMsg = 0;
2483    RECTL NewPos = {0, 0, 0, 0};
2484    BOOLEAN ShowFlag;
2485    LONG style;
2486    PWND Parent;
2487    PTHREADINFO pti;
2488    //HRGN VisibleRgn;
2489    BOOL ShowOwned = FALSE;
2490    BOOL FirstTime = FALSE;
2491    ASSERT_REFS_CO(Wnd);
2492    //KeRosDumpStackFrames(NULL, 20);
2493    pti = PsGetCurrentThreadWin32Thread();
2494    WasVisible = (Wnd->style & WS_VISIBLE) != 0;
2495    style = Wnd->style;
2496 
2497    TRACE("co_WinPosShowWindow START hwnd %p Cmd %d usicmd %u\n",
2498          Wnd->head.h, Cmd, pti->ppi->usi.wShowWindow);
2499 
2500    if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2501    {
2502       if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2503       {
2504          if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
2505          {
2506             if (Wnd->spwndOwner == NULL)
2507             {
2508                if ( Cmd == SW_SHOWNORMAL || Cmd == SW_SHOW)
2509                {
2510                     Cmd = SW_SHOWDEFAULT;
2511                }
2512                FirstTime = TRUE;
2513                TRACE("co_WPSW FT 1\n");
2514             }
2515          }
2516       }
2517    }
2518 
2519    if ( Cmd == SW_SHOWDEFAULT )
2520    {
2521       if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2522       {
2523          Cmd = pti->ppi->usi.wShowWindow;
2524          FirstTime = TRUE;
2525          TRACE("co_WPSW FT 2\n");
2526       }
2527    }
2528 
2529    if (FirstTime)
2530    {
2531       pti->ppi->usi.dwFlags &= ~(STARTF_USEPOSITION|STARTF_USESIZE|STARTF_USESHOWWINDOW);
2532    }
2533 
2534    switch (Cmd)
2535    {
2536       case SW_HIDE:
2537          {
2538             if (!WasVisible)
2539             {
2540                //ERR("co_WinPosShowWindow Exit Bad\n");
2541                return FALSE;
2542             }
2543             Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2544             if (Wnd != pti->MessageQueue->spwndActive)
2545                Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2546             break;
2547          }
2548 
2549       case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2550       case SW_SHOWMINNOACTIVE:
2551          Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2552          /* Fall through. */
2553       case SW_SHOWMINIMIZED:
2554          Swp |= SWP_SHOWWINDOW;
2555          /* Fall through. */
2556       case SW_MINIMIZE:
2557          {
2558             Swp |= SWP_NOACTIVATE;
2559             if (!(style & WS_MINIMIZE))
2560             {
2561                IntShowOwnedPopups(Wnd, FALSE );
2562                // Fix wine Win test_SetFocus todo #1 & #2,
2563                if (Cmd == SW_SHOWMINIMIZED)
2564                {
2565                   //ERR("co_WinPosShowWindow Set focus 1\n");
2566                   if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2567                      co_UserSetFocus(Wnd->spwndParent);
2568                   else
2569                      co_UserSetFocus(0);
2570                }
2571 
2572                Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2573 
2574                EventMsg = EVENT_SYSTEM_MINIMIZESTART;
2575             }
2576             else
2577             {
2578                if (WasVisible)
2579                {
2580                   //ERR("co_WinPosShowWindow Exit Good\n");
2581                   return TRUE;
2582                }
2583                Swp |= SWP_NOSIZE | SWP_NOMOVE;
2584             }
2585             break;
2586          }
2587 
2588       case SW_SHOWMAXIMIZED:
2589          {
2590             Swp |= SWP_SHOWWINDOW;
2591             if (!(style & WS_MAXIMIZE))
2592             {
2593                ShowOwned = TRUE;
2594 
2595                Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos);
2596 
2597                EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2598             }
2599             else
2600             {
2601                if (WasVisible)
2602                {
2603                   //ERR("co_WinPosShowWindow Exit Good 1\n");
2604                   return TRUE;
2605                }
2606                Swp |= SWP_NOSIZE | SWP_NOMOVE;
2607             }
2608             break;
2609          }
2610 
2611       case SW_SHOWNA:
2612          Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2613          if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
2614          break;
2615       case SW_SHOW:
2616          if (WasVisible) return(TRUE); // Nothing to do!
2617          Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2618          /* Don't activate the topmost window. */
2619          if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2620          break;
2621 
2622       case SW_SHOWNOACTIVATE:
2623          Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2624          /* Fall through. */
2625       case SW_SHOWNORMAL:
2626       case SW_SHOWDEFAULT:
2627       case SW_RESTORE:
2628          if (!WasVisible) Swp |= SWP_SHOWWINDOW;
2629          if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2630          {
2631             Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2632             if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2633          }
2634          else
2635          {
2636             if (WasVisible)
2637             {
2638                //ERR("co_WinPosShowWindow Exit Good 3\n");
2639                return TRUE;
2640             }
2641             Swp |= SWP_NOSIZE | SWP_NOMOVE;
2642          }
2643          if ( style & WS_CHILD &&
2644              !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2645              !(Swp & SWP_STATECHANGED))
2646             Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2647          break;
2648 
2649       default:
2650          //ERR("co_WinPosShowWindow Exit Good 4\n");
2651          return WasVisible;
2652    }
2653 
2654    ShowFlag = (Cmd != SW_HIDE);
2655 
2656    if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
2657    {
2658       co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
2659 #if 0 // Fix wine msg test_SetParent:WmSetParentSeq_1:2
2660       if (!(Wnd->state2 & WNDS2_WIN31COMPAT)) // <------------- XP sets this bit!
2661          co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
2662 #endif
2663       if (!VerifyWnd(Wnd)) return WasVisible;
2664    }
2665 
2666    /* We can't activate a child window */
2667    if ((Wnd->style & WS_CHILD) &&
2668        !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2669        Cmd != SW_SHOWNA)
2670    {
2671       //ERR("SWP Child No active and ZOrder\n");
2672       Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2673    }
2674 
2675 #if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works.
2676       // Breaks startup and shutdown active window...
2677    if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
2678         Wnd->pcls->style & CS_SAVEBITS &&
2679         ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
2680    {
2681       ERR("WinPosShowWindow Set active\n");
2682       //UserSetActiveWindow(Wnd);
2683       co_IntSetForegroundWindow(Wnd); // HACK
2684       Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2685    }
2686 #endif
2687 
2688    if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
2689    {
2690        TRACE("Child is Vis %s or State changed %s. ShowFlag %s Swp %04x\n",
2691              (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
2692              (ShowFlag ? "TRUE" : "FALSE"),LOWORD(Swp));
2693    co_WinPosSetWindowPos( Wnd,
2694                           0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
2695                           NewPos.left,
2696                           NewPos.top,
2697                           NewPos.right, // NewPos.right - NewPos.left, when minimized and restore, the window becomes smaller.
2698                           NewPos.bottom,// NewPos.bottom - NewPos.top,
2699                           LOWORD(Swp));
2700    }
2701    else
2702    {
2703       TRACE("Parent Vis?\n");
2704       /* if parent is not visible simply toggle WS_VISIBLE and return */
2705       if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
2706       else IntSetStyle( Wnd, 0, WS_VISIBLE );
2707    }
2708 
2709    if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2710 
2711    if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
2712 
2713    if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
2714    {
2715       if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue()  )
2716       {
2717           if (UserIsDesktopWindow(Wnd->spwndParent))
2718           {
2719               if (!ActivateOtherWindowMin(Wnd))
2720               {
2721                 co_WinPosActivateOtherWindow(Wnd);
2722               }
2723           }
2724           else
2725           {
2726               co_WinPosActivateOtherWindow(Wnd);
2727           }
2728       }
2729 
2730       /* Revert focus to parent */
2731       if (Wnd == pti->MessageQueue->spwndFocus)
2732       {
2733          Parent = Wnd->spwndParent;
2734          if (UserIsDesktopWindow(Wnd->spwndParent))
2735              Parent = 0;
2736          co_UserSetFocus(Parent);
2737       }
2738       // Hide, just return.
2739       if (Cmd == SW_HIDE) return WasVisible;
2740    }
2741 
2742    /* FIXME: Check for window destruction. */
2743 
2744    if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
2745        !(Wnd->state2 & WNDS2_INDESTROY))
2746    {
2747         co_WinPosSendSizeMove(Wnd);
2748    }
2749 
2750    /* if previous state was minimized Windows sets focus to the window */
2751    if (style & WS_MINIMIZE)
2752    {
2753       co_UserSetFocus(Wnd);
2754       // Fix wine Win test_SetFocus todo #3,
2755       if (!(style & WS_CHILD)) co_IntSendMessage(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
2756    }
2757    //ERR("co_WinPosShowWindow EXIT\n");
2758    return WasVisible;
2759 }
2760 
2761 static PWND
2762 co_WinPosSearchChildren(
2763    IN PWND ScopeWin,
2764    IN POINT *Point,
2765    IN OUT USHORT *HitTest,
2766    IN BOOL Ignore
2767    )
2768 {
2769     HWND *List, *phWnd;
2770     PWND pwndChild = NULL;
2771 
2772     /* not visible */
2773     if (!(ScopeWin->style & WS_VISIBLE))
2774     {
2775         return NULL;
2776     }
2777 
2778     /* not in window or in window region */
2779     if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2780     {
2781         return NULL;
2782     }
2783 
2784     /* transparent */
2785     if ((ScopeWin->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
2786     {
2787         return NULL;
2788     }
2789 
2790     if (!Ignore && (ScopeWin->style & WS_DISABLED))
2791     {   /* disabled child */
2792         if ((ScopeWin->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return NULL;
2793         /* process the hit error */
2794         *HitTest = HTERROR;
2795         return ScopeWin;
2796     }
2797 
2798     /* not minimized and check if point is inside the window */
2799     if (!(ScopeWin->style & WS_MINIMIZE) &&
2800          RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2801     {
2802         UserReferenceObject(ScopeWin);
2803 
2804         List = IntWinListChildren(ScopeWin);
2805         if (List)
2806         {
2807             for (phWnd = List; *phWnd; ++phWnd)
2808             {
2809                 if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
2810                 {
2811                     continue;
2812                 }
2813 
2814                 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
2815 
2816                 if (pwndChild != NULL)
2817                 {
2818                     /* We found a window. Don't send any more WM_NCHITTEST messages */
2819                     ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2820                     UserDereferenceObject(ScopeWin);
2821                     return pwndChild;
2822                 }
2823             }
2824             ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2825         }
2826         UserDereferenceObject(ScopeWin);
2827     }
2828 
2829     if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
2830     {
2831        *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0, MAKELONG(Point->x, Point->y));
2832 
2833        if ((*HitTest) == (USHORT)HTTRANSPARENT)
2834        {
2835            return NULL;
2836        }
2837     }
2838     else
2839     {
2840        if (*HitTest == HTNOWHERE && pwndChild == NULL) *HitTest = HTCLIENT;
2841     }
2842 
2843     return ScopeWin;
2844 }
2845 
2846 PWND APIENTRY
2847 co_WinPosWindowFromPoint(
2848    IN PWND ScopeWin,
2849    IN POINT *WinPoint,
2850    IN OUT USHORT* HitTest,
2851    IN BOOL Ignore)
2852 {
2853    PWND Window;
2854    POINT Point = *WinPoint;
2855    USER_REFERENCE_ENTRY Ref;
2856 
2857    if( ScopeWin == NULL )
2858    {
2859        ScopeWin = UserGetDesktopWindow();
2860        if(ScopeWin == NULL)
2861            return NULL;
2862    }
2863 
2864    *HitTest = HTNOWHERE;
2865 
2866    ASSERT_REFS_CO(ScopeWin);
2867    UserRefObjectCo(ScopeWin, &Ref);
2868 
2869    Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
2870 
2871    UserDerefObjectCo(ScopeWin);
2872    if (Window)
2873        ASSERT_REFS_CO(Window);
2874    ASSERT_REFS_CO(ScopeWin);
2875 
2876    return Window;
2877 }
2878 
2879 PWND FASTCALL
2880 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2881 {
2882    POINTL Pt;
2883    HWND *List, *phWnd;
2884    PWND pwndHit = NULL;
2885 
2886    Pt.x = x;
2887    Pt.y = y;
2888 
2889    if (!UserIsDesktopWindow(Parent))
2890    {
2891       Pt.x += Parent->rcClient.left;
2892       Pt.y += Parent->rcClient.top;
2893    }
2894 
2895    if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2896 
2897    if ((List = IntWinListChildren(Parent)))
2898    {
2899       for (phWnd = List; *phWnd; phWnd++)
2900       {
2901          PWND Child;
2902          if ((Child = ValidateHwndNoErr(*phWnd)))
2903          {
2904             if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
2905             {
2906                if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
2907                    (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
2908                {
2909                   ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2910                   return Child;
2911                }
2912                pwndHit = Child;
2913             }
2914          }
2915       }
2916       ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2917    }
2918    return pwndHit ? pwndHit : Parent;
2919 }
2920 
2921 PWND APIENTRY
2922 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
2923 {
2924    POINTL Pt;
2925    HWND *List, *phWnd;
2926    PWND pwndHit = NULL;
2927 
2928    Pt.x = x;
2929    Pt.y = y;
2930 
2931    if (!UserIsDesktopWindow(Parent))
2932    {
2933       if (Parent->ExStyle & WS_EX_LAYOUTRTL)
2934          Pt.x = Parent->rcClient.right - Pt.x;
2935       else
2936          Pt.x += Parent->rcClient.left;
2937       Pt.y += Parent->rcClient.top;
2938    }
2939 
2940    if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2941 
2942    if ((List = IntWinListChildren(Parent)))
2943    {
2944       for (phWnd = List; *phWnd; phWnd++)
2945       {
2946          PWND Child;
2947          if ((Child = ValidateHwndNoErr(*phWnd)))
2948          {
2949             if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
2950             {
2951                if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
2952                if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
2953             }
2954 
2955             if (uiFlags & CWP_SKIPTRANSPARENT)
2956             {
2957                if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
2958             }
2959 
2960             if (IntPtInWindow(Child, Pt.x, Pt.y))
2961             {
2962                pwndHit = Child;
2963                break;
2964             }
2965          }
2966       }
2967       ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2968    }
2969    return pwndHit ? pwndHit : Parent;
2970 }
2971 
2972 HDWP
2973 FASTCALL
2974 IntDeferWindowPos( HDWP hdwp,
2975                    HWND hwnd,
2976                    HWND hwndAfter,
2977                    INT x,
2978                    INT y,
2979                    INT cx,
2980                    INT cy,
2981                    UINT flags )
2982 {
2983     PSMWP pDWP;
2984     int i;
2985     HDWP retvalue = hdwp;
2986 
2987     TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2988           hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2989 
2990     if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
2991                   SWP_NOZORDER | SWP_NOREDRAW |
2992                   SWP_NOACTIVATE | SWP_NOCOPYBITS |
2993                   SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
2994                   SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2995     {
2996        EngSetLastError(ERROR_INVALID_PARAMETER);
2997        return NULL;
2998     }
2999 
3000     if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
3001     {
3002        EngSetLastError(ERROR_INVALID_DWP_HANDLE);
3003        return NULL;
3004     }
3005 
3006     for (i = 0; i < pDWP->ccvr; i++)
3007     {
3008         if (pDWP->acvr[i].pos.hwnd == hwnd)
3009         {
3010               /* Merge with the other changes */
3011             if (!(flags & SWP_NOZORDER))
3012             {
3013                 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
3014             }
3015             if (!(flags & SWP_NOMOVE))
3016             {
3017                 pDWP->acvr[i].pos.x = x;
3018                 pDWP->acvr[i].pos.y = y;
3019             }
3020             if (!(flags & SWP_NOSIZE))
3021             {
3022                 pDWP->acvr[i].pos.cx = cx;
3023                 pDWP->acvr[i].pos.cy = cy;
3024             }
3025             pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
3026                                                SWP_NOZORDER | SWP_NOREDRAW |
3027                                                SWP_NOACTIVATE | SWP_NOCOPYBITS|
3028                                                SWP_NOOWNERZORDER);
3029             pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
3030                                               SWP_FRAMECHANGED);
3031             goto END;
3032         }
3033     }
3034     if (pDWP->ccvr >= pDWP->ccvrAlloc)
3035     {
3036         PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
3037         if (!newpos)
3038         {
3039             retvalue = NULL;
3040             goto END;
3041         }
3042         RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
3043         RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
3044         ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
3045         pDWP->ccvrAlloc *= 2;
3046         pDWP->acvr = newpos;
3047     }
3048     pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
3049     pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
3050     pDWP->acvr[pDWP->ccvr].pos.x = x;
3051     pDWP->acvr[pDWP->ccvr].pos.y = y;
3052     pDWP->acvr[pDWP->ccvr].pos.cx = cx;
3053     pDWP->acvr[pDWP->ccvr].pos.cy = cy;
3054     pDWP->acvr[pDWP->ccvr].pos.flags = flags;
3055     pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
3056     pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
3057     pDWP->ccvr++;
3058 END:
3059     return retvalue;
3060 }
3061 
3062 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
3063 {
3064     PSMWP pDWP;
3065     PCVR winpos;
3066     BOOL res = TRUE;
3067     int i;
3068 
3069     TRACE("%p\n", hdwp);
3070 
3071     if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
3072     {
3073        EngSetLastError(ERROR_INVALID_DWP_HANDLE);
3074        return FALSE;
3075     }
3076 
3077     for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
3078     {
3079         PWND pwnd;
3080         USER_REFERENCE_ENTRY Ref;
3081 
3082         TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3083                winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
3084                winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
3085 
3086         pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
3087         if (!pwnd)
3088            continue;
3089 
3090         UserRefObjectCo(pwnd, &Ref);
3091 
3092         if ( sAsync )
3093         {
3094            LRESULT lRes;
3095            PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
3096            if ( ppos )
3097            {
3098               *ppos = winpos->pos;
3099               /* Yes it's a pointer inside Win32k! */
3100               lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
3101               /* We handle this the same way as Event Hooks and Hooks. */
3102               if ( !lRes )
3103               {
3104                  ExFreePoolWithTag(ppos, USERTAG_SWP);
3105               }
3106            }
3107         }
3108         else
3109            res = co_WinPosSetWindowPos( pwnd,
3110                                         winpos->pos.hwndInsertAfter,
3111                                         winpos->pos.x,
3112                                         winpos->pos.y,
3113                                         winpos->pos.cx,
3114                                         winpos->pos.cy,
3115                                         winpos->pos.flags);
3116 
3117         // Hack to pass tests.... Must have some work to do so clear the error.
3118         if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
3119            EngSetLastError(ERROR_SUCCESS);
3120 
3121         UserDerefObjectCo(pwnd);
3122     }
3123     ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
3124     UserDereferenceObject(pDWP);
3125     UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
3126     return res;
3127 }
3128 
3129 /*
3130  * @implemented
3131  */
3132 HWND APIENTRY
3133 NtUserChildWindowFromPointEx(HWND hwndParent,
3134                              LONG x,
3135                              LONG y,
3136                              UINT uiFlags)
3137 {
3138    PWND pwndParent;
3139    TRACE("Enter NtUserChildWindowFromPointEx\n");
3140    UserEnterExclusive();
3141    if ((pwndParent = UserGetWindowObject(hwndParent)))
3142    {
3143       pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
3144    }
3145    UserLeave();
3146    TRACE("Leave NtUserChildWindowFromPointEx\n");
3147    return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3148 }
3149 
3150 /*
3151  * @implemented
3152  */
3153 BOOL APIENTRY
3154 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
3155                           DWORD Unknown1)
3156 {
3157    BOOL Ret;
3158    TRACE("Enter NtUserEndDeferWindowPosEx\n");
3159    UserEnterExclusive();
3160    Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
3161    TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
3162    UserLeave();
3163    return Ret;
3164 }
3165 
3166 /*
3167  * @implemented
3168  */
3169 HDWP APIENTRY
3170 NtUserDeferWindowPos(HDWP WinPosInfo,
3171                      HWND Wnd,
3172                      HWND WndInsertAfter,
3173                      int x,
3174                      int y,
3175                      int cx,
3176                      int cy,
3177                      UINT Flags)
3178 {
3179    PWND pWnd, pWndIA;
3180    HDWP Ret = NULL;
3181    UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
3182                 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
3183                 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
3184 
3185    TRACE("Enter NtUserDeferWindowPos\n");
3186    UserEnterExclusive();
3187 
3188    if ( Flags & Tmp )
3189    {
3190       EngSetLastError(ERROR_INVALID_FLAGS);
3191       goto Exit;
3192    }
3193 
3194    pWnd = UserGetWindowObject(Wnd);
3195    if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3196    {
3197       goto Exit;
3198    }
3199 
3200    if ( WndInsertAfter &&
3201         WndInsertAfter != HWND_BOTTOM &&
3202         WndInsertAfter != HWND_TOPMOST &&
3203         WndInsertAfter != HWND_NOTOPMOST )
3204    {
3205       pWndIA = UserGetWindowObject(WndInsertAfter);
3206       if (!pWndIA || UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3207       {
3208          goto Exit;
3209       }
3210    }
3211 
3212    Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
3213 
3214 Exit:
3215    TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
3216    UserLeave();
3217    return Ret;
3218 }
3219 
3220 /*
3221  * @implemented
3222  */
3223 DWORD APIENTRY
3224 NtUserGetInternalWindowPos( HWND hWnd,
3225                             LPRECT rectWnd,
3226                             LPPOINT ptIcon)
3227 {
3228    PWND Window;
3229    DWORD Ret = 0;
3230    BOOL Hit = FALSE;
3231    WINDOWPLACEMENT wndpl;
3232 
3233    UserEnterShared();
3234 
3235    if (!(Window = UserGetWindowObject(hWnd)))
3236    {
3237       Hit = FALSE;
3238       goto Exit;
3239    }
3240 
3241    _SEH2_TRY
3242    {
3243        if(rectWnd)
3244        {
3245           ProbeForWrite(rectWnd,
3246                         sizeof(RECT),
3247                         1);
3248        }
3249        if(ptIcon)
3250        {
3251           ProbeForWrite(ptIcon,
3252                         sizeof(POINT),
3253                         1);
3254        }
3255 
3256    }
3257    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3258    {
3259        SetLastNtError(_SEH2_GetExceptionCode());
3260        Hit = TRUE;
3261    }
3262    _SEH2_END;
3263 
3264    wndpl.length = sizeof(WINDOWPLACEMENT);
3265 
3266    if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3267    {
3268       _SEH2_TRY
3269       {
3270           if (rectWnd)
3271           {
3272              RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3273           }
3274           if (ptIcon)
3275           {
3276              RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3277           }
3278 
3279       }
3280       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3281       {
3282           SetLastNtError(_SEH2_GetExceptionCode());
3283           Hit = TRUE;
3284       }
3285       _SEH2_END;
3286 
3287       if (!Hit) Ret = wndpl.showCmd;
3288    }
3289 Exit:
3290    UserLeave();
3291    return Ret;
3292 }
3293 
3294 /*
3295  * @implemented
3296  */
3297 BOOL APIENTRY
3298 NtUserGetWindowPlacement(HWND hWnd,
3299                          WINDOWPLACEMENT *lpwndpl)
3300 {
3301    PWND Wnd;
3302    WINDOWPLACEMENT Safepl;
3303    NTSTATUS Status;
3304    DECLARE_RETURN(BOOL);
3305 
3306    TRACE("Enter NtUserGetWindowPlacement\n");
3307    UserEnterShared();
3308 
3309    if (!(Wnd = UserGetWindowObject(hWnd)))
3310    {
3311       RETURN( FALSE);
3312    }
3313 
3314    Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3315    if (!NT_SUCCESS(Status))
3316    {
3317       SetLastNtError(Status);
3318       RETURN( FALSE);
3319    }
3320 
3321    Safepl.length = sizeof(WINDOWPLACEMENT);
3322 
3323    IntGetWindowPlacement(Wnd, &Safepl);
3324 
3325    Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
3326    if (!NT_SUCCESS(Status))
3327    {
3328       SetLastNtError(Status);
3329       RETURN( FALSE);
3330    }
3331 
3332    RETURN( TRUE);
3333 
3334 CLEANUP:
3335    TRACE("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
3336    UserLeave();
3337    END_CLEANUP;
3338 }
3339 
3340 DWORD
3341 APIENTRY
3342 NtUserMinMaximize(
3343     HWND hWnd,
3344     UINT cmd, // Wine SW_ commands
3345     BOOL Hide)
3346 {
3347   PWND pWnd;
3348 
3349   TRACE("Enter NtUserMinMaximize\n");
3350   UserEnterExclusive();
3351 
3352   pWnd = UserGetWindowObject(hWnd);
3353   if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3354   {
3355      goto Exit;
3356   }
3357 
3358   if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
3359   {
3360      EngSetLastError(ERROR_INVALID_PARAMETER);
3361      goto Exit;
3362   }
3363 
3364   cmd |= Hide ? SW_HIDE : 0;
3365 
3366   co_WinPosShowWindow(pWnd, cmd);
3367 
3368 Exit:
3369   TRACE("Leave NtUserMinMaximize\n");
3370   UserLeave();
3371   return 0; // Always NULL?
3372 }
3373 
3374 /*
3375  * @implemented
3376  */
3377 BOOL APIENTRY
3378 NtUserMoveWindow(
3379    HWND hWnd,
3380    int X,
3381    int Y,
3382    int nWidth,
3383    int nHeight,
3384    BOOL bRepaint)
3385 {
3386    return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
3387                              (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
3388                               SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
3389 }
3390 
3391 /*
3392  * @implemented
3393  */
3394 HWND APIENTRY
3395 NtUserRealChildWindowFromPoint(HWND Parent,
3396                                LONG x,
3397                                LONG y)
3398 {
3399    PWND pwndParent;
3400    TRACE("Enter NtUserRealChildWindowFromPoint\n");
3401    UserEnterShared();
3402    if ((pwndParent = UserGetWindowObject(Parent)))
3403    {
3404       pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y);
3405    }
3406    UserLeave();
3407    TRACE("Leave NtUserRealChildWindowFromPoint\n");
3408    return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3409 }
3410 
3411 /*
3412  * @implemented
3413  */
3414 BOOL APIENTRY
3415 NtUserSetWindowPos(
3416    HWND hWnd,
3417    HWND hWndInsertAfter,
3418    int X,
3419    int Y,
3420    int cx,
3421    int cy,
3422    UINT uFlags)
3423 {
3424    DECLARE_RETURN(BOOL);
3425    PWND Window, pWndIA;
3426    BOOL ret;
3427    USER_REFERENCE_ENTRY Ref;
3428 
3429    TRACE("Enter NtUserSetWindowPos\n");
3430    UserEnterExclusive();
3431 
3432    if (!(Window = UserGetWindowObject(hWnd)) ||
3433         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3434    {
3435       ERR("NtUserSetWindowPos bad window handle!\n");
3436       RETURN(FALSE);
3437    }
3438 
3439    if ( hWndInsertAfter != HWND_TOP &&
3440         hWndInsertAfter != HWND_BOTTOM &&
3441         hWndInsertAfter != HWND_TOPMOST &&
3442         hWndInsertAfter != HWND_NOTOPMOST )
3443    {
3444       if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) ||
3445             UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3446       {
3447          ERR("NtUserSetWindowPos bad insert window handle!\n");
3448          RETURN(FALSE);
3449       }
3450    }
3451 
3452    /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3453    if (!(uFlags & SWP_NOMOVE))
3454    {
3455       if (X < -32768) X = -32768;
3456       else if (X > 32767) X = 32767;
3457       if (Y < -32768) Y = -32768;
3458       else if (Y > 32767) Y = 32767;
3459    }
3460    if (!(uFlags & SWP_NOSIZE))
3461    {
3462       if (cx < 0) cx = 0;
3463       else if (cx > 32767) cx = 32767;
3464       if (cy < 0) cy = 0;
3465       else if (cy > 32767) cy = 32767;
3466    }
3467 
3468    UserRefObjectCo(Window, &Ref);
3469    ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
3470    UserDerefObjectCo(Window);
3471 
3472    RETURN(ret);
3473 
3474 CLEANUP:
3475    TRACE("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
3476    UserLeave();
3477    END_CLEANUP;
3478 }
3479 
3480 /*
3481  * @implemented
3482  */
3483 INT APIENTRY
3484 NtUserSetWindowRgn(
3485    HWND hWnd,
3486    HRGN hRgn,
3487    BOOL bRedraw)
3488 {
3489    HRGN hrgnCopy = NULL;
3490    PWND Window;
3491    INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
3492    BOOLEAN Ret = FALSE;
3493    DECLARE_RETURN(INT);
3494 
3495    TRACE("Enter NtUserSetWindowRgn\n");
3496    UserEnterExclusive();
3497 
3498    if (!(Window = UserGetWindowObject(hWnd)) ||
3499         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3500    {
3501       RETURN( 0);
3502    }
3503 
3504    if (hRgn) // The region will be deleted in user32.
3505    {
3506       if (GreIsHandleValid(hRgn))
3507       {
3508          hrgnCopy = NtGdiCreateRectRgn(0, 0, 0, 0);
3509       /* The coordinates of a window's window region are relative to the
3510          upper-left corner of the window, not the client area of the window. */
3511          NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY);
3512       }
3513       else
3514          RETURN( 0);
3515    }
3516 
3517    //// HACK 1 : Work around the lack of supporting DeferWindowPos.
3518    if (hrgnCopy)
3519    {
3520        Window->hrgnNewFrame = hrgnCopy; // Should be PSMWP->acvr->hrgnClip
3521    }
3522    else
3523    {
3524        Window->hrgnNewFrame = HRGN_WINDOW;
3525    }
3526    //// HACK 2
3527    Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) );
3528 
3529    RETURN( (INT)Ret);
3530 
3531 CLEANUP:
3532    TRACE("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
3533    UserLeave();
3534    END_CLEANUP;
3535 }
3536 
3537 /*
3538  * @implemented
3539  */
3540 DWORD APIENTRY
3541 NtUserSetInternalWindowPos(
3542    HWND    hwnd,
3543    UINT    showCmd,
3544    LPRECT  lprect,
3545    LPPOINT lppt)
3546 {
3547    WINDOWPLACEMENT wndpl;
3548    UINT flags;
3549    PWND Wnd;
3550    RECT rect;
3551    POINT pt = {0};
3552    DECLARE_RETURN(BOOL);
3553    USER_REFERENCE_ENTRY Ref;
3554 
3555    TRACE("Enter NtUserSetWindowPlacement\n");
3556    UserEnterExclusive();
3557 
3558    if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME:
3559         UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd))
3560    {
3561       RETURN( FALSE);
3562    }
3563 
3564    _SEH2_TRY
3565    {
3566       if (lppt)
3567       {
3568          ProbeForRead(lppt, sizeof(POINT), 1);
3569          RtlCopyMemory(&pt, lppt, sizeof(POINT));
3570       }
3571       if (lprect)
3572       {
3573          ProbeForRead(lprect, sizeof(RECT), 1);
3574          RtlCopyMemory(&rect, lprect, sizeof(RECT));
3575       }
3576    }
3577    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3578    {
3579       SetLastNtError(_SEH2_GetExceptionCode());
3580       _SEH2_YIELD(RETURN( FALSE));
3581    }
3582    _SEH2_END
3583 
3584    wndpl.length  = sizeof(wndpl);
3585    wndpl.showCmd = showCmd;
3586    wndpl.flags = flags = 0;
3587 
3588    if ( lppt )
3589    {
3590       flags |= PLACE_MIN;
3591       wndpl.flags |= WPF_SETMINPOSITION;
3592       wndpl.ptMinPosition = pt;
3593    }
3594    if ( lprect )
3595    {
3596       flags |= PLACE_RECT;
3597       wndpl.rcNormalPosition = rect;
3598    }
3599 
3600    UserRefObjectCo(Wnd, &Ref);
3601    IntSetWindowPlacement(Wnd, &wndpl, flags);
3602    UserDerefObjectCo(Wnd);
3603    RETURN(TRUE);
3604 
3605 CLEANUP:
3606    TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3607    UserLeave();
3608    END_CLEANUP;
3609 }
3610 
3611 /*
3612  * @implemented
3613  */
3614 BOOL APIENTRY
3615 NtUserSetWindowPlacement(HWND hWnd,
3616                          WINDOWPLACEMENT *lpwndpl)
3617 {
3618    PWND Wnd;
3619    WINDOWPLACEMENT Safepl;
3620    UINT Flags;
3621    DECLARE_RETURN(BOOL);
3622    USER_REFERENCE_ENTRY Ref;
3623 
3624    TRACE("Enter NtUserSetWindowPlacement\n");
3625    UserEnterExclusive();
3626 
3627    if (!(Wnd = UserGetWindowObject(hWnd)) ||
3628         UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd))
3629    {
3630       RETURN( FALSE);
3631    }
3632 
3633    _SEH2_TRY
3634    {
3635       ProbeForRead(lpwndpl, sizeof(WINDOWPLACEMENT), 1);
3636       RtlCopyMemory(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3637    }
3638    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3639    {
3640       SetLastNtError(_SEH2_GetExceptionCode());
3641       _SEH2_YIELD(RETURN( FALSE));
3642    }
3643    _SEH2_END
3644 
3645    if(Safepl.length != sizeof(WINDOWPLACEMENT))
3646    {
3647       RETURN( FALSE);
3648    }
3649 
3650    Flags = PLACE_MAX | PLACE_RECT;
3651    if (Safepl.flags & WPF_SETMINPOSITION) Flags |= PLACE_MIN;
3652    UserRefObjectCo(Wnd, &Ref);
3653    IntSetWindowPlacement(Wnd, &Safepl, Flags);
3654    UserDerefObjectCo(Wnd);
3655    RETURN(TRUE);
3656 
3657 CLEANUP:
3658    TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3659    UserLeave();
3660    END_CLEANUP;
3661 }
3662 
3663 /*
3664  * @implemented
3665  */
3666 BOOL APIENTRY
3667 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
3668 {
3669    PWND Window;
3670    BOOL ret;
3671    DECLARE_RETURN(BOOL);
3672    USER_REFERENCE_ENTRY Ref;
3673 
3674    TRACE("Enter NtUserShowWindowAsync\n");
3675    UserEnterExclusive();
3676 
3677    if (!(Window = UserGetWindowObject(hWnd)) ||
3678         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3679    {
3680       RETURN(FALSE);
3681    }
3682 
3683    if ( nCmdShow > SW_MAX )
3684    {
3685       EngSetLastError(ERROR_INVALID_PARAMETER);
3686       RETURN(FALSE);
3687    }
3688 
3689    UserRefObjectCo(Window, &Ref);
3690    ret = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 );
3691    UserDerefObjectCo(Window);
3692    if (-1 == (int) ret || !ret) ret = FALSE;
3693 
3694    RETURN(ret);
3695 
3696 CLEANUP:
3697    TRACE("Leave NtUserShowWindowAsync, ret=%i\n",_ret_);
3698    UserLeave();
3699    END_CLEANUP;
3700 }
3701 
3702 /*
3703  * @implemented
3704  */
3705 BOOL APIENTRY
3706 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
3707 {
3708    PWND Window;
3709    BOOL ret;
3710    DECLARE_RETURN(BOOL);
3711    USER_REFERENCE_ENTRY Ref;
3712 
3713    TRACE("Enter NtUserShowWindow hWnd %p SW_ %d\n",hWnd, nCmdShow);
3714    UserEnterExclusive();
3715 
3716    if (!(Window = UserGetWindowObject(hWnd)) ||
3717         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3718    {
3719       RETURN(FALSE);
3720    }
3721 
3722    if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
3723    {
3724       EngSetLastError(ERROR_INVALID_PARAMETER);
3725       RETURN(FALSE);
3726    }
3727 
3728    UserRefObjectCo(Window, &Ref);
3729    ret = co_WinPosShowWindow(Window, nCmdShow);
3730    UserDerefObjectCo(Window);
3731 
3732    RETURN(ret);
3733 
3734 CLEANUP:
3735    TRACE("Leave NtUserShowWindow, ret=%i\n",_ret_);
3736    UserLeave();
3737    END_CLEANUP;
3738 }
3739 
3740 
3741 /*
3742  *    @implemented
3743  */
3744 HWND APIENTRY
3745 NtUserWindowFromPoint(LONG X, LONG Y)
3746 {
3747    POINT pt;
3748    HWND Ret;
3749    PWND DesktopWindow = NULL, Window = NULL;
3750    USHORT hittest;
3751    DECLARE_RETURN(HWND);
3752    USER_REFERENCE_ENTRY Ref;
3753 
3754    TRACE("Enter NtUserWindowFromPoint\n");
3755    UserEnterExclusive();
3756 
3757    if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
3758    {
3759       //PTHREADINFO pti;
3760 
3761       pt.x = X;
3762       pt.y = Y;
3763 
3764       // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window.
3765       // It is possible this referencing is useless, though it should not hurt...
3766       UserRefObjectCo(DesktopWindow, &Ref);
3767 
3768       //pti = PsGetCurrentThreadWin32Thread();
3769       Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest, FALSE);
3770 
3771       if (Window)
3772       {
3773          Ret = UserHMGetHandle(Window);
3774 
3775          RETURN( Ret);
3776       }
3777    }
3778 
3779    RETURN( NULL);
3780 
3781 CLEANUP:
3782    if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
3783 
3784    TRACE("Leave NtUserWindowFromPoint, ret=%p\n", _ret_);
3785    UserLeave();
3786    END_CLEANUP;
3787 }
3788 
3789 /* EOF */
3790