xref: /reactos/win32ss/user/ntuser/winpos.c (revision f2df3bf0)
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)
892       Border += 1;
893    if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
894       Border += 2;
895    if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
896       Border ++;
897    Size->cx = Size->cy = Border;
898    if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
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 BOOL WINAPI
908 UserAdjustWindowRectEx(LPRECT lpRect,
909                        DWORD dwStyle,
910                        BOOL bMenu,
911                        DWORD dwExStyle)
912 {
913    SIZE BorderSize;
914 
915    if (bMenu)
916    {
917       lpRect->top -= UserGetSystemMetrics(SM_CYMENU);
918    }
919    if ((dwStyle & WS_CAPTION) == WS_CAPTION)
920    {
921       if (dwExStyle & WS_EX_TOOLWINDOW)
922          lpRect->top -= UserGetSystemMetrics(SM_CYSMCAPTION);
923       else
924          lpRect->top -= UserGetSystemMetrics(SM_CYCAPTION);
925    }
926    UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
927    RECTL_vInflateRect(
928       lpRect,
929       BorderSize.cx,
930       BorderSize.cy);
931 
932    return TRUE;
933 }
934 
935 UINT FASTCALL
936 co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
937                        POINT* MinTrack, POINT* MaxTrack)
938 {
939     MINMAXINFO MinMax;
940     PMONITOR monitor;
941     INT xinc, yinc;
942     LONG style = Window->style;
943     LONG adjustedStyle;
944     LONG exstyle = Window->ExStyle;
945     RECT rc;
946 
947     ASSERT_REFS_CO(Window);
948 
949     /* Compute default values */
950 
951     rc = Window->rcWindow;
952     MinMax.ptReserved.x = rc.left;
953     MinMax.ptReserved.y = rc.top;
954 
955     if ((style & WS_CAPTION) == WS_CAPTION)
956         adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
957     else
958         adjustedStyle = style;
959 
960     if(Window->spwndParent)
961         IntGetClientRect(Window->spwndParent, &rc);
962     UserAdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && Window->IDMenu), exstyle);
963 
964     xinc = -rc.left;
965     yinc = -rc.top;
966 
967     MinMax.ptMaxSize.x = rc.right - rc.left;
968     MinMax.ptMaxSize.y = rc.bottom - rc.top;
969     if (style & (WS_DLGFRAME | WS_BORDER))
970     {
971         MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
972         MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
973     }
974     else
975     {
976         MinMax.ptMinTrackSize.x = 2 * xinc;
977         MinMax.ptMinTrackSize.y = 2 * yinc;
978     }
979     MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK);
980     MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK);
981     MinMax.ptMaxPosition.x = -xinc;
982     MinMax.ptMaxPosition.y = -yinc;
983 
984    if (!EMPTYPOINT(Window->InternalPos.MaxPos)) MinMax.ptMaxPosition = Window->InternalPos.MaxPos;
985 
986     co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
987 
988     /* if the app didn't change the values, adapt them for the current monitor */
989     if ((monitor = UserGetPrimaryMonitor()))
990     {
991         RECT rc_work;
992 
993         rc_work = monitor->rcMonitor;
994 
995         if (style & WS_MAXIMIZEBOX)
996         {
997             if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
998                 rc_work = monitor->rcWork;
999         }
1000 
1001         if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
1002             MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
1003         {
1004             MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
1005             MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
1006         }
1007         if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
1008         {
1009             MinMax.ptMaxPosition.x = rc_work.left - xinc;
1010             MinMax.ptMaxPosition.y = rc_work.top - yinc;
1011         }
1012         if (MinMax.ptMaxSize.x >= (monitor->rcMonitor.right - monitor->rcMonitor.left) &&
1013             MinMax.ptMaxSize.y >= (monitor->rcMonitor.bottom - monitor->rcMonitor.top) )
1014             Window->state |= WNDS_MAXIMIZESTOMONITOR;
1015         else
1016             Window->state &= ~WNDS_MAXIMIZESTOMONITOR;
1017     }
1018 
1019 
1020    MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
1021                                  MinMax.ptMinTrackSize.x);
1022    MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
1023                                  MinMax.ptMinTrackSize.y);
1024 
1025    if (MaxSize)
1026       *MaxSize = MinMax.ptMaxSize;
1027    if (MaxPos)
1028       *MaxPos = MinMax.ptMaxPosition;
1029    if (MinTrack)
1030       *MinTrack = MinMax.ptMinTrackSize;
1031    if (MaxTrack)
1032       *MaxTrack = MinMax.ptMaxTrackSize;
1033 
1034    return 0; // FIXME: What does it return?
1035 }
1036 
1037 static
1038 BOOL
1039 IntValidateParent(PWND Child, PREGION ValidateRgn)
1040 {
1041    PWND ParentWnd = Child;
1042 
1043    if (ParentWnd->style & WS_CHILD)
1044    {
1045       do
1046          ParentWnd = ParentWnd->spwndParent;
1047       while (ParentWnd->style & WS_CHILD);
1048    }
1049 
1050    ParentWnd = Child->spwndParent;
1051    while (ParentWnd)
1052    {
1053       if (ParentWnd->style & WS_CLIPCHILDREN)
1054          break;
1055 
1056       if (ParentWnd->hrgnUpdate != 0)
1057       {
1058          IntInvalidateWindows( ParentWnd,
1059                                ValidateRgn,
1060                                RDW_VALIDATE | RDW_NOCHILDREN);
1061       }
1062 
1063       ParentWnd = ParentWnd->spwndParent;
1064    }
1065 
1066    return TRUE;
1067 }
1068 
1069 static
1070 VOID FASTCALL
1071 FixClientRect(PRECTL ClientRect, PRECTL WindowRect)
1072 {
1073    if (ClientRect->left < WindowRect->left)
1074    {
1075       ClientRect->left = WindowRect->left;
1076    }
1077    else if (WindowRect->right < ClientRect->left)
1078    {
1079       ClientRect->left = WindowRect->right;
1080    }
1081    if (ClientRect->right < WindowRect->left)
1082    {
1083       ClientRect->right = WindowRect->left;
1084    }
1085    else if (WindowRect->right < ClientRect->right)
1086    {
1087       ClientRect->right = WindowRect->right;
1088    }
1089    if (ClientRect->top < WindowRect->top)
1090    {
1091       ClientRect->top = WindowRect->top;
1092    }
1093    else if (WindowRect->bottom < ClientRect->top)
1094    {
1095       ClientRect->top = WindowRect->bottom;
1096    }
1097    if (ClientRect->bottom < WindowRect->top)
1098    {
1099       ClientRect->bottom = WindowRect->top;
1100    }
1101    else if (WindowRect->bottom < ClientRect->bottom)
1102    {
1103       ClientRect->bottom = WindowRect->bottom;
1104    }
1105 }
1106 /***********************************************************************
1107  *           get_valid_rects
1108  *
1109  * Compute the valid rects from the old and new client rect and WVR_* flags.
1110  * Helper for WM_NCCALCSIZE handling.
1111  */
1112 static
1113 VOID FASTCALL
1114 get_valid_rects( RECTL *old_client, RECTL *new_client, UINT flags, RECTL *valid )
1115 {
1116     int cx, cy;
1117 
1118     if (flags & WVR_REDRAW)
1119     {
1120         RECTL_vSetEmptyRect( &valid[0] );
1121         RECTL_vSetEmptyRect( &valid[1] );
1122         return;
1123     }
1124 
1125     if (flags & WVR_VALIDRECTS)
1126     {
1127         if (!RECTL_bIntersectRect( &valid[0], &valid[0], new_client ) ||
1128             !RECTL_bIntersectRect( &valid[1], &valid[1], old_client ))
1129         {
1130             RECTL_vSetEmptyRect( &valid[0] );
1131             RECTL_vSetEmptyRect( &valid[1] );
1132             return;
1133         }
1134         flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
1135     }
1136     else
1137     {
1138         valid[0] = *new_client;
1139         valid[1] = *old_client;
1140     }
1141 
1142     /* make sure the rectangles have the same size */
1143     cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
1144     cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
1145 
1146     if (flags & WVR_ALIGNBOTTOM)
1147     {
1148         valid[0].top = valid[0].bottom - cy;
1149         valid[1].top = valid[1].bottom - cy;
1150     }
1151     else
1152     {
1153         valid[0].bottom = valid[0].top + cy;
1154         valid[1].bottom = valid[1].top + cy;
1155     }
1156     if (flags & WVR_ALIGNRIGHT)
1157     {
1158         valid[0].left = valid[0].right - cx;
1159         valid[1].left = valid[1].right - cx;
1160     }
1161     else
1162     {
1163         valid[0].right = valid[0].left + cx;
1164         valid[1].right = valid[1].left + cx;
1165     }
1166 }
1167 
1168 static
1169 LONG FASTCALL
1170 co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos, RECTL* WindowRect, RECTL* ClientRect, RECTL* validRects)
1171 {
1172    PWND Parent;
1173    UINT wvrFlags = 0;
1174 
1175    ASSERT_REFS_CO(Window);
1176 
1177    /* Send WM_NCCALCSIZE message to get new client area */
1178    if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
1179    {
1180       NCCALCSIZE_PARAMS params;
1181       WINDOWPOS winposCopy;
1182 
1183       params.rgrc[0] = *WindowRect;      // new coordinates of a window that has been moved or resized
1184       params.rgrc[1] = Window->rcWindow; // window before it was moved or resized
1185       params.rgrc[2] = Window->rcClient; // client area before the window was moved or resized
1186 
1187       Parent = Window->spwndParent;
1188       if (0 != (Window->style & WS_CHILD) && Parent)
1189       {
1190          RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left, - Parent->rcClient.top);
1191          RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left, - Parent->rcClient.top);
1192          RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left, - Parent->rcClient.top);
1193       }
1194 
1195       params.lppos = &winposCopy;
1196       winposCopy = *WinPos;
1197 
1198       wvrFlags = co_IntSendMessage(Window->head.h, WM_NCCALCSIZE, TRUE, (LPARAM) &params);
1199 
1200       /* If the application send back garbage, ignore it */
1201       if (params.rgrc[0].left <= params.rgrc[0].right &&
1202           params.rgrc[0].top <= params.rgrc[0].bottom)
1203       {
1204          *ClientRect = params.rgrc[0]; // First rectangle contains the coordinates of the new client rectangle resulting from the move or resize
1205          if ((Window->style & WS_CHILD) && Parent)
1206          {
1207             RECTL_vOffsetRect(ClientRect, Parent->rcClient.left, Parent->rcClient.top);
1208          }
1209          FixClientRect(ClientRect, WindowRect);
1210       }
1211 
1212       if (ClientRect->left != Window->rcClient.left ||
1213           ClientRect->top != Window->rcClient.top)
1214       {
1215          WinPos->flags &= ~SWP_NOCLIENTMOVE;
1216       }
1217 
1218       if (ClientRect->right - ClientRect->left != Window->rcClient.right - Window->rcClient.left)
1219       {
1220          WinPos->flags &= ~SWP_NOCLIENTSIZE;
1221       }
1222       else
1223          wvrFlags &= ~WVR_HREDRAW;
1224 
1225       if (ClientRect->bottom - ClientRect->top != Window->rcClient.bottom - Window->rcClient.top)
1226       {
1227          WinPos->flags &= ~SWP_NOCLIENTSIZE;
1228       }
1229       else
1230          wvrFlags &= ~WVR_VREDRAW;
1231 
1232       validRects[0] = params.rgrc[1]; // second rectangle contains the valid destination rectangle
1233       validRects[1] = params.rgrc[2]; // third rectangle contains the valid source rectangle
1234    }
1235    else
1236    {
1237       if (!(WinPos->flags & SWP_NOMOVE) &&
1238           (ClientRect->left != Window->rcClient.left ||
1239            ClientRect->top != Window->rcClient.top))
1240       {
1241          WinPos->flags &= ~SWP_NOCLIENTMOVE;
1242       }
1243    }
1244 
1245    if (WinPos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
1246    {
1247       RECTL_vSetEmptyRect( &validRects[0] );
1248       RECTL_vSetEmptyRect( &validRects[1] );
1249    }
1250    else get_valid_rects( &Window->rcClient, ClientRect, wvrFlags, validRects );
1251 
1252    return wvrFlags;
1253 }
1254 
1255 static
1256 BOOL FASTCALL
1257 co_WinPosDoWinPosChanging(PWND Window,
1258                           PWINDOWPOS WinPos,
1259                           PRECTL WindowRect,
1260                           PRECTL ClientRect)
1261 {
1262    ASSERT_REFS_CO(Window);
1263 
1264    /* Send WM_WINDOWPOSCHANGING message */
1265 
1266    if (!(WinPos->flags & SWP_NOSENDCHANGING)
1267           && !((WinPos->flags & SWP_AGG_NOCLIENTCHANGE) && (WinPos->flags & SWP_SHOWWINDOW)))
1268    {
1269       TRACE("Sending WM_WINDOWPOSCHANGING to hwnd %p flags %04x.\n", Window->head.h,WinPos->flags);
1270       co_IntSendMessage(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
1271    }
1272 
1273    /* Calculate new position and size */
1274 
1275    *WindowRect = Window->rcWindow;
1276    *ClientRect = (Window->style & WS_MINIMIZE) ? Window->rcWindow : Window->rcClient;
1277 
1278    if (!(WinPos->flags & SWP_NOSIZE))
1279    {
1280       if (Window->style & WS_MINIMIZE)
1281       {
1282          WindowRect->right  = WindowRect->left + UserGetSystemMetrics(SM_CXMINIMIZED);
1283          WindowRect->bottom = WindowRect->top  + UserGetSystemMetrics(SM_CYMINIMIZED);
1284       }
1285       else
1286       {
1287          WindowRect->right = WindowRect->left + WinPos->cx;
1288          WindowRect->bottom = WindowRect->top + WinPos->cy;
1289       }
1290    }
1291 
1292    if (!(WinPos->flags & SWP_NOMOVE))
1293    {
1294       INT X, Y;
1295       PWND Parent;
1296       X = WinPos->x;
1297       Y = WinPos->y;
1298 
1299       Parent = Window->spwndParent;
1300 
1301       // Parent child position issue is in here. SetParent_W7 test CORE-6651.
1302       if (//((Window->style & WS_CHILD) != 0) && <- Fixes wine msg test_SetParent: "rects do not match", the last test.
1303            Parent &&
1304            Parent != Window->head.rpdesk->pDeskInfo->spwnd)
1305       {
1306          TRACE("Not SWP_NOMOVE 1 Parent client offset X %d Y %d\n",X,Y);
1307          X += Parent->rcClient.left;
1308          Y += Parent->rcClient.top;
1309          TRACE("Not SWP_NOMOVE 2 Parent client offset X %d Y %d\n",X,Y);
1310       }
1311 
1312       WindowRect->left    = X;
1313       WindowRect->top     = Y;
1314       WindowRect->right  += X - Window->rcWindow.left;
1315       WindowRect->bottom += Y - Window->rcWindow.top;
1316 
1317       RECTL_vOffsetRect(ClientRect, X - Window->rcWindow.left,
1318                                     Y - Window->rcWindow.top);
1319    }
1320    WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1321 
1322    TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
1323            WinPos->hwnd, WinPos->hwndInsertAfter, WinPos->x, WinPos->y,
1324            WinPos->cx, WinPos->cy, WinPos->flags );
1325    TRACE("WindowRect: %d %d %d %d\n", WindowRect->left,WindowRect->top,WindowRect->right,WindowRect->bottom);
1326    TRACE("ClientRect: %d %d %d %d\n", ClientRect->left,ClientRect->top,ClientRect->right,ClientRect->bottom);
1327 
1328    return TRUE;
1329 }
1330 
1331 /*
1332  * Fix Z order taking into account owned popups -
1333  * basically we need to maintain them above the window that owns them
1334  *
1335  * FIXME: hide/show owned popups when owner visibility changes.
1336  *
1337  * ReactOS: See bug CORE-6129 and CORE-6554.
1338  *
1339  */
1340  ////
1341  // Pass all the win:test_children/popup_zorder tests except "move hwnd_F and its popups down" which is if'ed out.
1342  // Side effect, breaks more of the DeferWindowPos api tests, but wine breaks more!!!!
1343 static
1344 HWND FASTCALL
1345 WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter)
1346 {
1347    HWND *List = NULL;
1348    HWND Owner;
1349    LONG Style;
1350    PWND DesktopWindow, ChildObject;
1351    int i;
1352 
1353    TRACE("(%p) hInsertAfter = %p\n", Window, hWndInsertAfter );
1354 
1355    Style = Window->style;
1356 
1357    if (Style & WS_CHILD)
1358    {
1359       TRACE("Window is child\n");
1360       return hWndInsertAfter;
1361    }
1362 
1363    Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
1364 
1365    if (Owner)
1366    {
1367       /* Make sure this popup stays above the owner */
1368 
1369       if (hWndInsertAfter != HWND_TOPMOST)
1370       {
1371          DesktopWindow = UserGetDesktopWindow();
1372          List = IntWinListChildren(DesktopWindow);
1373 
1374          if (List != NULL)
1375          {
1376             for (i = 0; List[i]; i++)
1377             {
1378                BOOL topmost = FALSE;
1379 
1380                ChildObject = ValidateHwndNoErr(List[i]);
1381                if (ChildObject)
1382                {
1383                   topmost = (ChildObject->ExStyle & WS_EX_TOPMOST) != 0;
1384                }
1385 
1386                if (List[i] == Owner)
1387                {
1388                   if (i > 0) hWndInsertAfter = List[i-1];
1389                   else hWndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
1390                   break;
1391                }
1392 
1393                if (hWndInsertAfter == HWND_TOP || hWndInsertAfter ==  HWND_NOTOPMOST)
1394                {
1395                   if (!topmost) break;
1396                }
1397                else if (List[i] == hWndInsertAfter) break;
1398             }
1399          }
1400          else
1401             return hWndInsertAfter;
1402       }
1403    }
1404 
1405    if (hWndInsertAfter == HWND_BOTTOM)
1406    {
1407       ERR("Window is HWND_BOTTOM hwnd %p\n",hWndInsertAfter);
1408       if (List) ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1409       goto done;
1410    }
1411 
1412    if (!List)
1413    {
1414       DesktopWindow = UserGetDesktopWindow();
1415       List = IntWinListChildren(DesktopWindow);
1416    }
1417 
1418    if (List != NULL)
1419    {
1420       i = 0;
1421 
1422       if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST)
1423       {
1424          if (hWndInsertAfter == HWND_NOTOPMOST || !(Window->ExStyle & WS_EX_TOPMOST))
1425          {
1426             TRACE("skip all the topmost windows\n");
1427             /* skip all the topmost windows */
1428             while (List[i] &&
1429                    (ChildObject = ValidateHwndNoErr(List[i])) &&
1430                    (ChildObject->ExStyle & WS_EX_TOPMOST)) i++;
1431          }
1432       }
1433       else if (hWndInsertAfter != HWND_TOPMOST)
1434       {
1435         /* skip windows that are already placed correctly */
1436         for (i = 0; List[i]; i++)
1437         {
1438             if (List[i] == hWndInsertAfter) break;
1439             if (List[i] == UserHMGetHandle(Window))
1440             {
1441                ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1442                goto done;  /* nothing to do if window is moving backwards in z-order */
1443             }
1444         }
1445       }
1446 
1447       for (; List[i]; i++)
1448       {
1449          PWND Wnd;
1450          USER_REFERENCE_ENTRY Ref;
1451 
1452          if (List[i] == UserHMGetHandle(Window))
1453             break;
1454 
1455          if (!(Wnd = ValidateHwndNoErr(List[i])))
1456             continue;
1457 
1458          Owner = Wnd->spwndOwner ? Wnd->spwndOwner->head.h : NULL;
1459 
1460          if (Owner != UserHMGetHandle(Window)) continue;
1461 
1462          UserRefObjectCo(Wnd, &Ref);
1463          TRACE( "moving %p owned by %p after %p\n", List[i], UserHMGetHandle(Window), hWndInsertAfter );
1464          co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
1465                                SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING| SWP_DEFERERASE);
1466 
1467          UserDerefObjectCo(Wnd);
1468          hWndInsertAfter = List[i];
1469       }
1470       ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1471    }
1472 done:
1473    return hWndInsertAfter;
1474 }
1475 ////
1476 
1477 /***********************************************************************
1478  *      WinPosInternalMoveWindow
1479  *
1480  * Update WindowRect and ClientRect of Window and all of its children
1481  * We keep both WindowRect and ClientRect in screen coordinates internally
1482  */
1483 static
1484 VOID FASTCALL
1485 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
1486 {
1487    PWND Child;
1488 
1489    ASSERT(Window != Window->spwndChild);
1490    TRACE("InternalMoveWin  X %d Y %d\n", MoveX, MoveY);
1491 
1492    Window->rcWindow.left += MoveX;
1493    Window->rcWindow.right += MoveX;
1494    Window->rcWindow.top += MoveY;
1495    Window->rcWindow.bottom += MoveY;
1496 
1497    Window->rcClient.left += MoveX;
1498    Window->rcClient.right += MoveX;
1499    Window->rcClient.top += MoveY;
1500    Window->rcClient.bottom += MoveY;
1501 
1502    for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
1503    {
1504       WinPosInternalMoveWindow(Child, MoveX, MoveY);
1505    }
1506 }
1507 
1508 /*
1509  * WinPosFixupSWPFlags
1510  *
1511  * Fix redundant flags and values in the WINDOWPOS structure.
1512  */
1513 static
1514 BOOL FASTCALL
1515 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
1516 {
1517    PWND Parent;
1518    POINT pt;
1519 
1520    /* Finally make sure that all coordinates are valid */
1521    if (WinPos->x < -32768) WinPos->x = -32768;
1522    else if (WinPos->x > 32767) WinPos->x = 32767;
1523    if (WinPos->y < -32768) WinPos->y = -32768;
1524    else if (WinPos->y > 32767) WinPos->y = 32767;
1525 
1526    WinPos->cx = max(WinPos->cx, 0);
1527    WinPos->cy = max(WinPos->cy, 0);
1528 
1529    Parent = UserGetAncestor( Wnd, GA_PARENT );
1530    if (!IntIsWindowVisible( Parent ) &&
1531       /* Fix B : wine msg test_SetParent:WmSetParentSeq_2:25 wParam bits! */
1532        (WinPos->flags & SWP_AGG_STATUSFLAGS) == SWP_AGG_NOPOSCHANGE) WinPos->flags |= SWP_NOREDRAW;
1533 
1534    if (Wnd->style & WS_VISIBLE) WinPos->flags &= ~SWP_SHOWWINDOW;
1535    else
1536    {
1537       WinPos->flags &= ~SWP_HIDEWINDOW;
1538       if (!(WinPos->flags & SWP_SHOWWINDOW)) WinPos->flags |= SWP_NOREDRAW;
1539    }
1540 
1541    /* Check for right size */
1542    if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
1543        Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
1544    {
1545       WinPos->flags |= SWP_NOSIZE;
1546    }
1547 
1548    pt.x = WinPos->x;
1549    pt.y = WinPos->y;
1550    IntClientToScreen( Parent, &pt );
1551    TRACE("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y);
1552    /* Check for right position */
1553    if (Wnd->rcWindow.left == pt.x && Wnd->rcWindow.top == pt.y)
1554    {
1555       //ERR("In right pos\n");
1556       WinPos->flags |= SWP_NOMOVE;
1557    }
1558 
1559    if ( WinPos->hwnd != UserGetForegroundWindow() && (Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1560    {
1561       /* Bring to the top when activating */
1562       if (!(WinPos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) &&
1563            (WinPos->flags & SWP_NOZORDER ||
1564            (WinPos->hwndInsertAfter != HWND_TOPMOST && WinPos->hwndInsertAfter != HWND_NOTOPMOST)))
1565       {
1566          WinPos->flags &= ~SWP_NOZORDER;
1567          WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP);
1568       }
1569    }
1570 
1571    /* Check hwndInsertAfter */
1572    if (!(WinPos->flags & SWP_NOZORDER))
1573    {
1574       /* Fix sign extension */
1575       if (WinPos->hwndInsertAfter == (HWND)0xffff)
1576       {
1577          WinPos->hwndInsertAfter = HWND_TOPMOST;
1578       }
1579       else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
1580       {
1581          WinPos->hwndInsertAfter = HWND_NOTOPMOST;
1582       }
1583 
1584       if (WinPos->hwndInsertAfter == HWND_TOP)
1585       {
1586          /* Keep it topmost when it's already topmost */
1587          if ((Wnd->ExStyle & WS_EX_TOPMOST) != 0)
1588             WinPos->hwndInsertAfter = HWND_TOPMOST;
1589 
1590          if (IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1591          {
1592             WinPos->flags |= SWP_NOZORDER;
1593          }
1594       }
1595       else if (WinPos->hwndInsertAfter == HWND_BOTTOM)
1596       {
1597          if (!(Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDLAST) == WinPos->hwnd)
1598             WinPos->flags |= SWP_NOZORDER;
1599       }
1600       else if (WinPos->hwndInsertAfter == HWND_TOPMOST)
1601       {
1602           if ((Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd)
1603              WinPos->flags |= SWP_NOZORDER;
1604       }
1605       else if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
1606       {
1607          if (!(Wnd->ExStyle & WS_EX_TOPMOST))
1608             WinPos->flags |= SWP_NOZORDER;
1609       }
1610       else /* hwndInsertAfter must be a sibling of the window */
1611       {
1612          PWND InsAfterWnd;
1613 
1614          InsAfterWnd = ValidateHwndNoErr(WinPos->hwndInsertAfter);
1615          if(!InsAfterWnd)
1616          {
1617              return TRUE;
1618          }
1619 
1620          if (InsAfterWnd->spwndParent != Wnd->spwndParent)
1621          {
1622             /* Note from wine User32 Win test_SetWindowPos:
1623                "Returns TRUE also for windows that are not siblings"
1624                "Does not seem to do anything even without passing flags, still returns TRUE"
1625                "Same thing the other way around."
1626                ".. and with these windows."
1627              */
1628             return FALSE;
1629          }
1630          else
1631          {
1632             /*
1633              * We don't need to change the Z order of hwnd if it's already
1634              * inserted after hwndInsertAfter or when inserting hwnd after
1635              * itself.
1636              */
1637             if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
1638                 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
1639             {
1640                WinPos->flags |= SWP_NOZORDER;
1641             }
1642          }
1643       }
1644    }
1645 
1646    return TRUE;
1647 }
1648 
1649 /* x and y are always screen relative */
1650 BOOLEAN FASTCALL
1651 co_WinPosSetWindowPos(
1652    PWND Window,
1653    HWND WndInsertAfter,
1654    INT x,
1655    INT y,
1656    INT cx,
1657    INT cy,
1658    UINT flags
1659    )
1660 {
1661    WINDOWPOS WinPos;
1662    RECTL NewWindowRect;
1663    RECTL NewClientRect;
1664    RECTL valid_rects[2];
1665    PREGION VisBefore = NULL;
1666    PREGION VisBeforeJustClient = NULL;
1667    PREGION VisAfter = NULL;
1668    PREGION CopyRgn = NULL;
1669    ULONG WvrFlags = 0;
1670    RECTL OldWindowRect, OldClientRect;
1671    int RgnType;
1672    HDC Dc;
1673    RECTL CopyRect;
1674    PWND Ancestor;
1675    BOOL bPointerInWindow, PosChanged = FALSE;
1676    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1677 
1678    ASSERT_REFS_CO(Window);
1679 
1680    TRACE("pwnd %p, after %p, %d,%d (%dx%d), flags %s",
1681           Window, WndInsertAfter, x, y, cx, cy, flags);
1682 #if DBG
1683    dump_winpos_flags(flags);
1684 #endif
1685 
1686    /* FIXME: Get current active window from active queue. Why? since r2915. */
1687 
1688    bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
1689 
1690    WinPos.hwnd = Window->head.h;
1691    WinPos.hwndInsertAfter = WndInsertAfter;
1692    WinPos.x = x;
1693    WinPos.y = y;
1694    WinPos.cx = cx;
1695    WinPos.cy = cy;
1696    WinPos.flags = flags;
1697 
1698    if ( flags & SWP_ASYNCWINDOWPOS )
1699    {
1700       LRESULT lRes;
1701       PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
1702       if ( ppos )
1703       {
1704          WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag.
1705          *ppos = WinPos;
1706          /* Yes it's a pointer inside Win32k! */
1707          lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
1708          /* We handle this the same way as Event Hooks and Hooks. */
1709          if ( !lRes )
1710          {
1711             ExFreePoolWithTag(ppos, USERTAG_SWP);
1712             return FALSE;
1713          }
1714          return TRUE;
1715       }
1716       return FALSE;
1717    }
1718 
1719    co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1720 
1721    /* Does the window still exist? */
1722    if (!IntIsWindow(WinPos.hwnd))
1723    {
1724       TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd);
1725       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1726       return FALSE;
1727    }
1728 
1729    /* Fix up the flags. */
1730    if (!WinPosFixupFlags(&WinPos, Window))
1731    {
1732       // See Note.
1733       return TRUE;
1734    }
1735 
1736    Ancestor = UserGetAncestor(Window, GA_PARENT);
1737    if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER &&
1738          Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
1739    {
1740       WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
1741    }
1742 
1743    if (!(WinPos.flags & SWP_NOREDRAW))
1744    {
1745       /* Compute the visible region before the window position is changed */
1746       if (!(WinPos.flags & SWP_SHOWWINDOW) &&
1747            (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1748                              SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1749             (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1750       {
1751          VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1752                                               (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1753 
1754          if ( VisBefore != NULL &&
1755               REGION_Complexity(VisBefore) == NULLREGION )
1756          {
1757             REGION_Delete(VisBefore);
1758             VisBefore = NULL;
1759          }
1760          else if(VisBefore)
1761          {
1762             REGION_bOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1763          }
1764 
1765          /* Calculate the non client area for resizes, as this is used in the copy region */
1766          if (!(WinPos.flags & SWP_NOSIZE))
1767          {
1768              VisBeforeJustClient = VIS_ComputeVisibleRegion(Window, TRUE, FALSE,
1769                  (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1770 
1771              if ( VisBeforeJustClient != NULL &&
1772                  REGION_Complexity(VisBeforeJustClient) == NULLREGION )
1773              {
1774                  REGION_Delete(VisBeforeJustClient);
1775                  VisBeforeJustClient = NULL;
1776              }
1777              else if(VisBeforeJustClient)
1778              {
1779                  REGION_bOffsetRgn(VisBeforeJustClient, -Window->rcWindow.left, -Window->rcWindow.top);
1780              }
1781          }
1782       }
1783    }
1784 
1785    //// HACK 3
1786    if (Window->hrgnNewFrame)
1787    {
1788        SelectWindowRgn( Window, Window->hrgnNewFrame ); // Should be PSMWP->acvr->hrgnClip
1789        Window->hrgnNewFrame = NULL;
1790    }
1791 
1792    WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects);
1793 
1794 //   ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags,
1795 //      valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom,
1796 //      valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom);
1797 
1798    /* Validate link windows. (also take into account shell window in hwndShellWindow) */
1799    if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1800    {
1801       IntLinkHwnd(Window, WinPos.hwndInsertAfter);
1802    }
1803 
1804    OldWindowRect = Window->rcWindow;
1805    OldClientRect = Window->rcClient;
1806 
1807    if (NewClientRect.left != OldClientRect.left ||
1808        NewClientRect.top  != OldClientRect.top)
1809    {
1810       // Move child window if their parent is moved. Keep Child window relative to Parent...
1811       WinPosInternalMoveWindow(Window,
1812                                NewClientRect.left - OldClientRect.left,
1813                                NewClientRect.top - OldClientRect.top);
1814       PosChanged = TRUE;
1815    }
1816 
1817    Window->rcWindow = NewWindowRect;
1818    Window->rcClient = NewClientRect;
1819 
1820    /* erase parent when hiding or resizing child */
1821    if (WinPos.flags & SWP_HIDEWINDOW)
1822    {
1823       /* Clear the update region */
1824       co_UserRedrawWindow( Window,
1825                            NULL,
1826                            0,
1827                            RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1828 
1829       if (UserIsDesktopWindow(Window->spwndParent))
1830          co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)Window->head.h, 0);
1831 
1832       Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE );
1833       Window->head.pti->cVisWindows--;
1834       IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1835    }
1836    else if (WinPos.flags & SWP_SHOWWINDOW)
1837    {
1838        if (UserIsDesktopWindow(Window->spwndParent) &&
1839            Window->spwndOwner == NULL &&
1840            (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
1841             (Window->ExStyle & WS_EX_APPWINDOW)))
1842          co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)Window->head.h, 0);
1843 
1844       Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 );
1845       Window->head.pti->cVisWindows++;
1846       IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1847    }
1848 
1849    if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1850    {
1851       NtGdiOffsetRgn(Window->hrgnUpdate,
1852                      NewWindowRect.left - OldWindowRect.left,
1853                      NewWindowRect.top - OldWindowRect.top);
1854    }
1855 
1856    DceResetActiveDCEs(Window); // For WS_VISIBLE changes.
1857 
1858    if (!(WinPos.flags & SWP_NOREDRAW))
1859    {
1860       /* Determine the new visible region */
1861       VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1862                                           (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1863 
1864       if ( VisAfter != NULL &&
1865            REGION_Complexity(VisAfter) == NULLREGION )
1866       {
1867          REGION_Delete(VisAfter);
1868          VisAfter = NULL;
1869       }
1870       else if(VisAfter)
1871       {
1872          REGION_bOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1873       }
1874 
1875       /*
1876        * Determine which pixels can be copied from the old window position
1877        * to the new. Those pixels must be visible in both the old and new
1878        * position. Also, check the class style to see if the windows of this
1879        * class need to be completely repainted on (horizontal/vertical) size
1880        * change.
1881        */
1882       if ( ( VisBefore != NULL &&
1883              VisAfter != NULL &&
1884             !(WinPos.flags & SWP_NOCOPYBITS) &&
1885             ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1886             !(Window->ExStyle & WS_EX_TRANSPARENT) ) ||
1887             ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore) )
1888       {
1889 
1890          /*
1891           * If this is (also) a window resize, the whole nonclient area
1892           * needs to be repainted. So we limit the copy to the client area,
1893           * 'cause there is no use in copying it (would possibly cause
1894           * "flashing" too). However, if the copy region is already empty,
1895           * we don't have to crop (can't take anything away from an empty
1896           * region...)
1897           */
1898 
1899          CopyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
1900          if (WinPos.flags & SWP_NOSIZE)
1901             RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1902          else if (VisBeforeJustClient != NULL)
1903          {
1904             RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND);
1905             REGION_Delete(VisBeforeJustClient);
1906          }
1907 
1908          /* Now use in copying bits which are in the update region. */
1909          if (Window->hrgnUpdate != NULL)
1910          {
1911             PREGION RgnUpdate = REGION_LockRgn(Window->hrgnUpdate);
1912             if (RgnUpdate)
1913             {
1914                 REGION_bOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1915                 IntGdiCombineRgn(CopyRgn, CopyRgn, RgnUpdate, RGN_DIFF);
1916                 REGION_bOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1917                 REGION_UnlockRgn(RgnUpdate);
1918             }
1919          }
1920 
1921          /*
1922           * Now, get the bounding box of the copy region. If it's empty
1923           * there's nothing to copy. Also, it's no use copying bits onto
1924           * themselves.
1925           */
1926          if (REGION_GetRgnBox(CopyRgn, &CopyRect) == NULLREGION)
1927          {
1928             /* Nothing to copy, clean up */
1929             REGION_Delete(CopyRgn);
1930             CopyRgn = NULL;
1931          }
1932          else if ( OldWindowRect.left != NewWindowRect.left ||
1933                    OldWindowRect.top != NewWindowRect.top ||
1934                   (WinPos.flags & SWP_FRAMECHANGED) )
1935          {
1936              HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
1937              PREGION DcRgnObj = REGION_LockRgn(DcRgn);
1938 
1939           /*
1940            * Small trick here: there is no function to bitblt a region. So
1941            * we set the region as the clipping region, take the bounding box
1942            * of the region and bitblt that. Since nothing outside the clipping
1943            * region is copied, this has the effect of bitblt'ing the region.
1944            *
1945            * Since NtUserGetDCEx takes ownership of the clip region, we need
1946            * to create a copy of CopyRgn and pass that. We need CopyRgn later
1947            */
1948             IntGdiCombineRgn(DcRgnObj, CopyRgn, NULL, RGN_COPY);
1949             REGION_bOffsetRgn(DcRgnObj, NewWindowRect.left, NewWindowRect.top);
1950             REGION_UnlockRgn(DcRgnObj);
1951             Dc = UserGetDCEx( Window,
1952                               DcRgn,
1953                               DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
1954             NtGdiBitBlt( Dc,
1955                          CopyRect.left, CopyRect.top,
1956                          CopyRect.right - CopyRect.left,
1957                          CopyRect.bottom - CopyRect.top,
1958                          Dc,
1959                          CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1960                          CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
1961                          SRCCOPY,
1962                          0,
1963                          0);
1964 
1965             UserReleaseDC(Window, Dc, FALSE);
1966             IntValidateParent(Window, CopyRgn);
1967             GreDeleteObject(DcRgn);
1968          }
1969       }
1970       else
1971       {
1972          CopyRgn = NULL;
1973       }
1974 #if 0
1975       /////// Fixes NoPopup tests but breaks msg_paint tests.
1976       if ( !PosChanged && (WinPos.flags & SWP_FRAMECHANGED) && VisBefore)
1977       {
1978          PWND Parent = Window->spwndParent;
1979          ERR("SWP_FRAMECHANGED no chg\n");
1980          if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
1981          {
1982             ERR("SWP_FRAMECHANGED Parent WS_CLIPCHILDREN\n");
1983             //IntInvalidateWindows( Window, VisBefore, /*RDW_ERASE |*/ RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1984          }
1985       }
1986 #endif
1987       /* We need to redraw what wasn't visible before */
1988       if (VisAfter != NULL)
1989       {
1990          PREGION DirtyRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
1991          if (DirtyRgn)
1992          {
1993              if (CopyRgn != NULL)
1994              {
1995                 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
1996              }
1997              else
1998              {
1999                 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
2000              }
2001 
2002              if (RgnType != ERROR && RgnType != NULLREGION)
2003              {
2004             /* old code
2005                 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2006                 IntInvalidateWindows( Window,
2007                                       DirtyRgn,
2008                    RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2009              }
2010              GreDeleteObject(DirtyRgn);
2011              */
2012 
2013                 PWND Parent = Window->spwndParent;
2014 
2015                 REGION_bOffsetRgn( DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
2016 
2017                 if ( (Window->style & WS_CHILD) && (Parent) && !(Parent->style & WS_CLIPCHILDREN))
2018                 {
2019                    IntInvalidateWindows( Parent, DirtyRgn, RDW_ERASE | RDW_INVALIDATE);
2020                    co_IntPaintWindows(Parent, RDW_NOCHILDREN, FALSE);
2021                 }
2022                 else
2023                 {
2024                    IntInvalidateWindows( Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2025                 }
2026              }
2027              REGION_Delete(DirtyRgn);
2028          }
2029       }
2030 
2031       if (CopyRgn != NULL)
2032       {
2033          REGION_Delete(CopyRgn);
2034       }
2035 
2036       /* Expose what was covered before but not covered anymore */
2037       if (VisBefore != NULL)
2038       {
2039          PREGION ExposedRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
2040          if (ExposedRgn)
2041          {
2042              RgnType = IntGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
2043              REGION_bOffsetRgn(ExposedRgn,
2044                                OldWindowRect.left - NewWindowRect.left,
2045                                OldWindowRect.top  - NewWindowRect.top);
2046 
2047              if (VisAfter != NULL)
2048                 RgnType = IntGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
2049 
2050              if (RgnType != ERROR && RgnType != NULLREGION)
2051              {
2052                 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
2053              }
2054              REGION_Delete(ExposedRgn);
2055          }
2056          REGION_Delete(VisBefore);
2057       }
2058 
2059       if (VisAfter != NULL)
2060       {
2061          REGION_Delete(VisAfter);
2062       }
2063    }
2064 
2065    if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2066    {
2067       if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2068       {
2069          co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
2070       }
2071       else
2072       {
2073          //ERR("SetWindowPos Set FG Window!\n");
2074          if ( pti->MessageQueue->spwndActive != Window ||
2075               pti->MessageQueue != gpqForeground )
2076          {
2077             //ERR("WPSWP : set active window\n");
2078             if (!(Window->state & WNDS_BEINGACTIVATED)) // Inside SAW?
2079             {
2080                co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow.
2081             }
2082          }
2083       }
2084    }
2085 
2086    if ( !PosChanged &&
2087          (WinPos.flags & SWP_FRAMECHANGED) &&
2088         !(WinPos.flags & SWP_DEFERERASE) &&    // Prevent sending WM_SYNCPAINT message.
2089          VisAfter )
2090    {
2091        PWND Parent = Window->spwndParent;
2092        if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN))
2093        {
2094            TRACE("SWP_FRAMECHANGED Parent WS_CLIPCHILDREN\n");
2095            UserSyncAndPaintWindows( Parent, RDW_CLIPCHILDREN);
2096        }
2097    }
2098 
2099    // Fix wine msg test_SetFocus, prevents sending WM_WINDOWPOSCHANGED.
2100    if ( VisBefore == NULL &&
2101         VisBeforeJustClient == NULL &&
2102        !(Window->ExStyle & WS_EX_TOPMOST) &&
2103         (WinPos.flags & SWP_AGG_STATUSFLAGS) == (SWP_AGG_NOPOSCHANGE & ~SWP_NOZORDER))
2104    {
2105       TRACE("No drawing, set no Z order and no redraw!\n");
2106       WinPos.flags |= SWP_NOZORDER|SWP_NOREDRAW;
2107    }
2108 
2109    if(!(flags & SWP_DEFERERASE))
2110    {
2111        /* erase parent when hiding or resizing child */
2112        if ((flags & SWP_HIDEWINDOW) ||
2113          (!(flags & SWP_SHOWWINDOW) &&
2114           (WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE))
2115        {
2116            PWND Parent = Window->spwndParent;
2117            if (!Parent || UserIsDesktopWindow(Parent)) Parent = Window;
2118            UserSyncAndPaintWindows( Parent, RDW_ERASENOW);
2119        }
2120 
2121        /* Give newly shown windows a chance to redraw */
2122        if(((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2123                 && !(flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW))
2124        {
2125            UserSyncAndPaintWindows( Window, RDW_ERASENOW);
2126        }
2127    }
2128 
2129    /* And last, send the WM_WINDOWPOSCHANGED message */
2130 
2131    TRACE("\tstatus hwnd %p flags = %04x\n",Window?Window->head.h:NULL,WinPos.flags & SWP_AGG_STATUSFLAGS);
2132 
2133    if (((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2134             && !((flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW)))
2135    {
2136       /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2137          and always contains final window position.
2138        */
2139       WinPos.x = NewWindowRect.left;
2140       WinPos.y = NewWindowRect.top;
2141       WinPos.cx = NewWindowRect.right - NewWindowRect.left;
2142       WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
2143       TRACE("WM_WINDOWPOSCHANGED hwnd %p Flags %04x\n",WinPos.hwnd,WinPos.flags);
2144       co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
2145    }
2146 
2147    if ( WinPos.flags & SWP_FRAMECHANGED  || WinPos.flags & SWP_STATECHANGED ||
2148       !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
2149    {
2150       PWND pWnd = ValidateHwndNoErr(WinPos.hwnd);
2151       if (pWnd)
2152          IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2153    }
2154 
2155    if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
2156    {
2157       /* Generate mouse move message */
2158       MSG msg;
2159       msg.message = WM_MOUSEMOVE;
2160       msg.wParam = UserGetMouseButtonsState();
2161       msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2162       msg.pt = gpsi->ptCursor;
2163       co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2164    }
2165 
2166    return TRUE;
2167 }
2168 
2169 LRESULT FASTCALL
2170 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
2171 {
2172    LRESULT Result;
2173 
2174    ASSERT_REFS_CO(Window);
2175 
2176    *ClientRect = *WindowRect;
2177    Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
2178 
2179    FixClientRect(ClientRect, WindowRect);
2180 
2181    return Result;
2182 }
2183 
2184 void FASTCALL
2185 co_WinPosSendSizeMove(PWND Wnd)
2186 {
2187     RECTL Rect;
2188     LPARAM lParam;
2189     WPARAM wParam = SIZE_RESTORED;
2190 
2191     IntGetClientRect(Wnd, &Rect);
2192     lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
2193 
2194     Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
2195 
2196     if (Wnd->style & WS_MAXIMIZE)
2197     {
2198         wParam = SIZE_MAXIMIZED;
2199     }
2200     else if (Wnd->style & WS_MINIMIZE)
2201     {
2202         wParam = SIZE_MINIMIZED;
2203         lParam = 0;
2204     }
2205 
2206     co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
2207 
2208     if (UserIsDesktopWindow(Wnd->spwndParent))
2209        lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
2210     else
2211        lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
2212 
2213     co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
2214 
2215     IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
2216 }
2217 
2218 UINT FASTCALL
2219 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
2220 {
2221    POINT Size;
2222    WINDOWPLACEMENT wpl;
2223    LONG old_style;
2224    UINT SwpFlags = 0;
2225 
2226    ASSERT_REFS_CO(Wnd);
2227 
2228    wpl.length = sizeof(wpl);
2229    IntGetWindowPlacement( Wnd, &wpl );
2230 
2231    if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
2232    {
2233       ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
2234       return SWP_NOSIZE | SWP_NOMOVE;
2235    }
2236       if (Wnd->style & WS_MINIMIZE)
2237       {
2238          switch (ShowFlag)
2239          {
2240          case SW_MINIMIZE:
2241          case SW_SHOWMINNOACTIVE:
2242          case SW_SHOWMINIMIZED:
2243          case SW_FORCEMINIMIZE:
2244              return SWP_NOSIZE | SWP_NOMOVE;
2245          }
2246          if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
2247          {
2248             return(SWP_NOSIZE | SWP_NOMOVE);
2249          }
2250          SwpFlags |= SWP_NOCOPYBITS;
2251       }
2252       switch (ShowFlag)
2253       {
2254          case SW_MINIMIZE:
2255          case SW_SHOWMINNOACTIVE:
2256          case SW_SHOWMINIMIZED:
2257          case SW_FORCEMINIMIZE:
2258             {
2259                //ERR("MinMaximize Minimize\n");
2260                if (Wnd->style & WS_MAXIMIZE)
2261                {
2262                   Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
2263                }
2264                else
2265                {
2266                   Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2267                }
2268 
2269                old_style = IntSetStyle( Wnd, WS_MINIMIZE, WS_MAXIMIZE );
2270 
2271                co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOINTERNALPAINT);
2272 
2273                if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION))
2274                   Wnd->InternalPos.flags &= ~WPF_MININIT;
2275 
2276                WinPosFindIconPos(Wnd, &wpl.ptMinPosition);
2277 
2278                if (!(old_style & WS_MINIMIZE))
2279                {
2280                   SwpFlags |= SWP_STATECHANGED;
2281                   IntShowOwnedPopups(Wnd, FALSE);
2282                }
2283 
2284                RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
2285                              wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
2286                              wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
2287                SwpFlags |= SWP_NOCOPYBITS;
2288                break;
2289             }
2290 
2291          case SW_MAXIMIZE:
2292             {
2293                //ERR("MinMaximize Maximize\n");
2294                if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE))
2295                {
2296                   SwpFlags = SWP_NOSIZE | SWP_NOMOVE;
2297                   break;
2298                }
2299                co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2300 
2301                /*ERR("Maximize: %d,%d %dx%d\n",
2302                       wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
2303                 */
2304                old_style = IntSetStyle( Wnd, WS_MAXIMIZE, WS_MINIMIZE );
2305                /*if (old_style & WS_MINIMIZE)
2306                {
2307                   IntShowOwnedPopups(Wnd, TRUE);
2308                }*/
2309 
2310                if (!(old_style & WS_MAXIMIZE)) SwpFlags |= SWP_STATECHANGED;
2311                RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2312                               //wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2313                               Size.x, Size.y);
2314                break;
2315             }
2316 
2317          case SW_SHOWNOACTIVATE:
2318             Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2319             /* fall through */
2320          case SW_SHOWNORMAL:
2321          case SW_RESTORE:
2322          case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
2323             {
2324                //ERR("MinMaximize Restore\n");
2325                old_style = IntSetStyle( Wnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
2326                if (old_style & WS_MINIMIZE)
2327                {
2328                   IntShowOwnedPopups(Wnd, TRUE);
2329 
2330                   if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED)
2331                   {
2332                      co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
2333                      IntSetStyle( Wnd, WS_MAXIMIZE, 0 );
2334                      SwpFlags |= SWP_STATECHANGED;
2335                      RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
2336                                     wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
2337                      break;
2338                   }
2339                   else
2340                   {
2341                      *NewPos = wpl.rcNormalPosition;
2342                      NewPos->right -= NewPos->left;
2343                      NewPos->bottom -= NewPos->top;
2344                      break;
2345                   }
2346                }
2347                else
2348                {
2349                   if (!(old_style & WS_MAXIMIZE))
2350                   {
2351                      break;
2352                   }
2353                   SwpFlags |= SWP_STATECHANGED;
2354                   Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
2355                   *NewPos = wpl.rcNormalPosition;
2356                   NewPos->right -= NewPos->left;
2357                   NewPos->bottom -= NewPos->top;
2358                   break;
2359                }
2360             }
2361       }
2362    return SwpFlags;
2363 }
2364 
2365 /*
2366    ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits!
2367  */
2368 BOOLEAN FASTCALL
2369 co_WinPosShowWindow(PWND Wnd, INT Cmd)
2370 {
2371    BOOLEAN WasVisible;
2372    UINT Swp = 0, EventMsg = 0;
2373    RECTL NewPos = {0, 0, 0, 0};
2374    BOOLEAN ShowFlag;
2375    LONG style;
2376    PWND Parent;
2377    PTHREADINFO pti;
2378    //HRGN VisibleRgn;
2379    BOOL ShowOwned = FALSE;
2380    BOOL FirstTime = FALSE;
2381    ASSERT_REFS_CO(Wnd);
2382    //KeRosDumpStackFrames(NULL, 20);
2383    pti = PsGetCurrentThreadWin32Thread();
2384    WasVisible = (Wnd->style & WS_VISIBLE) != 0;
2385    style = Wnd->style;
2386 
2387    TRACE("co_WinPosShowWindow START hwnd %p Cmd %d usicmd %u\n",
2388          Wnd->head.h, Cmd, pti->ppi->usi.wShowWindow);
2389 
2390    if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2391    {
2392       if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2393       {
2394          if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
2395          {
2396             if (Wnd->spwndOwner == NULL)
2397             {
2398                if ( Cmd == SW_SHOWNORMAL || Cmd == SW_SHOW)
2399                {
2400                     Cmd = SW_SHOWDEFAULT;
2401                }
2402                FirstTime = TRUE;
2403                TRACE("co_WPSW FT 1\n");
2404             }
2405          }
2406       }
2407    }
2408 
2409    if ( Cmd == SW_SHOWDEFAULT )
2410    {
2411       if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW )
2412       {
2413          Cmd = pti->ppi->usi.wShowWindow;
2414          FirstTime = TRUE;
2415          TRACE("co_WPSW FT 2\n");
2416       }
2417    }
2418 
2419    if (FirstTime)
2420    {
2421       pti->ppi->usi.dwFlags &= ~(STARTF_USEPOSITION|STARTF_USESIZE|STARTF_USESHOWWINDOW);
2422    }
2423 
2424    switch (Cmd)
2425    {
2426       case SW_HIDE:
2427          {
2428             if (!WasVisible)
2429             {
2430                //ERR("co_WinPosShowWindow Exit Bad\n");
2431                return FALSE;
2432             }
2433             Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2434             if (Wnd != pti->MessageQueue->spwndActive)
2435                Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2436             break;
2437          }
2438 
2439       case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
2440       case SW_SHOWMINNOACTIVE:
2441          Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2442          /* Fall through. */
2443       case SW_SHOWMINIMIZED:
2444          Swp |= SWP_SHOWWINDOW;
2445          /* Fall through. */
2446       case SW_MINIMIZE:
2447          {
2448             Swp |= SWP_NOACTIVATE;
2449             if (!(style & WS_MINIMIZE))
2450             {
2451                IntShowOwnedPopups(Wnd, FALSE );
2452                // Fix wine Win test_SetFocus todo #1 & #2,
2453                if (Cmd == SW_SHOWMINIMIZED)
2454                {
2455                   //ERR("co_WinPosShowWindow Set focus 1\n");
2456                   if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2457                      co_UserSetFocus(Wnd->spwndParent);
2458                   else
2459                      co_UserSetFocus(0);
2460                }
2461 
2462                Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2463 
2464                EventMsg = EVENT_SYSTEM_MINIMIZESTART;
2465             }
2466             else
2467             {
2468                if (WasVisible)
2469                {
2470                   //ERR("co_WinPosShowWindow Exit Good\n");
2471                   return TRUE;
2472                }
2473                Swp |= SWP_NOSIZE | SWP_NOMOVE;
2474             }
2475             break;
2476          }
2477 
2478       case SW_SHOWMAXIMIZED:
2479          {
2480             Swp |= SWP_SHOWWINDOW;
2481             if (!(style & WS_MAXIMIZE))
2482             {
2483                ShowOwned = TRUE;
2484 
2485                Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos);
2486 
2487                EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2488             }
2489             else
2490             {
2491                if (WasVisible)
2492                {
2493                   //ERR("co_WinPosShowWindow Exit Good 1\n");
2494                   return TRUE;
2495                }
2496                Swp |= SWP_NOSIZE | SWP_NOMOVE;
2497             }
2498             break;
2499          }
2500 
2501       case SW_SHOWNA:
2502          Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2503          if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER;
2504          break;
2505       case SW_SHOW:
2506          if (WasVisible) return(TRUE); // Nothing to do!
2507          Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
2508          /* Don't activate the topmost window. */
2509          if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2510          break;
2511 
2512       case SW_SHOWNOACTIVATE:
2513          Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2514          /* Fall through. */
2515       case SW_SHOWNORMAL:
2516       case SW_SHOWDEFAULT:
2517       case SW_RESTORE:
2518          if (!WasVisible) Swp |= SWP_SHOWWINDOW;
2519          if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2520          {
2521             Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos);
2522             if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND;
2523          }
2524          else
2525          {
2526             if (WasVisible)
2527             {
2528                //ERR("co_WinPosShowWindow Exit Good 3\n");
2529                return TRUE;
2530             }
2531             Swp |= SWP_NOSIZE | SWP_NOMOVE;
2532          }
2533          if ( style & WS_CHILD &&
2534              !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2535              !(Swp & SWP_STATECHANGED))
2536             Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2537          break;
2538 
2539       default:
2540          //ERR("co_WinPosShowWindow Exit Good 4\n");
2541          return WasVisible;
2542    }
2543 
2544    ShowFlag = (Cmd != SW_HIDE);
2545 
2546    if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED))
2547    {
2548       co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
2549 #if 0 // Fix wine msg test_SetParent:WmSetParentSeq_1:2
2550       if (!(Wnd->state2 & WNDS2_WIN31COMPAT)) // <------------- XP sets this bit!
2551          co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
2552 #endif
2553       if (!VerifyWnd(Wnd)) return WasVisible;
2554    }
2555 
2556    /* We can't activate a child window */
2557    if ((Wnd->style & WS_CHILD) &&
2558        !(Wnd->ExStyle & WS_EX_MDICHILD) &&
2559        Cmd != SW_SHOWNA)
2560    {
2561       //ERR("SWP Child No active and ZOrder\n");
2562       Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2563    }
2564 
2565 #if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works.
2566       // Breaks startup and shutdown active window...
2567    if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
2568         Wnd->pcls->style & CS_SAVEBITS &&
2569         ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
2570    {
2571       ERR("WinPosShowWindow Set active\n");
2572       //UserSetActiveWindow(Wnd);
2573       co_IntSetForegroundWindow(Wnd); // HACK
2574       Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
2575    }
2576 #endif
2577 
2578    if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED)
2579    {
2580        TRACE("Child is Vis %s or State changed %s. ShowFlag %s Swp %04x\n",
2581              (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"),
2582              (ShowFlag ? "TRUE" : "FALSE"),LOWORD(Swp));
2583    co_WinPosSetWindowPos( Wnd,
2584                           0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
2585                           NewPos.left,
2586                           NewPos.top,
2587                           NewPos.right, // NewPos.right - NewPos.left, when minimized and restore, the window becomes smaller.
2588                           NewPos.bottom,// NewPos.bottom - NewPos.top,
2589                           LOWORD(Swp));
2590    }
2591    else
2592    {
2593       TRACE("Parent Vis?\n");
2594       /* if parent is not visible simply toggle WS_VISIBLE and return */
2595       if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 );
2596       else IntSetStyle( Wnd, 0, WS_VISIBLE );
2597    }
2598 
2599    if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
2600 
2601    if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE );
2602 
2603    if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
2604    {
2605       if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue()  )
2606       {
2607           if (UserIsDesktopWindow(Wnd->spwndParent))
2608           {
2609               if (!ActivateOtherWindowMin(Wnd))
2610               {
2611                 co_WinPosActivateOtherWindow(Wnd);
2612               }
2613           }
2614           else
2615           {
2616               co_WinPosActivateOtherWindow(Wnd);
2617           }
2618       }
2619 
2620       /* Revert focus to parent */
2621       if (Wnd == pti->MessageQueue->spwndFocus)
2622       {
2623          Parent = Wnd->spwndParent;
2624          if (UserIsDesktopWindow(Wnd->spwndParent))
2625              Parent = 0;
2626          co_UserSetFocus(Parent);
2627       }
2628       // Hide, just return.
2629       if (Cmd == SW_HIDE) return WasVisible;
2630    }
2631 
2632    /* FIXME: Check for window destruction. */
2633 
2634    if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
2635        !(Wnd->state2 & WNDS2_INDESTROY))
2636    {
2637         co_WinPosSendSizeMove(Wnd);
2638    }
2639 
2640    /* if previous state was minimized Windows sets focus to the window */
2641    if (style & WS_MINIMIZE)
2642    {
2643       co_UserSetFocus(Wnd);
2644       // Fix wine Win test_SetFocus todo #3,
2645       if (!(style & WS_CHILD)) co_IntSendMessage(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0);
2646    }
2647    //ERR("co_WinPosShowWindow EXIT\n");
2648    return WasVisible;
2649 }
2650 
2651 static PWND
2652 co_WinPosSearchChildren(
2653    IN PWND ScopeWin,
2654    IN POINT *Point,
2655    IN OUT USHORT *HitTest,
2656    IN BOOL Ignore
2657    )
2658 {
2659     HWND *List, *phWnd;
2660     PWND pwndChild = NULL;
2661 
2662     /* not visible */
2663     if (!(ScopeWin->style & WS_VISIBLE))
2664     {
2665         return NULL;
2666     }
2667 
2668     /* not in window or in window region */
2669     if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2670     {
2671         return NULL;
2672     }
2673 
2674     /* transparent */
2675     if ((ScopeWin->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT))
2676     {
2677         return NULL;
2678     }
2679 
2680     if (!Ignore && (ScopeWin->style & WS_DISABLED))
2681     {   /* disabled child */
2682         if ((ScopeWin->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return NULL;
2683         /* process the hit error */
2684         *HitTest = HTERROR;
2685         return ScopeWin;
2686     }
2687 
2688     /* not minimized and check if point is inside the window */
2689     if (!(ScopeWin->style & WS_MINIMIZE) &&
2690          RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2691     {
2692         UserReferenceObject(ScopeWin);
2693 
2694         List = IntWinListChildren(ScopeWin);
2695         if (List)
2696         {
2697             for (phWnd = List; *phWnd; ++phWnd)
2698             {
2699                 if (!(pwndChild = ValidateHwndNoErr(*phWnd)))
2700                 {
2701                     continue;
2702                 }
2703 
2704                 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore);
2705 
2706                 if (pwndChild != NULL)
2707                 {
2708                     /* We found a window. Don't send any more WM_NCHITTEST messages */
2709                     ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2710                     UserDereferenceObject(ScopeWin);
2711                     return pwndChild;
2712                 }
2713             }
2714             ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2715         }
2716         UserDereferenceObject(ScopeWin);
2717     }
2718 
2719     if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread())
2720     {
2721        *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0, MAKELONG(Point->x, Point->y));
2722 
2723        if ((*HitTest) == (USHORT)HTTRANSPARENT)
2724        {
2725            return NULL;
2726        }
2727     }
2728     else
2729     {
2730        if (*HitTest == HTNOWHERE && pwndChild == NULL) *HitTest = HTCLIENT;
2731     }
2732 
2733     return ScopeWin;
2734 }
2735 
2736 PWND APIENTRY
2737 co_WinPosWindowFromPoint(
2738    IN PWND ScopeWin,
2739    IN POINT *WinPoint,
2740    IN OUT USHORT* HitTest,
2741    IN BOOL Ignore)
2742 {
2743    PWND Window;
2744    POINT Point = *WinPoint;
2745    USER_REFERENCE_ENTRY Ref;
2746 
2747    if( ScopeWin == NULL )
2748    {
2749        ScopeWin = UserGetDesktopWindow();
2750        if(ScopeWin == NULL)
2751            return NULL;
2752    }
2753 
2754    *HitTest = HTNOWHERE;
2755 
2756    ASSERT_REFS_CO(ScopeWin);
2757    UserRefObjectCo(ScopeWin, &Ref);
2758 
2759    Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore);
2760 
2761    UserDerefObjectCo(ScopeWin);
2762    if (Window)
2763        ASSERT_REFS_CO(Window);
2764    ASSERT_REFS_CO(ScopeWin);
2765 
2766    return Window;
2767 }
2768 
2769 PWND FASTCALL
2770 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2771 {
2772    POINTL Pt;
2773    HWND *List, *phWnd;
2774    PWND pwndHit = NULL;
2775 
2776    Pt.x = x;
2777    Pt.y = y;
2778 
2779    if (!UserIsDesktopWindow(Parent))
2780    {
2781       Pt.x += Parent->rcClient.left;
2782       Pt.y += Parent->rcClient.top;
2783    }
2784 
2785    if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2786 
2787    if ((List = IntWinListChildren(Parent)))
2788    {
2789       for (phWnd = List; *phWnd; phWnd++)
2790       {
2791          PWND Child;
2792          if ((Child = ValidateHwndNoErr(*phWnd)))
2793          {
2794             if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
2795             {
2796                if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
2797                    (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
2798                {
2799                   ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2800                   return Child;
2801                }
2802                pwndHit = Child;
2803             }
2804          }
2805       }
2806       ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2807    }
2808    return pwndHit ? pwndHit : Parent;
2809 }
2810 
2811 PWND APIENTRY
2812 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
2813 {
2814    POINTL Pt;
2815    HWND *List, *phWnd;
2816    PWND pwndHit = NULL;
2817 
2818    Pt.x = x;
2819    Pt.y = y;
2820 
2821    if (!UserIsDesktopWindow(Parent))
2822    {
2823       if (Parent->ExStyle & WS_EX_LAYOUTRTL)
2824          Pt.x = Parent->rcClient.right - Pt.x;
2825       else
2826          Pt.x += Parent->rcClient.left;
2827       Pt.y += Parent->rcClient.top;
2828    }
2829 
2830    if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2831 
2832    if ((List = IntWinListChildren(Parent)))
2833    {
2834       for (phWnd = List; *phWnd; phWnd++)
2835       {
2836          PWND Child;
2837          if ((Child = ValidateHwndNoErr(*phWnd)))
2838          {
2839             if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
2840             {
2841                if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
2842                if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
2843             }
2844 
2845             if (uiFlags & CWP_SKIPTRANSPARENT)
2846             {
2847                if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
2848             }
2849 
2850             if (IntPtInWindow(Child, Pt.x, Pt.y))
2851             {
2852                pwndHit = Child;
2853                break;
2854             }
2855          }
2856       }
2857       ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2858    }
2859    return pwndHit ? pwndHit : Parent;
2860 }
2861 
2862 HDWP
2863 FASTCALL
2864 IntDeferWindowPos( HDWP hdwp,
2865                    HWND hwnd,
2866                    HWND hwndAfter,
2867                    INT x,
2868                    INT y,
2869                    INT cx,
2870                    INT cy,
2871                    UINT flags )
2872 {
2873     PSMWP pDWP;
2874     int i;
2875     HDWP retvalue = hdwp;
2876 
2877     TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2878           hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2879 
2880     if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
2881                   SWP_NOZORDER | SWP_NOREDRAW |
2882                   SWP_NOACTIVATE | SWP_NOCOPYBITS |
2883                   SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
2884                   SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2885     {
2886        EngSetLastError(ERROR_INVALID_PARAMETER);
2887        return NULL;
2888     }
2889 
2890     if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2891     {
2892        EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2893        return NULL;
2894     }
2895 
2896     for (i = 0; i < pDWP->ccvr; i++)
2897     {
2898         if (pDWP->acvr[i].pos.hwnd == hwnd)
2899         {
2900               /* Merge with the other changes */
2901             if (!(flags & SWP_NOZORDER))
2902             {
2903                 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
2904             }
2905             if (!(flags & SWP_NOMOVE))
2906             {
2907                 pDWP->acvr[i].pos.x = x;
2908                 pDWP->acvr[i].pos.y = y;
2909             }
2910             if (!(flags & SWP_NOSIZE))
2911             {
2912                 pDWP->acvr[i].pos.cx = cx;
2913                 pDWP->acvr[i].pos.cy = cy;
2914             }
2915             pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2916                                                SWP_NOZORDER | SWP_NOREDRAW |
2917                                                SWP_NOACTIVATE | SWP_NOCOPYBITS|
2918                                                SWP_NOOWNERZORDER);
2919             pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2920                                               SWP_FRAMECHANGED);
2921             goto END;
2922         }
2923     }
2924     if (pDWP->ccvr >= pDWP->ccvrAlloc)
2925     {
2926         PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
2927         if (!newpos)
2928         {
2929             retvalue = NULL;
2930             goto END;
2931         }
2932         RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
2933         RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
2934         ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2935         pDWP->ccvrAlloc *= 2;
2936         pDWP->acvr = newpos;
2937     }
2938     pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
2939     pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
2940     pDWP->acvr[pDWP->ccvr].pos.x = x;
2941     pDWP->acvr[pDWP->ccvr].pos.y = y;
2942     pDWP->acvr[pDWP->ccvr].pos.cx = cx;
2943     pDWP->acvr[pDWP->ccvr].pos.cy = cy;
2944     pDWP->acvr[pDWP->ccvr].pos.flags = flags;
2945     pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
2946     pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
2947     pDWP->ccvr++;
2948 END:
2949     return retvalue;
2950 }
2951 
2952 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
2953 {
2954     PSMWP pDWP;
2955     PCVR winpos;
2956     BOOL res = TRUE;
2957     int i;
2958 
2959     TRACE("%p\n", hdwp);
2960 
2961     if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS)))
2962     {
2963        EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2964        return FALSE;
2965     }
2966 
2967     for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
2968     {
2969         PWND pwnd;
2970         USER_REFERENCE_ENTRY Ref;
2971 
2972         TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2973                winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
2974                winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
2975 
2976         pwnd = ValidateHwndNoErr(winpos->pos.hwnd);
2977         if (!pwnd)
2978            continue;
2979 
2980         UserRefObjectCo(pwnd, &Ref);
2981 
2982         if ( sAsync )
2983         {
2984            LRESULT lRes;
2985            PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
2986            if ( ppos )
2987            {
2988               *ppos = winpos->pos;
2989               /* Yes it's a pointer inside Win32k! */
2990               lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
2991               /* We handle this the same way as Event Hooks and Hooks. */
2992               if ( !lRes )
2993               {
2994                  ExFreePoolWithTag(ppos, USERTAG_SWP);
2995               }
2996            }
2997         }
2998         else
2999            res = co_WinPosSetWindowPos( pwnd,
3000                                         winpos->pos.hwndInsertAfter,
3001                                         winpos->pos.x,
3002                                         winpos->pos.y,
3003                                         winpos->pos.cx,
3004                                         winpos->pos.cy,
3005                                         winpos->pos.flags);
3006 
3007         // Hack to pass tests.... Must have some work to do so clear the error.
3008         if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER )
3009            EngSetLastError(ERROR_SUCCESS);
3010 
3011         UserDerefObjectCo(pwnd);
3012     }
3013     ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
3014     UserDereferenceObject(pDWP);
3015     UserDeleteObject(hdwp, TYPE_SETWINDOWPOS);
3016     return res;
3017 }
3018 
3019 /*
3020  * @implemented
3021  */
3022 HWND APIENTRY
3023 NtUserChildWindowFromPointEx(HWND hwndParent,
3024                              LONG x,
3025                              LONG y,
3026                              UINT uiFlags)
3027 {
3028    PWND pwndParent;
3029    TRACE("Enter NtUserChildWindowFromPointEx\n");
3030    UserEnterExclusive();
3031    if ((pwndParent = UserGetWindowObject(hwndParent)))
3032    {
3033       pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
3034    }
3035    UserLeave();
3036    TRACE("Leave NtUserChildWindowFromPointEx\n");
3037    return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3038 }
3039 
3040 /*
3041  * @implemented
3042  */
3043 BOOL APIENTRY
3044 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
3045                           DWORD Unknown1)
3046 {
3047    BOOL Ret;
3048    TRACE("Enter NtUserEndDeferWindowPosEx\n");
3049    UserEnterExclusive();
3050    Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
3051    TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
3052    UserLeave();
3053    return Ret;
3054 }
3055 
3056 /*
3057  * @implemented
3058  */
3059 HDWP APIENTRY
3060 NtUserDeferWindowPos(HDWP WinPosInfo,
3061                      HWND Wnd,
3062                      HWND WndInsertAfter,
3063                      int x,
3064                      int y,
3065                      int cx,
3066                      int cy,
3067                      UINT Flags)
3068 {
3069    PWND pWnd, pWndIA;
3070    HDWP Ret = NULL;
3071    UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
3072                 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
3073                 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
3074 
3075    TRACE("Enter NtUserDeferWindowPos\n");
3076    UserEnterExclusive();
3077 
3078    if ( Flags & Tmp )
3079    {
3080       EngSetLastError(ERROR_INVALID_FLAGS);
3081       goto Exit;
3082    }
3083 
3084    pWnd = UserGetWindowObject(Wnd);
3085    if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3086    {
3087       goto Exit;
3088    }
3089 
3090    if ( WndInsertAfter &&
3091         WndInsertAfter != HWND_BOTTOM &&
3092         WndInsertAfter != HWND_TOPMOST &&
3093         WndInsertAfter != HWND_NOTOPMOST )
3094    {
3095       pWndIA = UserGetWindowObject(WndInsertAfter);
3096       if (!pWndIA || UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3097       {
3098          goto Exit;
3099       }
3100    }
3101 
3102    Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
3103 
3104 Exit:
3105    TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret);
3106    UserLeave();
3107    return Ret;
3108 }
3109 
3110 /*
3111  * @implemented
3112  */
3113 DWORD APIENTRY
3114 NtUserGetInternalWindowPos( HWND hWnd,
3115                             LPRECT rectWnd,
3116                             LPPOINT ptIcon)
3117 {
3118    PWND Window;
3119    DWORD Ret = 0;
3120    BOOL Hit = FALSE;
3121    WINDOWPLACEMENT wndpl;
3122 
3123    UserEnterShared();
3124 
3125    if (!(Window = UserGetWindowObject(hWnd)))
3126    {
3127       Hit = FALSE;
3128       goto Exit;
3129    }
3130 
3131    _SEH2_TRY
3132    {
3133        if(rectWnd)
3134        {
3135           ProbeForWrite(rectWnd,
3136                         sizeof(RECT),
3137                         1);
3138        }
3139        if(ptIcon)
3140        {
3141           ProbeForWrite(ptIcon,
3142                         sizeof(POINT),
3143                         1);
3144        }
3145 
3146    }
3147    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3148    {
3149        SetLastNtError(_SEH2_GetExceptionCode());
3150        Hit = TRUE;
3151    }
3152    _SEH2_END;
3153 
3154    wndpl.length = sizeof(WINDOWPLACEMENT);
3155 
3156    if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3157    {
3158       _SEH2_TRY
3159       {
3160           if (rectWnd)
3161           {
3162              RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3163           }
3164           if (ptIcon)
3165           {
3166              RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3167           }
3168 
3169       }
3170       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3171       {
3172           SetLastNtError(_SEH2_GetExceptionCode());
3173           Hit = TRUE;
3174       }
3175       _SEH2_END;
3176 
3177       if (!Hit) Ret = wndpl.showCmd;
3178    }
3179 Exit:
3180    UserLeave();
3181    return Ret;
3182 }
3183 
3184 /*
3185  * @implemented
3186  */
3187 BOOL APIENTRY
3188 NtUserGetWindowPlacement(HWND hWnd,
3189                          WINDOWPLACEMENT *lpwndpl)
3190 {
3191    PWND Wnd;
3192    WINDOWPLACEMENT Safepl;
3193    NTSTATUS Status;
3194    DECLARE_RETURN(BOOL);
3195 
3196    TRACE("Enter NtUserGetWindowPlacement\n");
3197    UserEnterShared();
3198 
3199    if (!(Wnd = UserGetWindowObject(hWnd)))
3200    {
3201       RETURN( FALSE);
3202    }
3203 
3204    Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3205    if (!NT_SUCCESS(Status))
3206    {
3207       SetLastNtError(Status);
3208       RETURN( FALSE);
3209    }
3210 
3211    Safepl.length = sizeof(WINDOWPLACEMENT);
3212 
3213    IntGetWindowPlacement(Wnd, &Safepl);
3214 
3215    Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
3216    if (!NT_SUCCESS(Status))
3217    {
3218       SetLastNtError(Status);
3219       RETURN( FALSE);
3220    }
3221 
3222    RETURN( TRUE);
3223 
3224 CLEANUP:
3225    TRACE("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
3226    UserLeave();
3227    END_CLEANUP;
3228 }
3229 
3230 DWORD
3231 APIENTRY
3232 NtUserMinMaximize(
3233     HWND hWnd,
3234     UINT cmd, // Wine SW_ commands
3235     BOOL Hide)
3236 {
3237   PWND pWnd;
3238 
3239   TRACE("Enter NtUserMinMaximize\n");
3240   UserEnterExclusive();
3241 
3242   pWnd = UserGetWindowObject(hWnd);
3243   if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd))
3244   {
3245      goto Exit;
3246   }
3247 
3248   if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
3249   {
3250      EngSetLastError(ERROR_INVALID_PARAMETER);
3251      goto Exit;
3252   }
3253 
3254   cmd |= Hide ? SW_HIDE : 0;
3255 
3256   co_WinPosShowWindow(pWnd, cmd);
3257 
3258 Exit:
3259   TRACE("Leave NtUserMinMaximize\n");
3260   UserLeave();
3261   return 0; // Always NULL?
3262 }
3263 
3264 /*
3265  * @implemented
3266  */
3267 BOOL APIENTRY
3268 NtUserMoveWindow(
3269    HWND hWnd,
3270    int X,
3271    int Y,
3272    int nWidth,
3273    int nHeight,
3274    BOOL bRepaint)
3275 {
3276    return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
3277                              (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
3278                               SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
3279 }
3280 
3281 /*
3282  * @implemented
3283  */
3284 HWND APIENTRY
3285 NtUserRealChildWindowFromPoint(HWND Parent,
3286                                LONG x,
3287                                LONG y)
3288 {
3289    PWND pwndParent;
3290    TRACE("Enter NtUserRealChildWindowFromPoint\n");
3291    UserEnterShared();
3292    if ((pwndParent = UserGetWindowObject(Parent)))
3293    {
3294       pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y);
3295    }
3296    UserLeave();
3297    TRACE("Leave NtUserRealChildWindowFromPoint\n");
3298    return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
3299 }
3300 
3301 /*
3302  * @implemented
3303  */
3304 BOOL APIENTRY
3305 NtUserSetWindowPos(
3306    HWND hWnd,
3307    HWND hWndInsertAfter,
3308    int X,
3309    int Y,
3310    int cx,
3311    int cy,
3312    UINT uFlags)
3313 {
3314    DECLARE_RETURN(BOOL);
3315    PWND Window, pWndIA;
3316    BOOL ret;
3317    USER_REFERENCE_ENTRY Ref;
3318 
3319    TRACE("Enter NtUserSetWindowPos\n");
3320    UserEnterExclusive();
3321 
3322    if (!(Window = UserGetWindowObject(hWnd)) ||
3323         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3324    {
3325       ERR("NtUserSetWindowPos bad window handle!\n");
3326       RETURN(FALSE);
3327    }
3328 
3329    if ( hWndInsertAfter &&
3330         hWndInsertAfter != HWND_BOTTOM &&
3331         hWndInsertAfter != HWND_TOPMOST &&
3332         hWndInsertAfter != HWND_NOTOPMOST )
3333    {
3334       if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) ||
3335             UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA))
3336       {
3337          ERR("NtUserSetWindowPos bad insert window handle!\n");
3338          RETURN(FALSE);
3339       }
3340    }
3341 
3342    /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3343    if (!(uFlags & SWP_NOMOVE))
3344    {
3345       if (X < -32768) X = -32768;
3346       else if (X > 32767) X = 32767;
3347       if (Y < -32768) Y = -32768;
3348       else if (Y > 32767) Y = 32767;
3349    }
3350    if (!(uFlags & SWP_NOSIZE))
3351    {
3352       if (cx < 0) cx = 0;
3353       else if (cx > 32767) cx = 32767;
3354       if (cy < 0) cy = 0;
3355       else if (cy > 32767) cy = 32767;
3356    }
3357 
3358    UserRefObjectCo(Window, &Ref);
3359    ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
3360    UserDerefObjectCo(Window);
3361 
3362    RETURN(ret);
3363 
3364 CLEANUP:
3365    TRACE("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
3366    UserLeave();
3367    END_CLEANUP;
3368 }
3369 
3370 /*
3371  * @implemented
3372  */
3373 INT APIENTRY
3374 NtUserSetWindowRgn(
3375    HWND hWnd,
3376    HRGN hRgn,
3377    BOOL bRedraw)
3378 {
3379    HRGN hrgnCopy = NULL;
3380    PWND Window;
3381    INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
3382    BOOLEAN Ret = FALSE;
3383    DECLARE_RETURN(INT);
3384 
3385    TRACE("Enter NtUserSetWindowRgn\n");
3386    UserEnterExclusive();
3387 
3388    if (!(Window = UserGetWindowObject(hWnd)) ||
3389         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3390    {
3391       RETURN( 0);
3392    }
3393 
3394    if (hRgn) // The region will be deleted in user32.
3395    {
3396       if (GreIsHandleValid(hRgn))
3397       {
3398          hrgnCopy = NtGdiCreateRectRgn(0, 0, 0, 0);
3399       /* The coordinates of a window's window region are relative to the
3400          upper-left corner of the window, not the client area of the window. */
3401          NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY);
3402       }
3403       else
3404          RETURN( 0);
3405    }
3406 
3407    //// HACK 1 : Work around the lack of supporting DeferWindowPos.
3408    if (hrgnCopy)
3409    {
3410        Window->hrgnNewFrame = hrgnCopy; // Should be PSMWP->acvr->hrgnClip
3411    }
3412    else
3413    {
3414        Window->hrgnNewFrame = HRGN_WINDOW;
3415    }
3416    //// HACK 2
3417    Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) );
3418 
3419    RETURN( (INT)Ret);
3420 
3421 CLEANUP:
3422    TRACE("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
3423    UserLeave();
3424    END_CLEANUP;
3425 }
3426 
3427 /*
3428  * @implemented
3429  */
3430 DWORD APIENTRY
3431 NtUserSetInternalWindowPos(
3432    HWND    hwnd,
3433    UINT    showCmd,
3434    LPRECT  lprect,
3435    LPPOINT lppt)
3436 {
3437    WINDOWPLACEMENT wndpl;
3438    UINT flags;
3439    PWND Wnd;
3440    RECT rect;
3441    POINT pt = {0};
3442    DECLARE_RETURN(BOOL);
3443    USER_REFERENCE_ENTRY Ref;
3444 
3445    TRACE("Enter NtUserSetWindowPlacement\n");
3446    UserEnterExclusive();
3447 
3448    if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME:
3449         UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd))
3450    {
3451       RETURN( FALSE);
3452    }
3453 
3454    _SEH2_TRY
3455    {
3456       if (lppt)
3457       {
3458          ProbeForRead(lppt, sizeof(POINT), 1);
3459          RtlCopyMemory(&pt, lppt, sizeof(POINT));
3460       }
3461       if (lprect)
3462       {
3463          ProbeForRead(lprect, sizeof(RECT), 1);
3464          RtlCopyMemory(&rect, lprect, sizeof(RECT));
3465       }
3466    }
3467    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3468    {
3469       SetLastNtError(_SEH2_GetExceptionCode());
3470       _SEH2_YIELD(RETURN( FALSE));
3471    }
3472    _SEH2_END
3473 
3474    wndpl.length  = sizeof(wndpl);
3475    wndpl.showCmd = showCmd;
3476    wndpl.flags = flags = 0;
3477 
3478    if ( lppt )
3479    {
3480       flags |= PLACE_MIN;
3481       wndpl.flags |= WPF_SETMINPOSITION;
3482       wndpl.ptMinPosition = pt;
3483    }
3484    if ( lprect )
3485    {
3486       flags |= PLACE_RECT;
3487       wndpl.rcNormalPosition = rect;
3488    }
3489 
3490    UserRefObjectCo(Wnd, &Ref);
3491    IntSetWindowPlacement(Wnd, &wndpl, flags);
3492    UserDerefObjectCo(Wnd);
3493    RETURN(TRUE);
3494 
3495 CLEANUP:
3496    TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3497    UserLeave();
3498    END_CLEANUP;
3499 }
3500 
3501 /*
3502  * @implemented
3503  */
3504 BOOL APIENTRY
3505 NtUserSetWindowPlacement(HWND hWnd,
3506                          WINDOWPLACEMENT *lpwndpl)
3507 {
3508    PWND Wnd;
3509    WINDOWPLACEMENT Safepl;
3510    UINT Flags;
3511    DECLARE_RETURN(BOOL);
3512    USER_REFERENCE_ENTRY Ref;
3513 
3514    TRACE("Enter NtUserSetWindowPlacement\n");
3515    UserEnterExclusive();
3516 
3517    if (!(Wnd = UserGetWindowObject(hWnd)) ||
3518         UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd))
3519    {
3520       RETURN( FALSE);
3521    }
3522 
3523    _SEH2_TRY
3524    {
3525       ProbeForRead(lpwndpl, sizeof(WINDOWPLACEMENT), 1);
3526       RtlCopyMemory(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3527    }
3528    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3529    {
3530       SetLastNtError(_SEH2_GetExceptionCode());
3531       _SEH2_YIELD(RETURN( FALSE));
3532    }
3533    _SEH2_END
3534 
3535    if(Safepl.length != sizeof(WINDOWPLACEMENT))
3536    {
3537       RETURN( FALSE);
3538    }
3539 
3540    Flags = PLACE_MAX | PLACE_RECT;
3541    if (Safepl.flags & WPF_SETMINPOSITION) Flags |= PLACE_MIN;
3542    UserRefObjectCo(Wnd, &Ref);
3543    IntSetWindowPlacement(Wnd, &Safepl, Flags);
3544    UserDerefObjectCo(Wnd);
3545    RETURN(TRUE);
3546 
3547 CLEANUP:
3548    TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
3549    UserLeave();
3550    END_CLEANUP;
3551 }
3552 
3553 /*
3554  * @implemented
3555  */
3556 BOOL APIENTRY
3557 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
3558 {
3559    PWND Window;
3560    BOOL ret;
3561    DECLARE_RETURN(BOOL);
3562    USER_REFERENCE_ENTRY Ref;
3563 
3564    TRACE("Enter NtUserShowWindowAsync\n");
3565    UserEnterExclusive();
3566 
3567    if (!(Window = UserGetWindowObject(hWnd)) ||
3568         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3569    {
3570       RETURN(FALSE);
3571    }
3572 
3573    if ( nCmdShow > SW_MAX )
3574    {
3575       EngSetLastError(ERROR_INVALID_PARAMETER);
3576       RETURN(FALSE);
3577    }
3578 
3579    UserRefObjectCo(Window, &Ref);
3580    ret = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 );
3581    UserDerefObjectCo(Window);
3582    if (-1 == (int) ret || !ret) ret = FALSE;
3583 
3584    RETURN(ret);
3585 
3586 CLEANUP:
3587    TRACE("Leave NtUserShowWindowAsync, ret=%i\n",_ret_);
3588    UserLeave();
3589    END_CLEANUP;
3590 }
3591 
3592 /*
3593  * @implemented
3594  */
3595 BOOL APIENTRY
3596 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
3597 {
3598    PWND Window;
3599    BOOL ret;
3600    DECLARE_RETURN(BOOL);
3601    USER_REFERENCE_ENTRY Ref;
3602 
3603    TRACE("Enter NtUserShowWindow hWnd %p SW_ %d\n",hWnd, nCmdShow);
3604    UserEnterExclusive();
3605 
3606    if (!(Window = UserGetWindowObject(hWnd)) ||
3607         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
3608    {
3609       RETURN(FALSE);
3610    }
3611 
3612    if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
3613    {
3614       EngSetLastError(ERROR_INVALID_PARAMETER);
3615       RETURN(FALSE);
3616    }
3617 
3618    UserRefObjectCo(Window, &Ref);
3619    ret = co_WinPosShowWindow(Window, nCmdShow);
3620    UserDerefObjectCo(Window);
3621 
3622    RETURN(ret);
3623 
3624 CLEANUP:
3625    TRACE("Leave NtUserShowWindow, ret=%i\n",_ret_);
3626    UserLeave();
3627    END_CLEANUP;
3628 }
3629 
3630 
3631 /*
3632  *    @implemented
3633  */
3634 HWND APIENTRY
3635 NtUserWindowFromPoint(LONG X, LONG Y)
3636 {
3637    POINT pt;
3638    HWND Ret;
3639    PWND DesktopWindow = NULL, Window = NULL;
3640    USHORT hittest;
3641    DECLARE_RETURN(HWND);
3642    USER_REFERENCE_ENTRY Ref;
3643 
3644    TRACE("Enter NtUserWindowFromPoint\n");
3645    UserEnterExclusive();
3646 
3647    if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
3648    {
3649       //PTHREADINFO pti;
3650 
3651       pt.x = X;
3652       pt.y = Y;
3653 
3654       // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window.
3655       // It is possible this referencing is useless, though it should not hurt...
3656       UserRefObjectCo(DesktopWindow, &Ref);
3657 
3658       //pti = PsGetCurrentThreadWin32Thread();
3659       Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest, FALSE);
3660 
3661       if (Window)
3662       {
3663          Ret = UserHMGetHandle(Window);
3664 
3665          RETURN( Ret);
3666       }
3667    }
3668 
3669    RETURN( NULL);
3670 
3671 CLEANUP:
3672    if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
3673 
3674    TRACE("Leave NtUserWindowFromPoint, ret=%p\n", _ret_);
3675    UserLeave();
3676    END_CLEANUP;
3677 }
3678 
3679 /* EOF */
3680