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