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