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