user32: Send a WM_MOUSELEAVE even if another window calls TrackMouseEvent before...
[wine] / dlls / user / winpos.c
1 /*
2  * Window position related functions.
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  *                       1995, 1996, 1999 Alex Korobka
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26 #include <string.h>
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #include "winerror.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winerror.h"
34 #include "wine/winuser16.h"
35 #include "wine/server.h"
36 #include "controls.h"
37 #include "user_private.h"
38 #include "win.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(win);
42
43 #define HAS_DLGFRAME(style,exStyle) \
44     (((exStyle) & WS_EX_DLGMODALFRAME) || \
45      (((style) & WS_DLGFRAME) && !((style) & WS_BORDER)))
46
47 #define HAS_THICKFRAME(style) \
48     (((style) & WS_THICKFRAME) && \
49      !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
50
51 #define EMPTYPOINT(pt)          ((*(LONG*)&(pt)) == -1)
52
53 #define PLACE_MIN               0x0001
54 #define PLACE_MAX               0x0002
55 #define PLACE_RECT              0x0004
56
57
58 #define DWP_MAGIC  ((INT)('W' | ('P' << 8) | ('O' << 16) | ('S' << 24)))
59
60 typedef struct
61 {
62     INT       actualCount;
63     INT       suggestedCount;
64     BOOL      valid;
65     INT       wMagic;
66     HWND      hwndParent;
67     WINDOWPOS winPos[1];
68 } DWP;
69
70 typedef struct
71 {
72     RECT16   rectNormal;
73     POINT16  ptIconPos;
74     POINT16  ptMaxPos;
75     HWND     hwndIconTitle;
76 } INTERNALPOS, *LPINTERNALPOS;
77
78 /* ----- internal functions ----- */
79
80 static const WCHAR SysIP_W[] = { 'S','y','s','I','P',0 };
81
82 static inline INTERNALPOS *get_internal_pos( HWND hwnd )
83 {
84     return GetPropW( hwnd, SysIP_W );
85 }
86
87 static inline void set_internal_pos( HWND hwnd, INTERNALPOS *pos )
88 {
89     SetPropW( hwnd, SysIP_W, pos );
90 }
91
92 /***********************************************************************
93  *           WINPOS_CheckInternalPos
94  *
95  * Called when a window is destroyed.
96  */
97 void WINPOS_CheckInternalPos( HWND hwnd )
98 {
99     LPINTERNALPOS lpPos = get_internal_pos( hwnd );
100
101     if ( lpPos )
102     {
103         if( IsWindow(lpPos->hwndIconTitle) )
104             DestroyWindow( lpPos->hwndIconTitle );
105         HeapFree( GetProcessHeap(), 0, lpPos );
106     }
107 }
108
109 /***********************************************************************
110  *              ArrangeIconicWindows (USER32.@)
111  */
112 UINT WINAPI ArrangeIconicWindows( HWND parent )
113 {
114     RECT rectParent;
115     HWND hwndChild;
116     INT x, y, xspacing, yspacing;
117
118     GetClientRect( parent, &rectParent );
119     x = rectParent.left;
120     y = rectParent.bottom;
121     xspacing = GetSystemMetrics(SM_CXICONSPACING);
122     yspacing = GetSystemMetrics(SM_CYICONSPACING);
123
124     hwndChild = GetWindow( parent, GW_CHILD );
125     while (hwndChild)
126     {
127         if( IsIconic( hwndChild ) )
128         {
129             WINPOS_ShowIconTitle( hwndChild, FALSE );
130
131             SetWindowPos( hwndChild, 0, x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2,
132                             y - yspacing - GetSystemMetrics(SM_CYICON)/2, 0, 0,
133                             SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
134             if( IsWindow(hwndChild) )
135                 WINPOS_ShowIconTitle(hwndChild , TRUE );
136
137             if (x <= rectParent.right - xspacing) x += xspacing;
138             else
139             {
140                 x = rectParent.left;
141                 y -= yspacing;
142             }
143         }
144         hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
145     }
146     return yspacing;
147 }
148
149
150 /***********************************************************************
151  *              SwitchToThisWindow (USER32.@)
152  */
153 void WINAPI SwitchToThisWindow( HWND hwnd, BOOL restore )
154 {
155     ShowWindow( hwnd, restore ? SW_RESTORE : SW_SHOWMINIMIZED );
156 }
157
158
159 /***********************************************************************
160  *              GetWindowRect (USER32.@)
161  */
162 BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect )
163 {
164     BOOL ret = WIN_GetRectangles( hwnd, rect, NULL );
165     if (ret)
166     {
167         MapWindowPoints( GetAncestor( hwnd, GA_PARENT ), 0, (POINT *)rect, 2 );
168         TRACE( "hwnd %p (%d,%d)-(%d,%d)\n",
169                hwnd, rect->left, rect->top, rect->right, rect->bottom);
170     }
171     return ret;
172 }
173
174
175 /***********************************************************************
176  *              GetWindowRgn (USER32.@)
177  */
178 int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn )
179 {
180     int nRet = ERROR;
181     NTSTATUS status;
182     HRGN win_rgn = 0;
183     RGNDATA *data;
184     size_t size = 256;
185
186     do
187     {
188         if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 )))
189         {
190             SetLastError( ERROR_OUTOFMEMORY );
191             return ERROR;
192         }
193         SERVER_START_REQ( get_window_region )
194         {
195             req->window = hwnd;
196             wine_server_set_reply( req, data->Buffer, size );
197             if (!(status = wine_server_call( req )))
198             {
199                 size_t reply_size = wine_server_reply_size( reply );
200                 if (reply_size)
201                 {
202                     data->rdh.dwSize   = sizeof(data->rdh);
203                     data->rdh.iType    = RDH_RECTANGLES;
204                     data->rdh.nCount   = reply_size / sizeof(RECT);
205                     data->rdh.nRgnSize = reply_size;
206                     win_rgn = ExtCreateRegion( NULL, size, data );
207                 }
208             }
209             else size = reply->total_size;
210         }
211         SERVER_END_REQ;
212         HeapFree( GetProcessHeap(), 0, data );
213     } while (status == STATUS_BUFFER_OVERFLOW);
214
215     if (status) SetLastError( RtlNtStatusToDosError(status) );
216     else if (win_rgn)
217     {
218         nRet = CombineRgn( hrgn, win_rgn, 0, RGN_COPY );
219         DeleteObject( win_rgn );
220     }
221     return nRet;
222 }
223
224
225 /***********************************************************************
226  *              SetWindowRgn (USER32.@)
227  */
228 int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw )
229 {
230     static const RECT empty_rect;
231     BOOL ret;
232
233     if (hrgn)
234     {
235         RGNDATA *data;
236         DWORD size;
237
238         if (!(size = GetRegionData( hrgn, 0, NULL ))) return FALSE;
239         if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
240         if (!GetRegionData( hrgn, size, data ))
241         {
242             HeapFree( GetProcessHeap(), 0, data );
243             return FALSE;
244         }
245         SERVER_START_REQ( set_window_region )
246         {
247             req->window = hwnd;
248             if (data->rdh.nCount)
249                 wine_server_add_data( req, data->Buffer, data->rdh.nCount * sizeof(RECT) );
250             else
251                 wine_server_add_data( req, &empty_rect, sizeof(empty_rect) );
252             ret = !wine_server_call_err( req );
253         }
254         SERVER_END_REQ;
255     }
256     else  /* clear existing region */
257     {
258         SERVER_START_REQ( set_window_region )
259         {
260             req->window = hwnd;
261             ret = !wine_server_call_err( req );
262         }
263         SERVER_END_REQ;
264     }
265
266     if (ret) ret = USER_Driver->pSetWindowRgn( hwnd, hrgn, bRedraw );
267
268     if (ret && bRedraw) RedrawWindow( hwnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ERASE );
269     return ret;
270 }
271
272
273 /***********************************************************************
274  *              GetClientRect (USER32.@)
275  */
276 BOOL WINAPI GetClientRect( HWND hwnd, LPRECT rect )
277 {
278     BOOL ret;
279
280     if ((ret = WIN_GetRectangles( hwnd, NULL, rect )))
281     {
282         rect->right -= rect->left;
283         rect->bottom -= rect->top;
284         rect->left = rect->top = 0;
285     }
286     return ret;
287 }
288
289
290 /*******************************************************************
291  *              ClientToScreen (USER32.@)
292  */
293 BOOL WINAPI ClientToScreen( HWND hwnd, LPPOINT lppnt )
294 {
295     MapWindowPoints( hwnd, 0, lppnt, 1 );
296     return TRUE;
297 }
298
299
300 /*******************************************************************
301  *              ScreenToClient (USER32.@)
302  */
303 BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
304 {
305     MapWindowPoints( 0, hwnd, lppnt, 1 );
306     return TRUE;
307 }
308
309
310 /***********************************************************************
311  *           list_children_from_point
312  *
313  * Get the list of children that can contain point from the server.
314  * Point is in screen coordinates.
315  * Returned list must be freed by caller.
316  */
317 static HWND *list_children_from_point( HWND hwnd, POINT pt )
318 {
319     HWND *list;
320     int size = 32;
321
322     for (;;)
323     {
324         int count = 0;
325
326         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
327
328         SERVER_START_REQ( get_window_children_from_point )
329         {
330             req->parent = hwnd;
331             req->x = pt.x;
332             req->y = pt.y;
333             wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
334             if (!wine_server_call( req )) count = reply->count;
335         }
336         SERVER_END_REQ;
337         if (count && count < size)
338         {
339             list[count] = 0;
340             return list;
341         }
342         HeapFree( GetProcessHeap(), 0, list );
343         if (!count) break;
344         size = count + 1;  /* restart with a large enough buffer */
345     }
346     return NULL;
347 }
348
349
350 /***********************************************************************
351  *           WINPOS_WindowFromPoint
352  *
353  * Find the window and hittest for a given point.
354  */
355 HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
356 {
357     int i, res;
358     HWND ret, *list;
359
360     if (!hwndScope) hwndScope = GetDesktopWindow();
361
362     *hittest = HTNOWHERE;
363
364     if (!(list = list_children_from_point( hwndScope, pt ))) return 0;
365
366     /* now determine the hittest */
367
368     for (i = 0; list[i]; i++)
369     {
370         LONG style = GetWindowLongW( list[i], GWL_STYLE );
371
372         /* If window is minimized or disabled, return at once */
373         if (style & WS_MINIMIZE)
374         {
375             *hittest = HTCAPTION;
376             break;
377         }
378         if (style & WS_DISABLED)
379         {
380             *hittest = HTERROR;
381             break;
382         }
383         /* Send WM_NCCHITTEST (if same thread) */
384         if (!WIN_IsCurrentThread( list[i] ))
385         {
386             *hittest = HTCLIENT;
387             break;
388         }
389         res = SendMessageW( list[i], WM_NCHITTEST, 0, MAKELONG(pt.x,pt.y) );
390         if (res != HTTRANSPARENT)
391         {
392             *hittest = res;  /* Found the window */
393             break;
394         }
395         /* continue search with next window in z-order */
396     }
397     ret = list[i];
398     HeapFree( GetProcessHeap(), 0, list );
399     TRACE( "scope %p (%d,%d) returning %p\n", hwndScope, pt.x, pt.y, ret );
400     return ret;
401 }
402
403
404 /*******************************************************************
405  *              WindowFromPoint (USER32.@)
406  */
407 HWND WINAPI WindowFromPoint( POINT pt )
408 {
409     INT hittest;
410     return WINPOS_WindowFromPoint( 0, pt, &hittest );
411 }
412
413
414 /*******************************************************************
415  *              ChildWindowFromPoint (USER32.@)
416  */
417 HWND WINAPI ChildWindowFromPoint( HWND hwndParent, POINT pt )
418 {
419     return ChildWindowFromPointEx( hwndParent, pt, CWP_ALL );
420 }
421
422 /*******************************************************************
423  *              ChildWindowFromPointEx (USER32.@)
424  */
425 HWND WINAPI ChildWindowFromPointEx( HWND hwndParent, POINT pt, UINT uFlags)
426 {
427     /* pt is in the client coordinates */
428     HWND *list;
429     int i;
430     RECT rect;
431     HWND retvalue;
432
433     GetClientRect( hwndParent, &rect );
434     if (!PtInRect( &rect, pt )) return 0;
435     if (!(list = WIN_ListChildren( hwndParent ))) return hwndParent;
436
437     for (i = 0; list[i]; i++)
438     {
439         if (!WIN_GetRectangles( list[i], &rect, NULL )) continue;
440         if (!PtInRect( &rect, pt )) continue;
441         if (uFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
442         {
443             LONG style = GetWindowLongW( list[i], GWL_STYLE );
444             if ((uFlags & CWP_SKIPINVISIBLE) && !(style & WS_VISIBLE)) continue;
445             if ((uFlags & CWP_SKIPDISABLED) && (style & WS_DISABLED)) continue;
446         }
447         if (uFlags & CWP_SKIPTRANSPARENT)
448         {
449             if (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TRANSPARENT) continue;
450         }
451         break;
452     }
453     retvalue = list[i];
454     HeapFree( GetProcessHeap(), 0, list );
455     if (!retvalue) retvalue = hwndParent;
456     return retvalue;
457 }
458
459
460 /*******************************************************************
461  *         WINPOS_GetWinOffset
462  *
463  * Calculate the offset between the origin of the two windows. Used
464  * to implement MapWindowPoints.
465  */
466 static void WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, POINT *offset )
467 {
468     WND * wndPtr;
469
470     offset->x = offset->y = 0;
471
472     /* Translate source window origin to screen coords */
473     if (hwndFrom)
474     {
475         HWND hwnd = hwndFrom;
476
477         while (hwnd)
478         {
479             if (hwnd == hwndTo) return;
480             if (!(wndPtr = WIN_GetPtr( hwnd )))
481             {
482                 ERR( "bad hwndFrom = %p\n", hwnd );
483                 return;
484             }
485             if (wndPtr == WND_DESKTOP) break;
486             if (wndPtr == WND_OTHER_PROCESS) goto other_process;
487             offset->x += wndPtr->rectClient.left;
488             offset->y += wndPtr->rectClient.top;
489             hwnd = wndPtr->parent;
490             WIN_ReleasePtr( wndPtr );
491         }
492     }
493
494     /* Translate origin to destination window coords */
495     if (hwndTo)
496     {
497         HWND hwnd = hwndTo;
498
499         while (hwnd)
500         {
501             if (!(wndPtr = WIN_GetPtr( hwnd )))
502             {
503                 ERR( "bad hwndTo = %p\n", hwnd );
504                 return;
505             }
506             if (wndPtr == WND_DESKTOP) break;
507             if (wndPtr == WND_OTHER_PROCESS) goto other_process;
508             offset->x -= wndPtr->rectClient.left;
509             offset->y -= wndPtr->rectClient.top;
510             hwnd = wndPtr->parent;
511             WIN_ReleasePtr( wndPtr );
512         }
513     }
514     return;
515
516  other_process:  /* one of the parents may belong to another process, do it the hard way */
517     offset->x = offset->y = 0;
518     SERVER_START_REQ( get_windows_offset )
519     {
520         req->from = hwndFrom;
521         req->to   = hwndTo;
522         if (!wine_server_call( req ))
523         {
524             offset->x = reply->x;
525             offset->y = reply->y;
526         }
527     }
528     SERVER_END_REQ;
529 }
530
531
532 /*******************************************************************
533  *              MapWindowPoints (USER.258)
534  */
535 void WINAPI MapWindowPoints16( HWND16 hwndFrom, HWND16 hwndTo,
536                                LPPOINT16 lppt, UINT16 count )
537 {
538     POINT offset;
539
540     WINPOS_GetWinOffset( WIN_Handle32(hwndFrom), WIN_Handle32(hwndTo), &offset );
541     while (count--)
542     {
543         lppt->x += offset.x;
544         lppt->y += offset.y;
545         lppt++;
546     }
547 }
548
549
550 /*******************************************************************
551  *              MapWindowPoints (USER32.@)
552  */
553 INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT count )
554 {
555     POINT offset;
556
557     WINPOS_GetWinOffset( hwndFrom, hwndTo, &offset );
558     while (count--)
559     {
560         lppt->x += offset.x;
561         lppt->y += offset.y;
562         lppt++;
563     }
564     return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) );
565 }
566
567
568 /***********************************************************************
569  *              IsIconic (USER32.@)
570  */
571 BOOL WINAPI IsIconic(HWND hWnd)
572 {
573     return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MINIMIZE) != 0;
574 }
575
576
577 /***********************************************************************
578  *              IsZoomed (USER32.@)
579  */
580 BOOL WINAPI IsZoomed(HWND hWnd)
581 {
582     return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MAXIMIZE) != 0;
583 }
584
585
586 /*******************************************************************
587  *              AllowSetForegroundWindow (USER32.@)
588  */
589 BOOL WINAPI AllowSetForegroundWindow( DWORD procid )
590 {
591     /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
592      * implemented, then fix this function. */
593     return TRUE;
594 }
595
596
597 /*******************************************************************
598  *              LockSetForegroundWindow (USER32.@)
599  */
600 BOOL WINAPI LockSetForegroundWindow( UINT lockcode )
601 {
602     /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
603      * implemented, then fix this function. */
604     return TRUE;
605 }
606
607
608 /***********************************************************************
609  *              BringWindowToTop (USER32.@)
610  */
611 BOOL WINAPI BringWindowToTop( HWND hwnd )
612 {
613     return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
614 }
615
616
617 /***********************************************************************
618  *              MoveWindow (USER32.@)
619  */
620 BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
621                             BOOL repaint )
622 {
623     int flags = SWP_NOZORDER | SWP_NOACTIVATE;
624     if (!repaint) flags |= SWP_NOREDRAW;
625     TRACE("%p %d,%d %dx%d %d\n", hwnd, x, y, cx, cy, repaint );
626     return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
627 }
628
629 /***********************************************************************
630  *           WINPOS_InitInternalPos
631  */
632 static LPINTERNALPOS WINPOS_InitInternalPos( WND* wnd )
633 {
634     LPINTERNALPOS lpPos = get_internal_pos( wnd->hwndSelf );
635     if( !lpPos )
636     {
637         /* this happens when the window is minimized/maximized
638          * for the first time (rectWindow is not adjusted yet) */
639
640         lpPos = HeapAlloc( GetProcessHeap(), 0, sizeof(INTERNALPOS) );
641         if( !lpPos ) return NULL;
642
643         set_internal_pos( wnd->hwndSelf, lpPos );
644         lpPos->hwndIconTitle = 0; /* defer until needs to be shown */
645         lpPos->rectNormal.left   = wnd->rectWindow.left;
646         lpPos->rectNormal.top    = wnd->rectWindow.top;
647         lpPos->rectNormal.right  = wnd->rectWindow.right;
648         lpPos->rectNormal.bottom = wnd->rectWindow.bottom;
649         lpPos->ptIconPos.x = lpPos->ptIconPos.y = -1;
650         lpPos->ptMaxPos.x = lpPos->ptMaxPos.y = -1;
651     }
652
653     if( wnd->dwStyle & WS_MINIMIZE )
654     {
655         lpPos->ptIconPos.x = wnd->rectWindow.left;
656         lpPos->ptIconPos.y = wnd->rectWindow.top;
657     }
658     else if( wnd->dwStyle & WS_MAXIMIZE )
659     {
660         lpPos->ptMaxPos.x = wnd->rectWindow.left;
661         lpPos->ptMaxPos.y = wnd->rectWindow.top;
662     }
663     else
664     {
665         lpPos->rectNormal.left   = wnd->rectWindow.left;
666         lpPos->rectNormal.top    = wnd->rectWindow.top;
667         lpPos->rectNormal.right  = wnd->rectWindow.right;
668         lpPos->rectNormal.bottom = wnd->rectWindow.bottom;
669     }
670     return lpPos;
671 }
672
673 /***********************************************************************
674  *           WINPOS_RedrawIconTitle
675  */
676 BOOL WINPOS_RedrawIconTitle( HWND hWnd )
677 {
678     LPINTERNALPOS lpPos = get_internal_pos( hWnd );
679     if( lpPos )
680     {
681         if( lpPos->hwndIconTitle )
682         {
683             SendMessageW( lpPos->hwndIconTitle, WM_SHOWWINDOW, TRUE, 0);
684             InvalidateRect( lpPos->hwndIconTitle, NULL, TRUE );
685             return TRUE;
686         }
687     }
688     return FALSE;
689 }
690
691 /***********************************************************************
692  *           WINPOS_ShowIconTitle
693  */
694 BOOL WINPOS_ShowIconTitle( HWND hwnd, BOOL bShow )
695 {
696     LPINTERNALPOS lpPos = get_internal_pos( hwnd );
697
698     if (lpPos && !GetPropA( hwnd, "__wine_x11_managed" ))
699     {
700         HWND title = lpPos->hwndIconTitle;
701
702         TRACE("%p %i\n", hwnd, (bShow != 0) );
703
704         if( !title )
705             lpPos->hwndIconTitle = title = ICONTITLE_Create( hwnd );
706         if( bShow )
707         {
708             if (!IsWindowVisible(title))
709             {
710                 SendMessageW( title, WM_SHOWWINDOW, TRUE, 0 );
711                 SetWindowPos( title, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
712                               SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW );
713             }
714         }
715         else ShowWindow( title, SW_HIDE );
716     }
717     return FALSE;
718 }
719
720 /*******************************************************************
721  *           WINPOS_GetMinMaxInfo
722  *
723  * Get the minimized and maximized information for a window.
724  */
725 void WINPOS_GetMinMaxInfo( HWND hwnd, POINT *maxSize, POINT *maxPos,
726                            POINT *minTrack, POINT *maxTrack )
727 {
728     LPINTERNALPOS lpPos;
729     MINMAXINFO MinMax;
730     INT xinc, yinc;
731     LONG style = GetWindowLongA( hwnd, GWL_STYLE );
732     LONG exstyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
733     RECT rc;
734
735     /* Compute default values */
736
737     GetWindowRect(hwnd, &rc);
738     MinMax.ptReserved.x = rc.left;
739     MinMax.ptReserved.y = rc.top;
740
741     if (style & WS_CHILD)
742     {
743         if ((style & WS_CAPTION) == WS_CAPTION)
744             style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
745
746         GetClientRect(GetAncestor(hwnd,GA_PARENT), &rc);
747         AdjustWindowRectEx(&rc, style, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
748
749         /* avoid calculating this twice */
750         style &= ~(WS_DLGFRAME | WS_BORDER | WS_THICKFRAME);
751
752         MinMax.ptMaxSize.x = rc.right - rc.left;
753         MinMax.ptMaxSize.y = rc.bottom - rc.top;
754     }
755     else
756     {
757         MinMax.ptMaxSize.x = GetSystemMetrics(SM_CXSCREEN);
758         MinMax.ptMaxSize.y = GetSystemMetrics(SM_CYSCREEN);
759     }
760     MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
761     MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
762     MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXSCREEN) + 2*GetSystemMetrics(SM_CXFRAME);
763     MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYSCREEN) + 2*GetSystemMetrics(SM_CYFRAME);
764
765     if (HAS_DLGFRAME( style, exstyle ))
766     {
767         xinc = GetSystemMetrics(SM_CXDLGFRAME);
768         yinc = GetSystemMetrics(SM_CYDLGFRAME);
769     }
770     else
771     {
772         xinc = yinc = 0;
773         if (HAS_THICKFRAME(style))
774         {
775             xinc += GetSystemMetrics(SM_CXFRAME);
776             yinc += GetSystemMetrics(SM_CYFRAME);
777         }
778         if (style & WS_BORDER)
779         {
780             xinc += GetSystemMetrics(SM_CXBORDER);
781             yinc += GetSystemMetrics(SM_CYBORDER);
782         }
783     }
784     MinMax.ptMaxSize.x += 2 * xinc;
785     MinMax.ptMaxSize.y += 2 * yinc;
786
787     lpPos = get_internal_pos( hwnd );
788     if( lpPos && !EMPTYPOINT(lpPos->ptMaxPos) )
789     {
790         MinMax.ptMaxPosition.x = lpPos->ptMaxPos.x;
791         MinMax.ptMaxPosition.y = lpPos->ptMaxPos.y;
792     }
793     else
794     {
795         MinMax.ptMaxPosition.x = -xinc;
796         MinMax.ptMaxPosition.y = -yinc;
797     }
798
799     SendMessageW( hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
800
801       /* Some sanity checks */
802
803     TRACE("%d %d / %d %d / %d %d / %d %d\n",
804                       MinMax.ptMaxSize.x, MinMax.ptMaxSize.y,
805                       MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y,
806                       MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y,
807                       MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y);
808     MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x,
809                                    MinMax.ptMinTrackSize.x );
810     MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y,
811                                    MinMax.ptMinTrackSize.y );
812
813     if (maxSize) *maxSize = MinMax.ptMaxSize;
814     if (maxPos) *maxPos = MinMax.ptMaxPosition;
815     if (minTrack) *minTrack = MinMax.ptMinTrackSize;
816     if (maxTrack) *maxTrack = MinMax.ptMaxTrackSize;
817 }
818
819 /***********************************************************************
820  *              ShowWindowAsync (USER32.@)
821  *
822  * doesn't wait; returns immediately.
823  * used by threads to toggle windows in other (possibly hanging) threads
824  */
825 BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd )
826 {
827     HWND full_handle;
828
829     if (is_broadcast(hwnd))
830     {
831         SetLastError( ERROR_INVALID_PARAMETER );
832         return FALSE;
833     }
834
835     if ((full_handle = WIN_IsCurrentThread( hwnd )))
836         return USER_Driver->pShowWindow( full_handle, cmd );
837
838     return SendNotifyMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
839 }
840
841
842 /***********************************************************************
843  *              ShowWindow (USER32.@)
844  */
845 BOOL WINAPI ShowWindow( HWND hwnd, INT cmd )
846 {
847     HWND full_handle;
848
849     if (is_broadcast(hwnd))
850     {
851         SetLastError( ERROR_INVALID_PARAMETER );
852         return FALSE;
853     }
854     if ((full_handle = WIN_IsCurrentThread( hwnd )))
855         return USER_Driver->pShowWindow( full_handle, cmd );
856
857     return SendMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
858 }
859
860
861 /***********************************************************************
862  *              GetInternalWindowPos (USER32.@)
863  */
864 UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd,
865                                       LPPOINT ptIcon )
866 {
867     WINDOWPLACEMENT wndpl;
868     if (GetWindowPlacement( hwnd, &wndpl ))
869     {
870         if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
871         if (ptIcon)  *ptIcon = wndpl.ptMinPosition;
872         return wndpl.showCmd;
873     }
874     return 0;
875 }
876
877
878 /***********************************************************************
879  *              GetWindowPlacement (USER32.@)
880  *
881  * Win95:
882  * Fails if wndpl->length of Win95 (!) apps is invalid.
883  */
884 BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
885 {
886     WND *pWnd = WIN_GetPtr( hwnd );
887     LPINTERNALPOS lpPos;
888
889     if (!pWnd || pWnd == WND_DESKTOP) return FALSE;
890     if (pWnd == WND_OTHER_PROCESS)
891     {
892         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
893         return FALSE;
894     }
895
896     lpPos = WINPOS_InitInternalPos( pWnd );
897     wndpl->length  = sizeof(*wndpl);
898     if( pWnd->dwStyle & WS_MINIMIZE )
899         wndpl->showCmd = SW_SHOWMINIMIZED;
900     else
901         wndpl->showCmd = ( pWnd->dwStyle & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
902     if( pWnd->flags & WIN_RESTORE_MAX )
903         wndpl->flags = WPF_RESTORETOMAXIMIZED;
904     else
905         wndpl->flags = 0;
906     wndpl->ptMinPosition.x = lpPos->ptIconPos.x;
907     wndpl->ptMinPosition.y = lpPos->ptIconPos.y;
908     wndpl->ptMaxPosition.x = lpPos->ptMaxPos.x;
909     wndpl->ptMaxPosition.y = lpPos->ptMaxPos.y;
910     wndpl->rcNormalPosition.left   = lpPos->rectNormal.left;
911     wndpl->rcNormalPosition.top    = lpPos->rectNormal.top;
912     wndpl->rcNormalPosition.right  = lpPos->rectNormal.right;
913     wndpl->rcNormalPosition.bottom = lpPos->rectNormal.bottom;
914     WIN_ReleasePtr( pWnd );
915     return TRUE;
916 }
917
918
919 /***********************************************************************
920  *           WINPOS_SetPlacement
921  */
922 static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT flags )
923 {
924     LPINTERNALPOS lpPos;
925     DWORD style;
926     WND *pWnd = WIN_GetPtr( hwnd );
927
928     if (!pWnd || pWnd == WND_OTHER_PROCESS || pWnd == WND_DESKTOP) return FALSE;
929     lpPos = WINPOS_InitInternalPos( pWnd );
930
931     if( flags & PLACE_MIN )
932     {
933         lpPos->ptIconPos.x = wndpl->ptMinPosition.x;
934         lpPos->ptIconPos.y = wndpl->ptMinPosition.y;
935     }
936     if( flags & PLACE_MAX )
937     {
938         lpPos->ptMaxPos.x = wndpl->ptMaxPosition.x;
939         lpPos->ptMaxPos.y = wndpl->ptMaxPosition.y;
940     }
941     if( flags & PLACE_RECT)
942     {
943         lpPos->rectNormal.left   = wndpl->rcNormalPosition.left;
944         lpPos->rectNormal.top    = wndpl->rcNormalPosition.top;
945         lpPos->rectNormal.right  = wndpl->rcNormalPosition.right;
946         lpPos->rectNormal.bottom = wndpl->rcNormalPosition.bottom;
947     }
948
949     style = pWnd->dwStyle;
950     WIN_ReleasePtr( pWnd );
951
952     if( style & WS_MINIMIZE )
953     {
954         WINPOS_ShowIconTitle( hwnd, FALSE );
955         if( wndpl->flags & WPF_SETMINPOSITION && !EMPTYPOINT(lpPos->ptIconPos))
956             SetWindowPos( hwnd, 0, lpPos->ptIconPos.x, lpPos->ptIconPos.y,
957                           0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
958     }
959     else if( style & WS_MAXIMIZE )
960     {
961         if( !EMPTYPOINT(lpPos->ptMaxPos) )
962             SetWindowPos( hwnd, 0, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y,
963                           0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
964     }
965     else if( flags & PLACE_RECT )
966         SetWindowPos( hwnd, 0, lpPos->rectNormal.left, lpPos->rectNormal.top,
967                       lpPos->rectNormal.right - lpPos->rectNormal.left,
968                       lpPos->rectNormal.bottom - lpPos->rectNormal.top,
969                       SWP_NOZORDER | SWP_NOACTIVATE );
970
971     ShowWindow( hwnd, wndpl->showCmd );
972
973     if (IsIconic( hwnd ))
974     {
975         if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE) WINPOS_ShowIconTitle( hwnd, TRUE );
976
977         /* SDK: ...valid only the next time... */
978         if( wndpl->flags & WPF_RESTORETOMAXIMIZED )
979         {
980             pWnd = WIN_GetPtr( hwnd );
981             if (pWnd && pWnd != WND_OTHER_PROCESS)
982             {
983                 pWnd->flags |= WIN_RESTORE_MAX;
984                 WIN_ReleasePtr( pWnd );
985             }
986         }
987     }
988     return TRUE;
989 }
990
991
992 /***********************************************************************
993  *              SetWindowPlacement (USER32.@)
994  *
995  * Win95:
996  * Fails if wndpl->length of Win95 (!) apps is invalid.
997  */
998 BOOL WINAPI SetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl )
999 {
1000     if (!wpl) return FALSE;
1001     return WINPOS_SetPlacement( hwnd, wpl, PLACE_MIN | PLACE_MAX | PLACE_RECT );
1002 }
1003
1004
1005 /***********************************************************************
1006  *              AnimateWindow (USER32.@)
1007  *              Shows/Hides a window with an animation
1008  *              NO ANIMATION YET
1009  */
1010 BOOL WINAPI AnimateWindow(HWND hwnd, DWORD dwTime, DWORD dwFlags)
1011 {
1012         FIXME("partial stub\n");
1013
1014         /* If trying to show/hide and it's already   *
1015          * shown/hidden or invalid window, fail with *
1016          * invalid parameter                         */
1017         if(!IsWindow(hwnd) ||
1018            (IsWindowVisible(hwnd) && !(dwFlags & AW_HIDE)) ||
1019            (!IsWindowVisible(hwnd) && (dwFlags & AW_HIDE)))
1020         {
1021                 SetLastError(ERROR_INVALID_PARAMETER);
1022                 return FALSE;
1023         }
1024
1025         ShowWindow(hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA));
1026
1027         return TRUE;
1028 }
1029
1030 /***********************************************************************
1031  *              SetInternalWindowPos (USER32.@)
1032  */
1033 void WINAPI SetInternalWindowPos( HWND hwnd, UINT showCmd,
1034                                     LPRECT rect, LPPOINT pt )
1035 {
1036     if( IsWindow(hwnd) )
1037     {
1038         WINDOWPLACEMENT wndpl;
1039         UINT flags;
1040
1041         wndpl.length  = sizeof(wndpl);
1042         wndpl.showCmd = showCmd;
1043         wndpl.flags = flags = 0;
1044
1045         if( pt )
1046         {
1047             flags |= PLACE_MIN;
1048             wndpl.flags |= WPF_SETMINPOSITION;
1049             wndpl.ptMinPosition = *pt;
1050         }
1051         if( rect )
1052         {
1053             flags |= PLACE_RECT;
1054             wndpl.rcNormalPosition = *rect;
1055         }
1056         WINPOS_SetPlacement( hwnd, &wndpl, flags );
1057     }
1058 }
1059
1060
1061 /*******************************************************************
1062  *         can_activate_window
1063  *
1064  * Check if we can activate the specified window.
1065  */
1066 static BOOL can_activate_window( HWND hwnd )
1067 {
1068     LONG style;
1069
1070     if (!hwnd) return FALSE;
1071     style = GetWindowLongW( hwnd, GWL_STYLE );
1072     if (!(style & WS_VISIBLE)) return FALSE;
1073     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
1074     return !(style & WS_DISABLED);
1075 }
1076
1077
1078 /*******************************************************************
1079  *         WINPOS_ActivateOtherWindow
1080  *
1081  *  Activates window other than pWnd.
1082  */
1083 void WINPOS_ActivateOtherWindow(HWND hwnd)
1084 {
1085     HWND hwndTo, fg;
1086
1087     if ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) && (hwndTo = GetWindow( hwnd, GW_OWNER )))
1088     {
1089         hwndTo = GetAncestor( hwndTo, GA_ROOT );
1090         if (can_activate_window( hwndTo )) goto done;
1091     }
1092
1093     hwndTo = hwnd;
1094     for (;;)
1095     {
1096         if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break;
1097         if (can_activate_window( hwndTo )) break;
1098     }
1099
1100  done:
1101     fg = GetForegroundWindow();
1102     TRACE("win = %p fg = %p\n", hwndTo, fg);
1103     if (!fg || (hwnd == fg))
1104     {
1105         if (SetForegroundWindow( hwndTo )) return;
1106     }
1107     if (!SetActiveWindow( hwndTo )) SetActiveWindow(0);
1108 }
1109
1110
1111 /***********************************************************************
1112  *           WINPOS_HandleWindowPosChanging
1113  *
1114  * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
1115  */
1116 LONG WINPOS_HandleWindowPosChanging( HWND hwnd, WINDOWPOS *winpos )
1117 {
1118     POINT minTrack, maxTrack;
1119     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1120
1121     if (winpos->flags & SWP_NOSIZE) return 0;
1122     if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0))
1123     {
1124         WINPOS_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack );
1125         if (winpos->cx > maxTrack.x) winpos->cx = maxTrack.x;
1126         if (winpos->cy > maxTrack.y) winpos->cy = maxTrack.y;
1127         if (!(style & WS_MINIMIZE))
1128         {
1129             if (winpos->cx < minTrack.x ) winpos->cx = minTrack.x;
1130             if (winpos->cy < minTrack.y ) winpos->cy = minTrack.y;
1131         }
1132     }
1133     return 0;
1134 }
1135
1136
1137 /***********************************************************************
1138  *           dump_winpos_flags
1139  */
1140 static void dump_winpos_flags(UINT flags)
1141 {
1142     TRACE("flags:");
1143     if(flags & SWP_NOSIZE) TRACE(" SWP_NOSIZE");
1144     if(flags & SWP_NOMOVE) TRACE(" SWP_NOMOVE");
1145     if(flags & SWP_NOZORDER) TRACE(" SWP_NOZORDER");
1146     if(flags & SWP_NOREDRAW) TRACE(" SWP_NOREDRAW");
1147     if(flags & SWP_NOACTIVATE) TRACE(" SWP_NOACTIVATE");
1148     if(flags & SWP_FRAMECHANGED) TRACE(" SWP_FRAMECHANGED");
1149     if(flags & SWP_SHOWWINDOW) TRACE(" SWP_SHOWWINDOW");
1150     if(flags & SWP_HIDEWINDOW) TRACE(" SWP_HIDEWINDOW");
1151     if(flags & SWP_NOCOPYBITS) TRACE(" SWP_NOCOPYBITS");
1152     if(flags & SWP_NOOWNERZORDER) TRACE(" SWP_NOOWNERZORDER");
1153     if(flags & SWP_NOSENDCHANGING) TRACE(" SWP_NOSENDCHANGING");
1154     if(flags & SWP_DEFERERASE) TRACE(" SWP_DEFERERASE");
1155     if(flags & SWP_ASYNCWINDOWPOS) TRACE(" SWP_ASYNCWINDOWPOS");
1156
1157 #define DUMPED_FLAGS \
1158     (SWP_NOSIZE | \
1159     SWP_NOMOVE | \
1160     SWP_NOZORDER | \
1161     SWP_NOREDRAW | \
1162     SWP_NOACTIVATE | \
1163     SWP_FRAMECHANGED | \
1164     SWP_SHOWWINDOW | \
1165     SWP_HIDEWINDOW | \
1166     SWP_NOCOPYBITS | \
1167     SWP_NOOWNERZORDER | \
1168     SWP_NOSENDCHANGING | \
1169     SWP_DEFERERASE | \
1170     SWP_ASYNCWINDOWPOS)
1171
1172     if(flags & ~DUMPED_FLAGS) TRACE(" %08x", flags & ~DUMPED_FLAGS);
1173     TRACE("\n");
1174 #undef DUMPED_FLAGS
1175 }
1176
1177 /***********************************************************************
1178  *              SetWindowPos (USER32.@)
1179  */
1180 BOOL WINAPI SetWindowPos( HWND hwnd, HWND hwndInsertAfter,
1181                           INT x, INT y, INT cx, INT cy, UINT flags )
1182 {
1183     WINDOWPOS winpos;
1184
1185     TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
1186           hwnd, hwndInsertAfter, x, y, cx, cy, flags);
1187     if(TRACE_ON(win)) dump_winpos_flags(flags);
1188
1189     if (is_broadcast(hwnd))
1190     {
1191         SetLastError( ERROR_INVALID_PARAMETER );
1192         return FALSE;
1193     }
1194
1195     winpos.hwnd = WIN_GetFullHandle(hwnd);
1196     winpos.hwndInsertAfter = WIN_GetFullHandle(hwndInsertAfter);
1197     winpos.x = x;
1198     winpos.y = y;
1199     winpos.cx = cx;
1200     winpos.cy = cy;
1201     winpos.flags = flags;
1202     if (WIN_IsCurrentThread( hwnd ))
1203         return USER_Driver->pSetWindowPos( &winpos );
1204
1205     return SendMessageW( winpos.hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)&winpos );
1206 }
1207
1208
1209 /***********************************************************************
1210  *              BeginDeferWindowPos (USER32.@)
1211  */
1212 HDWP WINAPI BeginDeferWindowPos( INT count )
1213 {
1214     HDWP handle;
1215     DWP *pDWP;
1216
1217     TRACE("%d\n", count);
1218
1219     if (count < 0)
1220     {
1221         SetLastError(ERROR_INVALID_PARAMETER);
1222         return 0;
1223     }
1224     /* Windows allows zero count, in which case it allocates context for 8 moves */
1225     if (count == 0) count = 8;
1226
1227     handle = USER_HEAP_ALLOC( sizeof(DWP) + (count-1)*sizeof(WINDOWPOS) );
1228     if (!handle) return 0;
1229     pDWP = (DWP *) USER_HEAP_LIN_ADDR( handle );
1230     pDWP->actualCount    = 0;
1231     pDWP->suggestedCount = count;
1232     pDWP->valid          = TRUE;
1233     pDWP->wMagic         = DWP_MAGIC;
1234     pDWP->hwndParent     = 0;
1235
1236     TRACE("returning hdwp %p\n", handle);
1237     return handle;
1238 }
1239
1240
1241 /***********************************************************************
1242  *              DeferWindowPos (USER32.@)
1243  */
1244 HDWP WINAPI DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter,
1245                                 INT x, INT y, INT cx, INT cy,
1246                                 UINT flags )
1247 {
1248     DWP *pDWP;
1249     int i;
1250     HDWP newhdwp = hdwp,retvalue;
1251
1252     TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
1253           hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
1254
1255     hwnd = WIN_GetFullHandle( hwnd );
1256     if (hwnd == GetDesktopWindow()) return 0;
1257
1258     if (!(pDWP = USER_HEAP_LIN_ADDR( hdwp ))) return 0;
1259
1260     USER_Lock();
1261
1262     for (i = 0; i < pDWP->actualCount; i++)
1263     {
1264         if (pDWP->winPos[i].hwnd == hwnd)
1265         {
1266               /* Merge with the other changes */
1267             if (!(flags & SWP_NOZORDER))
1268             {
1269                 pDWP->winPos[i].hwndInsertAfter = WIN_GetFullHandle(hwndAfter);
1270             }
1271             if (!(flags & SWP_NOMOVE))
1272             {
1273                 pDWP->winPos[i].x = x;
1274                 pDWP->winPos[i].y = y;
1275             }
1276             if (!(flags & SWP_NOSIZE))
1277             {
1278                 pDWP->winPos[i].cx = cx;
1279                 pDWP->winPos[i].cy = cy;
1280             }
1281             pDWP->winPos[i].flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
1282                                                SWP_NOZORDER | SWP_NOREDRAW |
1283                                                SWP_NOACTIVATE | SWP_NOCOPYBITS|
1284                                                SWP_NOOWNERZORDER);
1285             pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
1286                                               SWP_FRAMECHANGED);
1287             retvalue = hdwp;
1288             goto END;
1289         }
1290     }
1291     if (pDWP->actualCount >= pDWP->suggestedCount)
1292     {
1293         newhdwp = USER_HEAP_REALLOC( hdwp,
1294                       sizeof(DWP) + pDWP->suggestedCount*sizeof(WINDOWPOS) );
1295         if (!newhdwp)
1296         {
1297             retvalue = 0;
1298             goto END;
1299         }
1300         pDWP = (DWP *) USER_HEAP_LIN_ADDR( newhdwp );
1301         pDWP->suggestedCount++;
1302     }
1303     pDWP->winPos[pDWP->actualCount].hwnd = hwnd;
1304     pDWP->winPos[pDWP->actualCount].hwndInsertAfter = hwndAfter;
1305     pDWP->winPos[pDWP->actualCount].x = x;
1306     pDWP->winPos[pDWP->actualCount].y = y;
1307     pDWP->winPos[pDWP->actualCount].cx = cx;
1308     pDWP->winPos[pDWP->actualCount].cy = cy;
1309     pDWP->winPos[pDWP->actualCount].flags = flags;
1310     pDWP->actualCount++;
1311     retvalue = newhdwp;
1312 END:
1313     USER_Unlock();
1314     return retvalue;
1315 }
1316
1317
1318 /***********************************************************************
1319  *              EndDeferWindowPos (USER32.@)
1320  */
1321 BOOL WINAPI EndDeferWindowPos( HDWP hdwp )
1322 {
1323     DWP *pDWP;
1324     WINDOWPOS *winpos;
1325     BOOL res = TRUE;
1326     int i;
1327
1328     TRACE("%p\n", hdwp);
1329
1330     pDWP = (DWP *) USER_HEAP_LIN_ADDR( hdwp );
1331     if (!pDWP) return FALSE;
1332     for (i = 0, winpos = pDWP->winPos; i < pDWP->actualCount; i++, winpos++)
1333     {
1334         TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
1335                winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
1336                winpos->cx, winpos->cy, winpos->flags);
1337
1338         if (!(res = USER_Driver->pSetWindowPos( winpos ))) break;
1339     }
1340     USER_HEAP_FREE( hdwp );
1341     return res;
1342 }
1343
1344
1345 /***********************************************************************
1346  *              TileChildWindows (USER.199)
1347  */
1348 void WINAPI TileChildWindows16( HWND16 parent, WORD action )
1349 {
1350     FIXME("(%04x, %d): stub\n", parent, action);
1351 }
1352
1353 /***********************************************************************
1354  *              CascadeChildWindows (USER.198)
1355  */
1356 void WINAPI CascadeChildWindows16( HWND16 parent, WORD action )
1357 {
1358     FIXME("(%04x, %d): stub\n", parent, action);
1359 }