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