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