user32/tests: Fix an intermittent test failure.
[wine] / dlls / user32 / 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 "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winerror.h"
33 #include "wine/server.h"
34 #include "controls.h"
35 #include "user_private.h"
36 #include "win.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(win);
40
41 #define SWP_AGG_NOGEOMETRYCHANGE \
42     (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER)
43 #define SWP_AGG_NOPOSCHANGE \
44     (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
45 #define SWP_AGG_STATUSFLAGS \
46     (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
47
48 #define HAS_DLGFRAME(style,exStyle) \
49     (((exStyle) & WS_EX_DLGMODALFRAME) || \
50      (((style) & WS_DLGFRAME) && !((style) & WS_BORDER)))
51
52 #define HAS_THICKFRAME(style) \
53     (((style) & WS_THICKFRAME) && \
54      !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
55
56 #define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1)
57
58 #define ON_LEFT_BORDER(hit) \
59  (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
60 #define ON_RIGHT_BORDER(hit) \
61  (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
62 #define ON_TOP_BORDER(hit) \
63  (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
64 #define ON_BOTTOM_BORDER(hit) \
65  (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
66
67 #define PLACE_MIN               0x0001
68 #define PLACE_MAX               0x0002
69 #define PLACE_RECT              0x0004
70
71
72 #define DWP_MAGIC  ((INT)('W' | ('P' << 8) | ('O' << 16) | ('S' << 24)))
73
74 typedef struct
75 {
76     INT       actualCount;
77     INT       suggestedCount;
78     BOOL      valid;
79     INT       wMagic;
80     HWND      hwndParent;
81     WINDOWPOS winPos[1];
82 } DWP;
83
84
85 /***********************************************************************
86  *              SwitchToThisWindow (USER32.@)
87  */
88 void WINAPI SwitchToThisWindow( HWND hwnd, BOOL alt_tab )
89 {
90     if (IsIconic( hwnd )) ShowWindow( hwnd, SW_RESTORE );
91     else BringWindowToTop( hwnd );
92 }
93
94
95 /***********************************************************************
96  *              GetWindowRect (USER32.@)
97  */
98 BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect )
99 {
100     BOOL ret = WIN_GetRectangles( hwnd, rect, NULL );
101     if (ret)
102     {
103         MapWindowPoints( GetAncestor( hwnd, GA_PARENT ), 0, (POINT *)rect, 2 );
104         TRACE( "hwnd %p (%s)\n", hwnd, wine_dbgstr_rect(rect) );
105     }
106     return ret;
107 }
108
109
110 /***********************************************************************
111  *              GetWindowRgn (USER32.@)
112  */
113 int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn )
114 {
115     int nRet = ERROR;
116     NTSTATUS status;
117     HRGN win_rgn = 0;
118     RGNDATA *data;
119     size_t size = 256;
120
121     do
122     {
123         if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 )))
124         {
125             SetLastError( ERROR_OUTOFMEMORY );
126             return ERROR;
127         }
128         SERVER_START_REQ( get_window_region )
129         {
130             req->window = wine_server_user_handle( hwnd );
131             wine_server_set_reply( req, data->Buffer, size );
132             if (!(status = wine_server_call( req )))
133             {
134                 size_t reply_size = wine_server_reply_size( reply );
135                 if (reply_size)
136                 {
137                     data->rdh.dwSize   = sizeof(data->rdh);
138                     data->rdh.iType    = RDH_RECTANGLES;
139                     data->rdh.nCount   = reply_size / sizeof(RECT);
140                     data->rdh.nRgnSize = reply_size;
141                     win_rgn = ExtCreateRegion( NULL, size, data );
142                 }
143             }
144             else size = reply->total_size;
145         }
146         SERVER_END_REQ;
147         HeapFree( GetProcessHeap(), 0, data );
148     } while (status == STATUS_BUFFER_OVERFLOW);
149
150     if (status) SetLastError( RtlNtStatusToDosError(status) );
151     else if (win_rgn)
152     {
153         nRet = CombineRgn( hrgn, win_rgn, 0, RGN_COPY );
154         DeleteObject( win_rgn );
155     }
156     return nRet;
157 }
158
159 /***********************************************************************
160  *              GetWindowRgnBox (USER32.@)
161  */
162 int WINAPI GetWindowRgnBox( HWND hwnd, LPRECT prect )
163 {
164     int ret = ERROR;
165     HRGN hrgn;
166
167     if (!prect)
168         return ERROR;
169
170     if ((hrgn = CreateRectRgn(0, 0, 0, 0)))
171     {
172         if ((ret = GetWindowRgn( hwnd, hrgn )) != ERROR )
173             ret = GetRgnBox( hrgn, prect );
174         DeleteObject(hrgn);
175     }
176
177     return ret;
178 }
179
180 /***********************************************************************
181  *              SetWindowRgn (USER32.@)
182  */
183 int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw )
184 {
185     static const RECT empty_rect;
186     BOOL ret;
187
188     if (hrgn)
189     {
190         RGNDATA *data;
191         DWORD size;
192
193         if (!(size = GetRegionData( hrgn, 0, NULL ))) return FALSE;
194         if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
195         if (!GetRegionData( hrgn, size, data ))
196         {
197             HeapFree( GetProcessHeap(), 0, data );
198             return FALSE;
199         }
200         SERVER_START_REQ( set_window_region )
201         {
202             req->window = wine_server_user_handle( hwnd );
203             req->redraw = (bRedraw != 0);
204             if (data->rdh.nCount)
205                 wine_server_add_data( req, data->Buffer, data->rdh.nCount * sizeof(RECT) );
206             else
207                 wine_server_add_data( req, &empty_rect, sizeof(empty_rect) );
208             ret = !wine_server_call_err( req );
209         }
210         SERVER_END_REQ;
211         HeapFree( GetProcessHeap(), 0, data );
212     }
213     else  /* clear existing region */
214     {
215         SERVER_START_REQ( set_window_region )
216         {
217             req->window = wine_server_user_handle( hwnd );
218             req->redraw = (bRedraw != 0);
219             ret = !wine_server_call_err( req );
220         }
221         SERVER_END_REQ;
222     }
223
224     if (ret) ret = USER_Driver->pSetWindowRgn( hwnd, hrgn, bRedraw );
225
226     if (ret)
227     {
228         UINT swp_flags = SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE;
229         if (!bRedraw) swp_flags |= SWP_NOREDRAW;
230         SetWindowPos( hwnd, 0, 0, 0, 0, 0, swp_flags );
231         invalidate_dce( hwnd, NULL );
232     }
233     return ret;
234 }
235
236
237 /***********************************************************************
238  *              GetClientRect (USER32.@)
239  */
240 BOOL WINAPI GetClientRect( HWND hwnd, LPRECT rect )
241 {
242     BOOL ret;
243
244     if ((ret = WIN_GetRectangles( hwnd, NULL, rect )))
245     {
246         rect->right -= rect->left;
247         rect->bottom -= rect->top;
248         rect->left = rect->top = 0;
249     }
250     return ret;
251 }
252
253
254 /*******************************************************************
255  *              ClientToScreen (USER32.@)
256  */
257 BOOL WINAPI ClientToScreen( HWND hwnd, LPPOINT lppnt )
258 {
259     MapWindowPoints( hwnd, 0, lppnt, 1 );
260     return TRUE;
261 }
262
263
264 /*******************************************************************
265  *              ScreenToClient (USER32.@)
266  */
267 BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
268 {
269     MapWindowPoints( 0, hwnd, lppnt, 1 );
270     return TRUE;
271 }
272
273
274 /***********************************************************************
275  *           list_children_from_point
276  *
277  * Get the list of children that can contain point from the server.
278  * Point is in screen coordinates.
279  * Returned list must be freed by caller.
280  */
281 static HWND *list_children_from_point( HWND hwnd, POINT pt )
282 {
283     HWND *list;
284     int i, size = 128;
285
286     for (;;)
287     {
288         int count = 0;
289
290         if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
291
292         SERVER_START_REQ( get_window_children_from_point )
293         {
294             req->parent = wine_server_user_handle( hwnd );
295             req->x = pt.x;
296             req->y = pt.y;
297             wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
298             if (!wine_server_call( req )) count = reply->count;
299         }
300         SERVER_END_REQ;
301         if (count && count < size)
302         {
303             /* start from the end since HWND is potentially larger than user_handle_t */
304             for (i = count - 1; i >= 0; i--)
305                 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
306             list[count] = 0;
307             return list;
308         }
309         HeapFree( GetProcessHeap(), 0, list );
310         if (!count) break;
311         size = count + 1;  /* restart with a large enough buffer */
312     }
313     return NULL;
314 }
315
316
317 /***********************************************************************
318  *           WINPOS_WindowFromPoint
319  *
320  * Find the window and hittest for a given point.
321  */
322 HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
323 {
324     int i, res;
325     HWND ret, *list;
326
327     if (!hwndScope) hwndScope = GetDesktopWindow();
328
329     *hittest = HTNOWHERE;
330
331     if (!(list = list_children_from_point( hwndScope, pt ))) return 0;
332
333     /* now determine the hittest */
334
335     for (i = 0; list[i]; i++)
336     {
337         LONG style = GetWindowLongW( list[i], GWL_STYLE );
338
339         /* If window is minimized or disabled, return at once */
340         if (style & WS_MINIMIZE)
341         {
342             *hittest = HTCAPTION;
343             break;
344         }
345         if (style & WS_DISABLED)
346         {
347             *hittest = HTERROR;
348             break;
349         }
350         /* Send WM_NCCHITTEST (if same thread) */
351         if (!WIN_IsCurrentThread( list[i] ))
352         {
353             *hittest = HTCLIENT;
354             break;
355         }
356         res = SendMessageW( list[i], WM_NCHITTEST, 0, MAKELONG(pt.x,pt.y) );
357         if (res != HTTRANSPARENT)
358         {
359             *hittest = res;  /* Found the window */
360             break;
361         }
362         /* continue search with next window in z-order */
363     }
364     ret = list[i];
365     HeapFree( GetProcessHeap(), 0, list );
366     TRACE( "scope %p (%d,%d) returning %p\n", hwndScope, pt.x, pt.y, ret );
367     return ret;
368 }
369
370
371 /*******************************************************************
372  *              WindowFromPoint (USER32.@)
373  */
374 HWND WINAPI WindowFromPoint( POINT pt )
375 {
376     INT hittest;
377     return WINPOS_WindowFromPoint( 0, pt, &hittest );
378 }
379
380
381 /*******************************************************************
382  *              ChildWindowFromPoint (USER32.@)
383  */
384 HWND WINAPI ChildWindowFromPoint( HWND hwndParent, POINT pt )
385 {
386     return ChildWindowFromPointEx( hwndParent, pt, CWP_ALL );
387 }
388
389 /*******************************************************************
390  *              RealChildWindowFromPoint (USER32.@)
391  */
392 HWND WINAPI RealChildWindowFromPoint( HWND hwndParent, POINT pt )
393 {
394     return ChildWindowFromPointEx( hwndParent, pt, CWP_SKIPTRANSPARENT );
395 }
396
397 /*******************************************************************
398  *              ChildWindowFromPointEx (USER32.@)
399  */
400 HWND WINAPI ChildWindowFromPointEx( HWND hwndParent, POINT pt, UINT uFlags)
401 {
402     /* pt is in the client coordinates */
403     HWND *list;
404     int i;
405     RECT rect;
406     HWND retvalue;
407
408     GetClientRect( hwndParent, &rect );
409     if (!PtInRect( &rect, pt )) return 0;
410     if (!(list = WIN_ListChildren( hwndParent ))) return hwndParent;
411
412     for (i = 0; list[i]; i++)
413     {
414         if (!WIN_GetRectangles( list[i], &rect, NULL )) continue;
415         if (!PtInRect( &rect, pt )) continue;
416         if (uFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
417         {
418             LONG style = GetWindowLongW( list[i], GWL_STYLE );
419             if ((uFlags & CWP_SKIPINVISIBLE) && !(style & WS_VISIBLE)) continue;
420             if ((uFlags & CWP_SKIPDISABLED) && (style & WS_DISABLED)) continue;
421         }
422         if (uFlags & CWP_SKIPTRANSPARENT)
423         {
424             if (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TRANSPARENT) continue;
425         }
426         break;
427     }
428     retvalue = list[i];
429     HeapFree( GetProcessHeap(), 0, list );
430     if (!retvalue) retvalue = hwndParent;
431     return retvalue;
432 }
433
434
435 /*******************************************************************
436  *         WINPOS_GetWinOffset
437  *
438  * Calculate the offset between the origin of the two windows. Used
439  * to implement MapWindowPoints.
440  */
441 static void WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, POINT *offset )
442 {
443     WND * wndPtr;
444
445     offset->x = offset->y = 0;
446
447     /* Translate source window origin to screen coords */
448     if (hwndFrom)
449     {
450         HWND hwnd = hwndFrom;
451
452         while (hwnd)
453         {
454             if (hwnd == hwndTo) return;
455             if (!(wndPtr = WIN_GetPtr( hwnd )))
456             {
457                 ERR( "bad hwndFrom = %p\n", hwnd );
458                 return;
459             }
460             if (wndPtr == WND_DESKTOP) break;
461             if (wndPtr == WND_OTHER_PROCESS) goto other_process;
462             if (wndPtr->parent)
463             {
464                 offset->x += wndPtr->rectClient.left;
465                 offset->y += wndPtr->rectClient.top;
466             }
467             hwnd = wndPtr->parent;
468             WIN_ReleasePtr( wndPtr );
469         }
470     }
471
472     /* Translate origin to destination window coords */
473     if (hwndTo)
474     {
475         HWND hwnd = hwndTo;
476
477         while (hwnd)
478         {
479             if (!(wndPtr = WIN_GetPtr( hwnd )))
480             {
481                 ERR( "bad hwndTo = %p\n", hwnd );
482                 return;
483             }
484             if (wndPtr == WND_DESKTOP) break;
485             if (wndPtr == WND_OTHER_PROCESS) goto other_process;
486             if (wndPtr->parent)
487             {
488                 offset->x -= wndPtr->rectClient.left;
489                 offset->y -= wndPtr->rectClient.top;
490             }
491             hwnd = wndPtr->parent;
492             WIN_ReleasePtr( wndPtr );
493         }
494     }
495     return;
496
497  other_process:  /* one of the parents may belong to another process, do it the hard way */
498     offset->x = offset->y = 0;
499     SERVER_START_REQ( get_windows_offset )
500     {
501         req->from = wine_server_user_handle( hwndFrom );
502         req->to   = wine_server_user_handle( hwndTo );
503         if (!wine_server_call( req ))
504         {
505             offset->x = reply->x;
506             offset->y = reply->y;
507         }
508     }
509     SERVER_END_REQ;
510 }
511
512
513 /*******************************************************************
514  *              MapWindowPoints (USER.258)
515  */
516 void WINAPI MapWindowPoints16( HWND16 hwndFrom, HWND16 hwndTo,
517                                LPPOINT16 lppt, UINT16 count )
518 {
519     POINT offset;
520
521     WINPOS_GetWinOffset( WIN_Handle32(hwndFrom), WIN_Handle32(hwndTo), &offset );
522     while (count--)
523     {
524         lppt->x += offset.x;
525         lppt->y += offset.y;
526         lppt++;
527     }
528 }
529
530
531 /*******************************************************************
532  *              MapWindowPoints (USER32.@)
533  */
534 INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT count )
535 {
536     POINT offset;
537
538     WINPOS_GetWinOffset( hwndFrom, hwndTo, &offset );
539     while (count--)
540     {
541         lppt->x += offset.x;
542         lppt->y += offset.y;
543         lppt++;
544     }
545     return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) );
546 }
547
548
549 /***********************************************************************
550  *              IsIconic (USER32.@)
551  */
552 BOOL WINAPI IsIconic(HWND hWnd)
553 {
554     return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MINIMIZE) != 0;
555 }
556
557
558 /***********************************************************************
559  *              IsZoomed (USER32.@)
560  */
561 BOOL WINAPI IsZoomed(HWND hWnd)
562 {
563     return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MAXIMIZE) != 0;
564 }
565
566
567 /*******************************************************************
568  *              AllowSetForegroundWindow (USER32.@)
569  */
570 BOOL WINAPI AllowSetForegroundWindow( DWORD procid )
571 {
572     /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
573      * implemented, then fix this function. */
574     return TRUE;
575 }
576
577
578 /*******************************************************************
579  *              LockSetForegroundWindow (USER32.@)
580  */
581 BOOL WINAPI LockSetForegroundWindow( UINT lockcode )
582 {
583     /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
584      * implemented, then fix this function. */
585     return TRUE;
586 }
587
588
589 /***********************************************************************
590  *              BringWindowToTop (USER32.@)
591  */
592 BOOL WINAPI BringWindowToTop( HWND hwnd )
593 {
594     return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
595 }
596
597
598 /***********************************************************************
599  *              MoveWindow (USER32.@)
600  */
601 BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
602                             BOOL repaint )
603 {
604     int flags = SWP_NOZORDER | SWP_NOACTIVATE;
605     if (!repaint) flags |= SWP_NOREDRAW;
606     TRACE("%p %d,%d %dx%d %d\n", hwnd, x, y, cx, cy, repaint );
607     return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
608 }
609
610
611 /***********************************************************************
612  *           WINPOS_RedrawIconTitle
613  */
614 BOOL WINPOS_RedrawIconTitle( HWND hWnd )
615 {
616     HWND icon_title = 0;
617     WND *win = WIN_GetPtr( hWnd );
618
619     if (win && win != WND_OTHER_PROCESS && win != WND_DESKTOP)
620     {
621         icon_title = win->icon_title;
622         WIN_ReleasePtr( win );
623     }
624     if (!icon_title) return FALSE;
625     SendMessageW( icon_title, WM_SHOWWINDOW, TRUE, 0 );
626     InvalidateRect( icon_title, NULL, TRUE );
627     return TRUE;
628 }
629
630 /***********************************************************************
631  *           WINPOS_ShowIconTitle
632  */
633 static BOOL WINPOS_ShowIconTitle( HWND hwnd, BOOL bShow )
634 {
635     if (!GetPropA( hwnd, "__wine_x11_managed" ))
636     {
637         WND *win = WIN_GetPtr( hwnd );
638         HWND title = 0;
639
640         TRACE("%p %i\n", hwnd, (bShow != 0) );
641
642         if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP) return FALSE;
643         title = win->icon_title;
644         WIN_ReleasePtr( win );
645
646         if( bShow )
647         {
648             if (!title)
649             {
650                 title = ICONTITLE_Create( hwnd );
651                 if (!(win = WIN_GetPtr( hwnd )) || win == WND_OTHER_PROCESS)
652                 {
653                     DestroyWindow( title );
654                     return FALSE;
655                 }
656                 win->icon_title = title;
657                 WIN_ReleasePtr( win );
658             }
659             if (!IsWindowVisible(title))
660             {
661                 SendMessageW( title, WM_SHOWWINDOW, TRUE, 0 );
662                 SetWindowPos( title, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
663                               SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW );
664             }
665         }
666         else if (title) ShowWindow( title, SW_HIDE );
667     }
668     return FALSE;
669 }
670
671 /*******************************************************************
672  *           WINPOS_GetMinMaxInfo
673  *
674  * Get the minimized and maximized information for a window.
675  */
676 void WINPOS_GetMinMaxInfo( HWND hwnd, POINT *maxSize, POINT *maxPos,
677                            POINT *minTrack, POINT *maxTrack )
678 {
679     MINMAXINFO MinMax;
680     HMONITOR monitor;
681     INT xinc, yinc;
682     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
683     LONG adjustedStyle;
684     LONG exstyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
685     RECT rc;
686     WND *win;
687
688     /* Compute default values */
689
690     GetWindowRect(hwnd, &rc);
691     MinMax.ptReserved.x = rc.left;
692     MinMax.ptReserved.y = rc.top;
693
694     if ((style & WS_CAPTION) == WS_CAPTION)
695         adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
696     else
697         adjustedStyle = style;
698
699     GetClientRect(GetAncestor(hwnd,GA_PARENT), &rc);
700     AdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
701
702     xinc = -rc.left;
703     yinc = -rc.top;
704
705     MinMax.ptMaxSize.x = rc.right - rc.left;
706     MinMax.ptMaxSize.y = rc.bottom - rc.top;
707     if (style & (WS_DLGFRAME | WS_BORDER))
708     {
709         MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
710         MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
711     }
712     else
713     {
714         MinMax.ptMinTrackSize.x = 2 * xinc;
715         MinMax.ptMinTrackSize.y = 2 * yinc;
716     }
717     MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
718     MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
719     MinMax.ptMaxPosition.x = -xinc;
720     MinMax.ptMaxPosition.y = -yinc;
721
722     if ((win = WIN_GetPtr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS)
723     {
724         if (!EMPTYPOINT(win->max_pos)) MinMax.ptMaxPosition = win->max_pos;
725         WIN_ReleasePtr( win );
726     }
727
728     SendMessageW( hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
729
730     /* if the app didn't change the values, adapt them for the current monitor */
731
732     if ((monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY )))
733     {
734         RECT rc_work;
735         MONITORINFO mon_info;
736
737         mon_info.cbSize = sizeof(mon_info);
738         GetMonitorInfoW( monitor, &mon_info );
739
740         rc_work = mon_info.rcMonitor;
741
742         if (style & WS_MAXIMIZEBOX)
743         {
744             if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
745                 rc_work = mon_info.rcWork;
746         }
747
748         if (MinMax.ptMaxSize.x == GetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
749             MinMax.ptMaxSize.y == GetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
750         {
751             MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
752             MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
753         }
754         if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
755         {
756             MinMax.ptMaxPosition.x = rc_work.left - xinc;
757             MinMax.ptMaxPosition.y = rc_work.top - yinc;
758         }
759     }
760
761       /* Some sanity checks */
762
763     TRACE("%d %d / %d %d / %d %d / %d %d\n",
764                       MinMax.ptMaxSize.x, MinMax.ptMaxSize.y,
765                       MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y,
766                       MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y,
767                       MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y);
768     MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x,
769                                    MinMax.ptMinTrackSize.x );
770     MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y,
771                                    MinMax.ptMinTrackSize.y );
772
773     if (maxSize) *maxSize = MinMax.ptMaxSize;
774     if (maxPos) *maxPos = MinMax.ptMaxPosition;
775     if (minTrack) *minTrack = MinMax.ptMinTrackSize;
776     if (maxTrack) *maxTrack = MinMax.ptMaxTrackSize;
777 }
778
779
780 /***********************************************************************
781  *           WINPOS_FindIconPos
782  *
783  * Find a suitable place for an iconic window.
784  */
785 static POINT WINPOS_FindIconPos( HWND hwnd, POINT pt )
786 {
787     RECT rect, rectParent;
788     HWND parent, child;
789     HRGN hrgn, tmp;
790     int xspacing, yspacing;
791
792     parent = GetAncestor( hwnd, GA_PARENT );
793     GetClientRect( parent, &rectParent );
794     if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics(SM_CXICON) < rectParent.right) &&
795         (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics(SM_CYICON) < rectParent.bottom))
796         return pt;  /* The icon already has a suitable position */
797
798     xspacing = GetSystemMetrics(SM_CXICONSPACING);
799     yspacing = GetSystemMetrics(SM_CYICONSPACING);
800
801     /* Check if another icon already occupies this spot */
802     /* FIXME: this is completely inefficient */
803
804     hrgn = CreateRectRgn( 0, 0, 0, 0 );
805     tmp = CreateRectRgn( 0, 0, 0, 0 );
806     for (child = GetWindow( parent, GW_HWNDFIRST ); child; child = GetWindow( child, GW_HWNDNEXT ))
807     {
808         WND *childPtr;
809         if (child == hwnd) continue;
810         if ((GetWindowLongW( child, GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE))
811             continue;
812         if (!(childPtr = WIN_GetPtr( child )) || childPtr == WND_OTHER_PROCESS)
813             continue;
814         SetRectRgn( tmp, childPtr->rectWindow.left, childPtr->rectWindow.top,
815                     childPtr->rectWindow.right, childPtr->rectWindow.bottom );
816         CombineRgn( hrgn, hrgn, tmp, RGN_OR );
817         WIN_ReleasePtr( childPtr );
818     }
819     DeleteObject( tmp );
820
821     for (rect.bottom = rectParent.bottom; rect.bottom >= yspacing; rect.bottom -= yspacing)
822     {
823         for (rect.left = rectParent.left; rect.left <= rectParent.right - xspacing; rect.left += xspacing)
824         {
825             rect.right = rect.left + xspacing;
826             rect.top = rect.bottom - yspacing;
827             if (!RectInRegion( hrgn, &rect ))
828             {
829                 /* No window was found, so it's OK for us */
830                 pt.x = rect.left + (xspacing - GetSystemMetrics(SM_CXICON)) / 2;
831                 pt.y = rect.top + (yspacing - GetSystemMetrics(SM_CYICON)) / 2;
832                 DeleteObject( hrgn );
833                 return pt;
834             }
835         }
836     }
837     DeleteObject( hrgn );
838     pt.x = pt.y = 0;
839     return pt;
840 }
841
842
843 /***********************************************************************
844  *           WINPOS_MinMaximize
845  */
846 UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
847 {
848     WND *wndPtr;
849     UINT swpFlags = 0;
850     POINT size;
851     LONG old_style;
852     WINDOWPLACEMENT wpl;
853
854     TRACE("%p %u\n", hwnd, cmd );
855
856     wpl.length = sizeof(wpl);
857     GetWindowPlacement( hwnd, &wpl );
858
859     if (HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd, TRUE ))
860         return SWP_NOSIZE | SWP_NOMOVE;
861
862     if (IsIconic( hwnd ))
863     {
864         switch (cmd)
865         {
866         case SW_SHOWMINNOACTIVE:
867         case SW_SHOWMINIMIZED:
868         case SW_FORCEMINIMIZE:
869         case SW_MINIMIZE:
870             return SWP_NOSIZE | SWP_NOMOVE;
871         }
872         if (!SendMessageW( hwnd, WM_QUERYOPEN, 0, 0 )) return SWP_NOSIZE | SWP_NOMOVE;
873         swpFlags |= SWP_NOCOPYBITS;
874     }
875
876     switch( cmd )
877     {
878     case SW_SHOWMINNOACTIVE:
879     case SW_SHOWMINIMIZED:
880     case SW_FORCEMINIMIZE:
881     case SW_MINIMIZE:
882         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
883         if( wndPtr->dwStyle & WS_MAXIMIZE) wndPtr->flags |= WIN_RESTORE_MAX;
884         else wndPtr->flags &= ~WIN_RESTORE_MAX;
885         WIN_ReleasePtr( wndPtr );
886
887         old_style = WIN_SetStyle( hwnd, WS_MINIMIZE, WS_MAXIMIZE );
888
889         wpl.ptMinPosition = WINPOS_FindIconPos( hwnd, wpl.ptMinPosition );
890
891         if (!(old_style & WS_MINIMIZE)) swpFlags |= SWP_STATECHANGED;
892         SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
893                  wpl.ptMinPosition.x + GetSystemMetrics(SM_CXICON),
894                  wpl.ptMinPosition.y + GetSystemMetrics(SM_CYICON) );
895         swpFlags |= SWP_NOCOPYBITS;
896         break;
897
898     case SW_MAXIMIZE:
899         old_style = GetWindowLongW( hwnd, GWL_STYLE );
900         if ((old_style & WS_MAXIMIZE) && (old_style & WS_VISIBLE)) return SWP_NOSIZE | SWP_NOMOVE;
901
902         WINPOS_GetMinMaxInfo( hwnd, &size, &wpl.ptMaxPosition, NULL, NULL );
903
904         old_style = WIN_SetStyle( hwnd, WS_MAXIMIZE, WS_MINIMIZE );
905         if (old_style & WS_MINIMIZE) WINPOS_ShowIconTitle( hwnd, FALSE );
906
907         if (!(old_style & WS_MAXIMIZE)) swpFlags |= SWP_STATECHANGED;
908         SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
909                  wpl.ptMaxPosition.x +  size.x, wpl.ptMaxPosition.y + size.y );
910         break;
911
912     case SW_SHOWNOACTIVATE:
913     case SW_SHOWNORMAL:
914     case SW_RESTORE:
915         old_style = WIN_SetStyle( hwnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
916         if (old_style & WS_MINIMIZE)
917         {
918             BOOL restore_max;
919
920             WINPOS_ShowIconTitle( hwnd, FALSE );
921
922             if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
923             restore_max = (wndPtr->flags & WIN_RESTORE_MAX) != 0;
924             WIN_ReleasePtr( wndPtr );
925             if (restore_max)
926             {
927                 /* Restore to maximized position */
928                 WINPOS_GetMinMaxInfo( hwnd, &size, &wpl.ptMaxPosition, NULL, NULL);
929                 WIN_SetStyle( hwnd, WS_MAXIMIZE, 0 );
930                 swpFlags |= SWP_STATECHANGED;
931                 SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
932                          wpl.ptMaxPosition.x + size.x, wpl.ptMaxPosition.y + size.y );
933                 break;
934             }
935         }
936         else if (!(old_style & WS_MAXIMIZE)) break;
937
938         swpFlags |= SWP_STATECHANGED;
939
940         /* Restore to normal position */
941
942         *rect = wpl.rcNormalPosition;
943         break;
944     }
945
946     return swpFlags;
947 }
948
949
950 /***********************************************************************
951  *              show_window
952  *
953  * Implementation of ShowWindow and ShowWindowAsync.
954  */
955 static BOOL show_window( HWND hwnd, INT cmd )
956 {
957     WND *wndPtr;
958     HWND parent;
959     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
960     BOOL wasVisible = (style & WS_VISIBLE) != 0;
961     BOOL showFlag = TRUE;
962     RECT newPos = {0, 0, 0, 0};
963     UINT swp = 0;
964
965     TRACE("hwnd=%p, cmd=%d, wasVisible %d\n", hwnd, cmd, wasVisible);
966
967     switch(cmd)
968     {
969         case SW_HIDE:
970             if (!wasVisible) return FALSE;
971             showFlag = FALSE;
972             swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
973             if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
974             break;
975
976         case SW_SHOWMINNOACTIVE:
977         case SW_MINIMIZE:
978         case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
979             swp |= SWP_NOACTIVATE | SWP_NOZORDER;
980             /* fall through */
981         case SW_SHOWMINIMIZED:
982             swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
983             swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
984             if ((style & WS_MINIMIZE) && wasVisible) return TRUE;
985             break;
986
987         case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
988             if (!wasVisible) swp |= SWP_SHOWWINDOW;
989             swp |= SWP_FRAMECHANGED;
990             swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
991             if ((style & WS_MAXIMIZE) && wasVisible) return TRUE;
992             break;
993
994         case SW_SHOWNA:
995             swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
996             if (style & WS_CHILD) swp |= SWP_NOZORDER;
997             break;
998         case SW_SHOW:
999             if (wasVisible) return TRUE;
1000             swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1001             if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1002             break;
1003
1004         case SW_SHOWNOACTIVATE:
1005             swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1006             /* fall through */
1007         case SW_RESTORE:
1008             /* fall through */
1009         case SW_SHOWNORMAL:  /* same as SW_NORMAL: */
1010         case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1011             if (!wasVisible) swp |= SWP_SHOWWINDOW;
1012             if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1013             {
1014                 swp |= SWP_FRAMECHANGED;
1015                 swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
1016             }
1017             else
1018             {
1019                 if (wasVisible) return TRUE;
1020                 swp |= SWP_NOSIZE | SWP_NOMOVE;
1021             }
1022             if (style & WS_CHILD && !(swp & SWP_STATECHANGED)) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1023             break;
1024         default:
1025             return wasVisible;
1026     }
1027
1028     if ((showFlag != wasVisible || cmd == SW_SHOWNA) && cmd != SW_SHOWMAXIMIZED && !(swp & SWP_STATECHANGED))
1029     {
1030         SendMessageW( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1031         if (!IsWindow( hwnd )) return wasVisible;
1032     }
1033
1034     swp = USER_Driver->pShowWindow( hwnd, cmd, &newPos, swp );
1035
1036     parent = GetAncestor( hwnd, GA_PARENT );
1037     if (parent && !IsWindowVisible( parent ) && !(swp & SWP_STATECHANGED))
1038     {
1039         /* if parent is not visible simply toggle WS_VISIBLE and return */
1040         if (showFlag) WIN_SetStyle( hwnd, WS_VISIBLE, 0 );
1041         else WIN_SetStyle( hwnd, 0, WS_VISIBLE );
1042     }
1043     else
1044         SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
1045                       newPos.right - newPos.left, newPos.bottom - newPos.top, swp );
1046
1047     if (cmd == SW_HIDE)
1048     {
1049         HWND hFocus;
1050
1051         WINPOS_ShowIconTitle( hwnd, FALSE );
1052
1053         /* FIXME: This will cause the window to be activated irrespective
1054          * of whether it is owned by the same thread. Has to be done
1055          * asynchronously.
1056          */
1057
1058         if (hwnd == GetActiveWindow())
1059             WINPOS_ActivateOtherWindow(hwnd);
1060
1061         /* Revert focus to parent */
1062         hFocus = GetFocus();
1063         if (hwnd == hFocus || IsChild(hwnd, hFocus))
1064         {
1065             HWND parent = GetAncestor(hwnd, GA_PARENT);
1066             if (parent == GetDesktopWindow()) parent = 0;
1067             SetFocus(parent);
1068         }
1069         return wasVisible;
1070     }
1071
1072     if (IsIconic(hwnd)) WINPOS_ShowIconTitle( hwnd, TRUE );
1073
1074     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return wasVisible;
1075
1076     if (wndPtr->flags & WIN_NEED_SIZE)
1077     {
1078         /* should happen only in CreateWindowEx() */
1079         int wParam = SIZE_RESTORED;
1080         RECT client = wndPtr->rectClient;
1081         LPARAM lparam = MAKELONG( client.right - client.left, client.bottom - client.top );
1082
1083         wndPtr->flags &= ~WIN_NEED_SIZE;
1084         if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
1085         else if (wndPtr->dwStyle & WS_MINIMIZE)
1086         {
1087             wParam = SIZE_MINIMIZED;
1088             lparam = 0;
1089         }
1090         WIN_ReleasePtr( wndPtr );
1091
1092         SendMessageW( hwnd, WM_SIZE, wParam, lparam );
1093         SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( client.left, client.top ));
1094     }
1095     else WIN_ReleasePtr( wndPtr );
1096
1097     /* if previous state was minimized Windows sets focus to the window */
1098     if (style & WS_MINIMIZE) SetFocus( hwnd );
1099
1100     return wasVisible;
1101 }
1102
1103
1104 /***********************************************************************
1105  *              ShowWindowAsync (USER32.@)
1106  *
1107  * doesn't wait; returns immediately.
1108  * used by threads to toggle windows in other (possibly hanging) threads
1109  */
1110 BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd )
1111 {
1112     HWND full_handle;
1113
1114     if (is_broadcast(hwnd))
1115     {
1116         SetLastError( ERROR_INVALID_PARAMETER );
1117         return FALSE;
1118     }
1119
1120     if ((full_handle = WIN_IsCurrentThread( hwnd )))
1121         return show_window( full_handle, cmd );
1122
1123     return SendNotifyMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
1124 }
1125
1126
1127 /***********************************************************************
1128  *              ShowWindow (USER32.@)
1129  */
1130 BOOL WINAPI ShowWindow( HWND hwnd, INT cmd )
1131 {
1132     HWND full_handle;
1133
1134     if (is_broadcast(hwnd))
1135     {
1136         SetLastError( ERROR_INVALID_PARAMETER );
1137         return FALSE;
1138     }
1139     if ((full_handle = WIN_IsCurrentThread( hwnd )))
1140         return show_window( full_handle, cmd );
1141
1142     return SendMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
1143 }
1144
1145
1146 /***********************************************************************
1147  *              GetInternalWindowPos (USER32.@)
1148  */
1149 UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd,
1150                                       LPPOINT ptIcon )
1151 {
1152     WINDOWPLACEMENT wndpl;
1153     if (GetWindowPlacement( hwnd, &wndpl ))
1154     {
1155         if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
1156         if (ptIcon)  *ptIcon = wndpl.ptMinPosition;
1157         return wndpl.showCmd;
1158     }
1159     return 0;
1160 }
1161
1162
1163 /***********************************************************************
1164  *              GetWindowPlacement (USER32.@)
1165  *
1166  * Win95:
1167  * Fails if wndpl->length of Win95 (!) apps is invalid.
1168  */
1169 BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
1170 {
1171     WND *pWnd = WIN_GetPtr( hwnd );
1172
1173     if (!pWnd) return FALSE;
1174
1175     if (pWnd == WND_DESKTOP)
1176     {
1177         wndpl->length  = sizeof(*wndpl);
1178         wndpl->showCmd = SW_SHOWNORMAL;
1179         wndpl->flags = 0;
1180         wndpl->ptMinPosition.x = -1;
1181         wndpl->ptMinPosition.y = -1;
1182         wndpl->ptMaxPosition.x = -1;
1183         wndpl->ptMaxPosition.y = -1;
1184         GetWindowRect( hwnd, &wndpl->rcNormalPosition );
1185         return TRUE;
1186     }
1187     if (pWnd == WND_OTHER_PROCESS)
1188     {
1189         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
1190         return FALSE;
1191     }
1192
1193     /* update the placement according to the current style */
1194     if (pWnd->dwStyle & WS_MINIMIZE)
1195     {
1196         pWnd->min_pos.x = pWnd->rectWindow.left;
1197         pWnd->min_pos.y = pWnd->rectWindow.top;
1198     }
1199     else if (pWnd->dwStyle & WS_MAXIMIZE)
1200     {
1201         pWnd->max_pos.x = pWnd->rectWindow.left;
1202         pWnd->max_pos.y = pWnd->rectWindow.top;
1203     }
1204     else
1205     {
1206         pWnd->normal_rect = pWnd->rectWindow;
1207     }
1208
1209     wndpl->length  = sizeof(*wndpl);
1210     if( pWnd->dwStyle & WS_MINIMIZE )
1211         wndpl->showCmd = SW_SHOWMINIMIZED;
1212     else
1213         wndpl->showCmd = ( pWnd->dwStyle & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
1214     if( pWnd->flags & WIN_RESTORE_MAX )
1215         wndpl->flags = WPF_RESTORETOMAXIMIZED;
1216     else
1217         wndpl->flags = 0;
1218     wndpl->ptMinPosition    = pWnd->min_pos;
1219     wndpl->ptMaxPosition    = pWnd->max_pos;
1220     wndpl->rcNormalPosition = pWnd->normal_rect;
1221     WIN_ReleasePtr( pWnd );
1222
1223     TRACE( "%p: returning min %d,%d max %d,%d normal %s\n",
1224            hwnd, wndpl->ptMinPosition.x, wndpl->ptMinPosition.y,
1225            wndpl->ptMaxPosition.x, wndpl->ptMaxPosition.y,
1226            wine_dbgstr_rect(&wndpl->rcNormalPosition) );
1227     return TRUE;
1228 }
1229
1230 /* make sure the specified rect is visible on screen */
1231 static void make_rect_onscreen( RECT *rect )
1232 {
1233     MONITORINFO info;
1234     HMONITOR monitor = MonitorFromRect( rect, MONITOR_DEFAULTTONEAREST );
1235
1236     info.cbSize = sizeof(info);
1237     if (!monitor || !GetMonitorInfoW( monitor, &info )) return;
1238     /* FIXME: map coordinates from rcWork to rcMonitor */
1239     if (rect->right <= info.rcWork.left)
1240     {
1241         rect->right += info.rcWork.left - rect->left;
1242         rect->left = info.rcWork.left;
1243     }
1244     else if (rect->left >= info.rcWork.right)
1245     {
1246         rect->left += info.rcWork.right - rect->right;
1247         rect->right = info.rcWork.right;
1248     }
1249     if (rect->bottom <= info.rcWork.top)
1250     {
1251         rect->bottom += info.rcWork.top - rect->top;
1252         rect->top = info.rcWork.top;
1253     }
1254     else if (rect->top >= info.rcWork.bottom)
1255     {
1256         rect->top += info.rcWork.bottom - rect->bottom;
1257         rect->bottom = info.rcWork.bottom;
1258     }
1259 }
1260
1261 /* make sure the specified point is visible on screen */
1262 static void make_point_onscreen( POINT *pt )
1263 {
1264     RECT rect;
1265
1266     SetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 );
1267     make_rect_onscreen( &rect );
1268     pt->x = rect.left;
1269     pt->y = rect.top;
1270 }
1271
1272
1273 /***********************************************************************
1274  *           WINPOS_SetPlacement
1275  */
1276 static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT flags )
1277 {
1278     DWORD style;
1279     WND *pWnd = WIN_GetPtr( hwnd );
1280     WINDOWPLACEMENT wp = *wndpl;
1281
1282     if (flags & PLACE_MIN) make_point_onscreen( &wp.ptMinPosition );
1283     if (flags & PLACE_MAX) make_point_onscreen( &wp.ptMaxPosition );
1284     if (flags & PLACE_RECT) make_rect_onscreen( &wp.rcNormalPosition );
1285
1286     TRACE( "%p: setting min %d,%d max %d,%d normal %s flags %x ajusted to min %d,%d max %d,%d normal %s\n",
1287            hwnd, wndpl->ptMinPosition.x, wndpl->ptMinPosition.y,
1288            wndpl->ptMaxPosition.x, wndpl->ptMaxPosition.y,
1289            wine_dbgstr_rect(&wndpl->rcNormalPosition), flags,
1290            wp.ptMinPosition.x, wp.ptMinPosition.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y,
1291            wine_dbgstr_rect(&wp.rcNormalPosition) );
1292
1293     if (!pWnd || pWnd == WND_OTHER_PROCESS || pWnd == WND_DESKTOP) return FALSE;
1294
1295     if( flags & PLACE_MIN ) pWnd->min_pos = wp.ptMinPosition;
1296     if( flags & PLACE_MAX ) pWnd->max_pos = wp.ptMaxPosition;
1297     if( flags & PLACE_RECT) pWnd->normal_rect = wp.rcNormalPosition;
1298
1299     style = pWnd->dwStyle;
1300
1301     WIN_ReleasePtr( pWnd );
1302
1303     if( style & WS_MINIMIZE )
1304     {
1305         if (flags & PLACE_MIN)
1306         {
1307             WINPOS_ShowIconTitle( hwnd, FALSE );
1308             SetWindowPos( hwnd, 0, wp.ptMinPosition.x, wp.ptMinPosition.y, 0, 0,
1309                           SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1310         }
1311     }
1312     else if( style & WS_MAXIMIZE )
1313     {
1314         if (flags & PLACE_MAX)
1315             SetWindowPos( hwnd, 0, wp.ptMaxPosition.x, wp.ptMaxPosition.y, 0, 0,
1316                           SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1317     }
1318     else if( flags & PLACE_RECT )
1319         SetWindowPos( hwnd, 0, wp.rcNormalPosition.left, wp.rcNormalPosition.top,
1320                       wp.rcNormalPosition.right - wp.rcNormalPosition.left,
1321                       wp.rcNormalPosition.bottom - wp.rcNormalPosition.top,
1322                       SWP_NOZORDER | SWP_NOACTIVATE );
1323
1324     ShowWindow( hwnd, wndpl->showCmd );
1325
1326     if (IsIconic( hwnd ))
1327     {
1328         if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE) WINPOS_ShowIconTitle( hwnd, TRUE );
1329
1330         /* SDK: ...valid only the next time... */
1331         if( wndpl->flags & WPF_RESTORETOMAXIMIZED )
1332         {
1333             pWnd = WIN_GetPtr( hwnd );
1334             if (pWnd && pWnd != WND_OTHER_PROCESS)
1335             {
1336                 pWnd->flags |= WIN_RESTORE_MAX;
1337                 WIN_ReleasePtr( pWnd );
1338             }
1339         }
1340     }
1341     return TRUE;
1342 }
1343
1344
1345 /***********************************************************************
1346  *              SetWindowPlacement (USER32.@)
1347  *
1348  * Win95:
1349  * Fails if wndpl->length of Win95 (!) apps is invalid.
1350  */
1351 BOOL WINAPI SetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl )
1352 {
1353     UINT flags = PLACE_MAX | PLACE_RECT;
1354     if (!wpl) return FALSE;
1355     if (wpl->flags & WPF_SETMINPOSITION) flags |= PLACE_MIN;
1356     return WINPOS_SetPlacement( hwnd, wpl, flags );
1357 }
1358
1359
1360 /***********************************************************************
1361  *              AnimateWindow (USER32.@)
1362  *              Shows/Hides a window with an animation
1363  *              NO ANIMATION YET
1364  */
1365 BOOL WINAPI AnimateWindow(HWND hwnd, DWORD dwTime, DWORD dwFlags)
1366 {
1367         FIXME("partial stub\n");
1368
1369         /* If trying to show/hide and it's already   *
1370          * shown/hidden or invalid window, fail with *
1371          * invalid parameter                         */
1372         if(!IsWindow(hwnd) ||
1373            (IsWindowVisible(hwnd) && !(dwFlags & AW_HIDE)) ||
1374            (!IsWindowVisible(hwnd) && (dwFlags & AW_HIDE)))
1375         {
1376                 SetLastError(ERROR_INVALID_PARAMETER);
1377                 return FALSE;
1378         }
1379
1380         ShowWindow(hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA));
1381
1382         return TRUE;
1383 }
1384
1385 /***********************************************************************
1386  *              SetInternalWindowPos (USER32.@)
1387  */
1388 void WINAPI SetInternalWindowPos( HWND hwnd, UINT showCmd,
1389                                     LPRECT rect, LPPOINT pt )
1390 {
1391     WINDOWPLACEMENT wndpl;
1392     UINT flags;
1393
1394     wndpl.length  = sizeof(wndpl);
1395     wndpl.showCmd = showCmd;
1396     wndpl.flags = flags = 0;
1397
1398     if( pt )
1399     {
1400         flags |= PLACE_MIN;
1401         wndpl.flags |= WPF_SETMINPOSITION;
1402         wndpl.ptMinPosition = *pt;
1403     }
1404     if( rect )
1405     {
1406         flags |= PLACE_RECT;
1407         wndpl.rcNormalPosition = *rect;
1408     }
1409     WINPOS_SetPlacement( hwnd, &wndpl, flags );
1410 }
1411
1412
1413 /*******************************************************************
1414  *         can_activate_window
1415  *
1416  * Check if we can activate the specified window.
1417  */
1418 static BOOL can_activate_window( HWND hwnd )
1419 {
1420     LONG style;
1421
1422     if (!hwnd) return FALSE;
1423     style = GetWindowLongW( hwnd, GWL_STYLE );
1424     if (!(style & WS_VISIBLE)) return FALSE;
1425     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
1426     return !(style & WS_DISABLED);
1427 }
1428
1429
1430 /*******************************************************************
1431  *         WINPOS_ActivateOtherWindow
1432  *
1433  *  Activates window other than pWnd.
1434  */
1435 void WINPOS_ActivateOtherWindow(HWND hwnd)
1436 {
1437     HWND hwndTo, fg;
1438
1439     if ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) && (hwndTo = GetWindow( hwnd, GW_OWNER )))
1440     {
1441         hwndTo = GetAncestor( hwndTo, GA_ROOT );
1442         if (can_activate_window( hwndTo )) goto done;
1443     }
1444
1445     hwndTo = hwnd;
1446     for (;;)
1447     {
1448         if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break;
1449         if (can_activate_window( hwndTo )) break;
1450     }
1451
1452  done:
1453     fg = GetForegroundWindow();
1454     TRACE("win = %p fg = %p\n", hwndTo, fg);
1455     if (!fg || (hwnd == fg))
1456     {
1457         if (SetForegroundWindow( hwndTo )) return;
1458     }
1459     if (!SetActiveWindow( hwndTo )) SetActiveWindow(0);
1460 }
1461
1462
1463 /***********************************************************************
1464  *           WINPOS_HandleWindowPosChanging
1465  *
1466  * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
1467  */
1468 LONG WINPOS_HandleWindowPosChanging( HWND hwnd, WINDOWPOS *winpos )
1469 {
1470     POINT minTrack, maxTrack;
1471     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1472
1473     if (winpos->flags & SWP_NOSIZE) return 0;
1474     if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0))
1475     {
1476         WINPOS_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack );
1477         if (winpos->cx > maxTrack.x) winpos->cx = maxTrack.x;
1478         if (winpos->cy > maxTrack.y) winpos->cy = maxTrack.y;
1479         if (!(style & WS_MINIMIZE))
1480         {
1481             if (winpos->cx < minTrack.x ) winpos->cx = minTrack.x;
1482             if (winpos->cy < minTrack.y ) winpos->cy = minTrack.y;
1483         }
1484     }
1485     return 0;
1486 }
1487
1488
1489 /***********************************************************************
1490  *           dump_winpos_flags
1491  */
1492 static void dump_winpos_flags(UINT flags)
1493 {
1494     static const DWORD dumped_flags = (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW |
1495                                        SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW |
1496                                        SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOOWNERZORDER |
1497                                        SWP_NOSENDCHANGING | SWP_DEFERERASE | SWP_ASYNCWINDOWPOS |
1498                                        SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_STATECHANGED);
1499     TRACE("flags:");
1500     if(flags & SWP_NOSIZE) TRACE(" SWP_NOSIZE");
1501     if(flags & SWP_NOMOVE) TRACE(" SWP_NOMOVE");
1502     if(flags & SWP_NOZORDER) TRACE(" SWP_NOZORDER");
1503     if(flags & SWP_NOREDRAW) TRACE(" SWP_NOREDRAW");
1504     if(flags & SWP_NOACTIVATE) TRACE(" SWP_NOACTIVATE");
1505     if(flags & SWP_FRAMECHANGED) TRACE(" SWP_FRAMECHANGED");
1506     if(flags & SWP_SHOWWINDOW) TRACE(" SWP_SHOWWINDOW");
1507     if(flags & SWP_HIDEWINDOW) TRACE(" SWP_HIDEWINDOW");
1508     if(flags & SWP_NOCOPYBITS) TRACE(" SWP_NOCOPYBITS");
1509     if(flags & SWP_NOOWNERZORDER) TRACE(" SWP_NOOWNERZORDER");
1510     if(flags & SWP_NOSENDCHANGING) TRACE(" SWP_NOSENDCHANGING");
1511     if(flags & SWP_DEFERERASE) TRACE(" SWP_DEFERERASE");
1512     if(flags & SWP_ASYNCWINDOWPOS) TRACE(" SWP_ASYNCWINDOWPOS");
1513     if(flags & SWP_NOCLIENTSIZE) TRACE(" SWP_NOCLIENTSIZE");
1514     if(flags & SWP_NOCLIENTMOVE) TRACE(" SWP_NOCLIENTMOVE");
1515     if(flags & SWP_STATECHANGED) TRACE(" SWP_STATECHANGED");
1516
1517     if(flags & ~dumped_flags) TRACE(" %08x", flags & ~dumped_flags);
1518     TRACE("\n");
1519 }
1520
1521 /***********************************************************************
1522  *           SWP_DoWinPosChanging
1523  */
1524 static BOOL SWP_DoWinPosChanging( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT* pNewClientRect )
1525 {
1526     WND *wndPtr;
1527
1528     /* Send WM_WINDOWPOSCHANGING message */
1529
1530     if (!(pWinpos->flags & SWP_NOSENDCHANGING))
1531         SendMessageW( pWinpos->hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
1532
1533     if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) ||
1534         wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
1535
1536     /* Calculate new position and size */
1537
1538     *pNewWindowRect = wndPtr->rectWindow;
1539     *pNewClientRect = (wndPtr->dwStyle & WS_MINIMIZE) ? wndPtr->rectWindow
1540                                                     : wndPtr->rectClient;
1541
1542     if (!(pWinpos->flags & SWP_NOSIZE))
1543     {
1544         pNewWindowRect->right  = pNewWindowRect->left + pWinpos->cx;
1545         pNewWindowRect->bottom = pNewWindowRect->top + pWinpos->cy;
1546     }
1547     if (!(pWinpos->flags & SWP_NOMOVE))
1548     {
1549         pNewWindowRect->left    = pWinpos->x;
1550         pNewWindowRect->top     = pWinpos->y;
1551         pNewWindowRect->right  += pWinpos->x - wndPtr->rectWindow.left;
1552         pNewWindowRect->bottom += pWinpos->y - wndPtr->rectWindow.top;
1553
1554         OffsetRect( pNewClientRect, pWinpos->x - wndPtr->rectWindow.left,
1555                                     pWinpos->y - wndPtr->rectWindow.top );
1556     }
1557     pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1558
1559     TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
1560            pWinpos->hwnd, pWinpos->hwndInsertAfter, pWinpos->x, pWinpos->y,
1561            pWinpos->cx, pWinpos->cy, pWinpos->flags );
1562     TRACE( "current %s style %08x new %s\n",
1563            wine_dbgstr_rect( &wndPtr->rectWindow ), wndPtr->dwStyle,
1564            wine_dbgstr_rect( pNewWindowRect ));
1565
1566     WIN_ReleasePtr( wndPtr );
1567     return TRUE;
1568 }
1569
1570 /***********************************************************************
1571  *           get_valid_rects
1572  *
1573  * Compute the valid rects from the old and new client rect and WVR_* flags.
1574  * Helper for WM_NCCALCSIZE handling.
1575  */
1576 static inline void get_valid_rects( const RECT *old_client, const RECT *new_client, UINT flags,
1577                                     RECT *valid )
1578 {
1579     int cx, cy;
1580
1581     if (flags & WVR_REDRAW)
1582     {
1583         SetRectEmpty( &valid[0] );
1584         SetRectEmpty( &valid[1] );
1585         return;
1586     }
1587
1588     if (flags & WVR_VALIDRECTS)
1589     {
1590         if (!IntersectRect( &valid[0], &valid[0], new_client ) ||
1591             !IntersectRect( &valid[1], &valid[1], old_client ))
1592         {
1593             SetRectEmpty( &valid[0] );
1594             SetRectEmpty( &valid[1] );
1595             return;
1596         }
1597         flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
1598     }
1599     else
1600     {
1601         valid[0] = *new_client;
1602         valid[1] = *old_client;
1603     }
1604
1605     /* make sure the rectangles have the same size */
1606     cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
1607     cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
1608
1609     if (flags & WVR_ALIGNBOTTOM)
1610     {
1611         valid[0].top = valid[0].bottom - cy;
1612         valid[1].top = valid[1].bottom - cy;
1613     }
1614     else
1615     {
1616         valid[0].bottom = valid[0].top + cy;
1617         valid[1].bottom = valid[1].top + cy;
1618     }
1619     if (flags & WVR_ALIGNRIGHT)
1620     {
1621         valid[0].left = valid[0].right - cx;
1622         valid[1].left = valid[1].right - cx;
1623     }
1624     else
1625     {
1626         valid[0].right = valid[0].left + cx;
1627         valid[1].right = valid[1].left + cx;
1628     }
1629 }
1630
1631
1632 /***********************************************************************
1633  *           SWP_DoOwnedPopups
1634  *
1635  * fix Z order taking into account owned popups -
1636  * basically we need to maintain them above the window that owns them
1637  *
1638  * FIXME: hide/show owned popups when owner visibility changes.
1639  */
1640 static HWND SWP_DoOwnedPopups(HWND hwnd, HWND hwndInsertAfter)
1641 {
1642     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1643     HWND owner, *list = NULL;
1644     unsigned int i;
1645
1646     TRACE("(%p) hInsertAfter = %p\n", hwnd, hwndInsertAfter );
1647
1648     if ((style & WS_POPUP) && (owner = GetWindow( hwnd, GW_OWNER )))
1649     {
1650         /* make sure this popup stays above the owner */
1651
1652         if (hwndInsertAfter != HWND_TOP && hwndInsertAfter != HWND_TOPMOST)
1653         {
1654             if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return hwndInsertAfter;
1655
1656             for (i = 0; list[i]; i++)
1657             {
1658                 if (list[i] == owner)
1659                 {
1660                     if (i > 0) hwndInsertAfter = list[i-1];
1661                     else hwndInsertAfter = HWND_TOP;
1662                     break;
1663                 }
1664
1665                 if (hwndInsertAfter == HWND_NOTOPMOST)
1666                 {
1667                     if (!(GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TOPMOST)) break;
1668                 }
1669                 else if (list[i] == hwndInsertAfter) break;
1670             }
1671         }
1672     }
1673     else if (style & WS_CHILD) return hwndInsertAfter;
1674
1675     if (hwndInsertAfter == HWND_BOTTOM) goto done;
1676     if (!list && !(list = WIN_ListChildren( GetDesktopWindow() ))) goto done;
1677
1678     i = 0;
1679     if (hwndInsertAfter == HWND_TOP || hwndInsertAfter == HWND_NOTOPMOST)
1680     {
1681         if (hwndInsertAfter == HWND_NOTOPMOST || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST))
1682         {
1683             /* skip all the topmost windows */
1684             while (list[i] && (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TOPMOST)) i++;
1685         }
1686     }
1687     else if (hwndInsertAfter != HWND_TOPMOST)
1688     {
1689         /* skip windows that are already placed correctly */
1690         for (i = 0; list[i]; i++)
1691         {
1692             if (list[i] == hwndInsertAfter) break;
1693             if (list[i] == hwnd) goto done;  /* nothing to do if window is moving backwards in z-order */
1694         }
1695     }
1696
1697     for ( ; list[i]; i++)
1698     {
1699         if (list[i] == hwnd) break;
1700         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_POPUP)) continue;
1701         if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1702         TRACE( "moving %p owned by %p after %p\n", list[i], hwnd, hwndInsertAfter );
1703         SetWindowPos( list[i], hwndInsertAfter, 0, 0, 0, 0,
1704                       SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE );
1705         hwndInsertAfter = list[i];
1706     }
1707
1708 done:
1709     HeapFree( GetProcessHeap(), 0, list );
1710     return hwndInsertAfter;
1711 }
1712
1713 /***********************************************************************
1714  *           SWP_DoNCCalcSize
1715  */
1716 static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, const RECT* pNewWindowRect, RECT* pNewClientRect,
1717                               RECT *validRects )
1718 {
1719     UINT wvrFlags = 0;
1720     WND *wndPtr;
1721
1722     if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1723
1724       /* Send WM_NCCALCSIZE message to get new client area */
1725     if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
1726     {
1727         NCCALCSIZE_PARAMS params;
1728         WINDOWPOS winposCopy;
1729
1730         params.rgrc[0] = *pNewWindowRect;
1731         params.rgrc[1] = wndPtr->rectWindow;
1732         params.rgrc[2] = wndPtr->rectClient;
1733         params.lppos = &winposCopy;
1734         winposCopy = *pWinpos;
1735         WIN_ReleasePtr( wndPtr );
1736
1737         wvrFlags = SendMessageW( pWinpos->hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)&params );
1738
1739         *pNewClientRect = params.rgrc[0];
1740
1741         if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1742
1743         TRACE( "hwnd %p old win %s old client %s new win %s new client %s\n", pWinpos->hwnd,
1744                wine_dbgstr_rect(&wndPtr->rectWindow), wine_dbgstr_rect(&wndPtr->rectClient),
1745                wine_dbgstr_rect(pNewWindowRect), wine_dbgstr_rect(pNewClientRect) );
1746
1747         if( pNewClientRect->left != wndPtr->rectClient.left ||
1748             pNewClientRect->top != wndPtr->rectClient.top )
1749             pWinpos->flags &= ~SWP_NOCLIENTMOVE;
1750
1751         if( (pNewClientRect->right - pNewClientRect->left !=
1752              wndPtr->rectClient.right - wndPtr->rectClient.left))
1753             pWinpos->flags &= ~SWP_NOCLIENTSIZE;
1754         else
1755             wvrFlags &= ~WVR_HREDRAW;
1756
1757         if (pNewClientRect->bottom - pNewClientRect->top !=
1758              wndPtr->rectClient.bottom - wndPtr->rectClient.top)
1759             pWinpos->flags &= ~SWP_NOCLIENTSIZE;
1760         else
1761             wvrFlags &= ~WVR_VREDRAW;
1762
1763         validRects[0] = params.rgrc[1];
1764         validRects[1] = params.rgrc[2];
1765     }
1766     else
1767     {
1768         if (!(pWinpos->flags & SWP_NOMOVE) &&
1769             (pNewClientRect->left != wndPtr->rectClient.left ||
1770              pNewClientRect->top != wndPtr->rectClient.top))
1771             pWinpos->flags &= ~SWP_NOCLIENTMOVE;
1772     }
1773
1774     if (pWinpos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
1775     {
1776         SetRectEmpty( &validRects[0] );
1777         SetRectEmpty( &validRects[1] );
1778     }
1779     else get_valid_rects( &wndPtr->rectClient, pNewClientRect, wvrFlags, validRects );
1780
1781     WIN_ReleasePtr( wndPtr );
1782     return wvrFlags;
1783 }
1784
1785 /* fix redundant flags and values in the WINDOWPOS structure */
1786 static BOOL fixup_flags( WINDOWPOS *winpos )
1787 {
1788     HWND parent;
1789     WND *wndPtr = WIN_GetPtr( winpos->hwnd );
1790     BOOL ret = TRUE;
1791
1792     if (!wndPtr || wndPtr == WND_OTHER_PROCESS)
1793     {
1794         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1795         return FALSE;
1796     }
1797     winpos->hwnd = wndPtr->hwndSelf;  /* make it a full handle */
1798
1799     /* Finally make sure that all coordinates are valid */
1800     if (winpos->x < -32768) winpos->x = -32768;
1801     else if (winpos->x > 32767) winpos->x = 32767;
1802     if (winpos->y < -32768) winpos->y = -32768;
1803     else if (winpos->y > 32767) winpos->y = 32767;
1804
1805     if (winpos->cx < 0) winpos->cx = 0;
1806     else if (winpos->cx > 32767) winpos->cx = 32767;
1807     if (winpos->cy < 0) winpos->cy = 0;
1808     else if (winpos->cy > 32767) winpos->cy = 32767;
1809
1810     parent = GetAncestor( winpos->hwnd, GA_PARENT );
1811     if (!IsWindowVisible( parent )) winpos->flags |= SWP_NOREDRAW;
1812
1813     if (wndPtr->dwStyle & WS_VISIBLE) winpos->flags &= ~SWP_SHOWWINDOW;
1814     else
1815     {
1816         winpos->flags &= ~SWP_HIDEWINDOW;
1817         if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
1818     }
1819
1820     if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == winpos->cx) &&
1821         (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == winpos->cy))
1822         winpos->flags |= SWP_NOSIZE;    /* Already the right size */
1823
1824     if ((wndPtr->rectWindow.left == winpos->x) && (wndPtr->rectWindow.top == winpos->y))
1825         winpos->flags |= SWP_NOMOVE;    /* Already the right position */
1826
1827     if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1828     {
1829         if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) && /* Bring to the top when activating */
1830             (winpos->flags & SWP_NOZORDER ||
1831              (winpos->hwndInsertAfter != HWND_TOPMOST && winpos->hwndInsertAfter != HWND_NOTOPMOST)))
1832         {
1833             winpos->flags &= ~SWP_NOZORDER;
1834             winpos->hwndInsertAfter = HWND_TOP;
1835         }
1836     }
1837
1838     /* Check hwndInsertAfter */
1839     if (winpos->flags & SWP_NOZORDER) goto done;
1840
1841     /* fix sign extension */
1842     if (winpos->hwndInsertAfter == (HWND)0xffff) winpos->hwndInsertAfter = HWND_TOPMOST;
1843     else if (winpos->hwndInsertAfter == (HWND)0xfffe) winpos->hwndInsertAfter = HWND_NOTOPMOST;
1844
1845     /* hwndInsertAfter must be a sibling of the window */
1846     if (winpos->hwndInsertAfter == HWND_TOP)
1847     {
1848         if (GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
1849             winpos->flags |= SWP_NOZORDER;
1850     }
1851     else if (winpos->hwndInsertAfter == HWND_BOTTOM)
1852     {
1853         if (!(wndPtr->dwExStyle & WS_EX_TOPMOST) && GetWindow(winpos->hwnd, GW_HWNDLAST) == winpos->hwnd)
1854             winpos->flags |= SWP_NOZORDER;
1855     }
1856     else if (winpos->hwndInsertAfter == HWND_TOPMOST)
1857     {
1858         if ((wndPtr->dwExStyle & WS_EX_TOPMOST) && GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
1859             winpos->flags |= SWP_NOZORDER;
1860     }
1861     else if (winpos->hwndInsertAfter == HWND_NOTOPMOST)
1862     {
1863         if (!(wndPtr->dwExStyle & WS_EX_TOPMOST))
1864             winpos->flags |= SWP_NOZORDER;
1865     }
1866     else
1867     {
1868         if (GetAncestor( winpos->hwndInsertAfter, GA_PARENT ) != parent) ret = FALSE;
1869         else
1870         {
1871             /* don't need to change the Zorder of hwnd if it's already inserted
1872              * after hwndInsertAfter or when inserting hwnd after itself.
1873              */
1874             if ((winpos->hwnd == winpos->hwndInsertAfter) ||
1875                 (winpos->hwnd == GetWindow( winpos->hwndInsertAfter, GW_HWNDNEXT )))
1876                 winpos->flags |= SWP_NOZORDER;
1877         }
1878     }
1879  done:
1880     WIN_ReleasePtr( wndPtr );
1881     return ret;
1882 }
1883
1884
1885 /***********************************************************************
1886  *              set_window_pos
1887  *
1888  * Backend implementation of SetWindowPos.
1889  */
1890 BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags,
1891                      const RECT *window_rect, const RECT *client_rect, const RECT *valid_rects )
1892 {
1893     WND *win;
1894     BOOL ret;
1895     RECT visible_rect, old_window_rect;
1896
1897     visible_rect = *window_rect;
1898     USER_Driver->pWindowPosChanging( hwnd, insert_after, swp_flags,
1899                                      window_rect, client_rect, &visible_rect );
1900
1901     if (!(win = WIN_GetPtr( hwnd ))) return FALSE;
1902     if (win == WND_DESKTOP || win == WND_OTHER_PROCESS) return FALSE;
1903
1904     old_window_rect = win->rectWindow;
1905     SERVER_START_REQ( set_window_pos )
1906     {
1907         req->handle        = wine_server_user_handle( hwnd );
1908         req->previous      = wine_server_user_handle( insert_after );
1909         req->flags         = swp_flags;
1910         req->window.left   = window_rect->left;
1911         req->window.top    = window_rect->top;
1912         req->window.right  = window_rect->right;
1913         req->window.bottom = window_rect->bottom;
1914         req->client.left   = client_rect->left;
1915         req->client.top    = client_rect->top;
1916         req->client.right  = client_rect->right;
1917         req->client.bottom = client_rect->bottom;
1918         if (memcmp( window_rect, &visible_rect, sizeof(RECT) ) || !IsRectEmpty( &valid_rects[0] ))
1919         {
1920             wine_server_add_data( req, &visible_rect, sizeof(visible_rect) );
1921             if (!IsRectEmpty( &valid_rects[0] ))
1922                 wine_server_add_data( req, valid_rects, 2 * sizeof(*valid_rects) );
1923         }
1924         if ((ret = !wine_server_call( req )))
1925         {
1926             win->dwStyle    = reply->new_style;
1927             win->dwExStyle  = reply->new_ex_style;
1928             win->rectWindow = *window_rect;
1929             win->rectClient = *client_rect;
1930         }
1931     }
1932     SERVER_END_REQ;
1933     WIN_ReleasePtr( win );
1934
1935     if (ret)
1936     {
1937         if (((swp_flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) ||
1938             (swp_flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW | SWP_STATECHANGED)))
1939             invalidate_dce( hwnd, &old_window_rect );
1940
1941         USER_Driver->pWindowPosChanged( hwnd, insert_after, swp_flags, window_rect,
1942                                         client_rect, &visible_rect, valid_rects );
1943     }
1944     return ret;
1945 }
1946
1947
1948 /***********************************************************************
1949  *              USER_SetWindowPos
1950  *
1951  *     User32 internal function
1952  */
1953 BOOL USER_SetWindowPos( WINDOWPOS * winpos )
1954 {
1955     RECT newWindowRect, newClientRect, valid_rects[2];
1956     UINT orig_flags;
1957     
1958     orig_flags = winpos->flags;
1959     
1960     /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
1961     if (!(winpos->flags & SWP_NOMOVE))
1962     {
1963         if (winpos->x < -32768) winpos->x = -32768;
1964         else if (winpos->x > 32767) winpos->x = 32767;
1965         if (winpos->y < -32768) winpos->y = -32768;
1966         else if (winpos->y > 32767) winpos->y = 32767;
1967     }
1968     if (!(winpos->flags & SWP_NOSIZE))
1969     {
1970         if (winpos->cx < 0) winpos->cx = 0;
1971         else if (winpos->cx > 32767) winpos->cx = 32767;
1972         if (winpos->cy < 0) winpos->cy = 0;
1973         else if (winpos->cy > 32767) winpos->cy = 32767;
1974     }
1975
1976     if (!SWP_DoWinPosChanging( winpos, &newWindowRect, &newClientRect )) return FALSE;
1977
1978     /* Fix redundant flags */
1979     if (!fixup_flags( winpos )) return FALSE;
1980
1981     if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
1982     {
1983         if (GetAncestor( winpos->hwnd, GA_PARENT ) == GetDesktopWindow())
1984             winpos->hwndInsertAfter = SWP_DoOwnedPopups( winpos->hwnd, winpos->hwndInsertAfter );
1985     }
1986
1987     /* Common operations */
1988
1989     SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect, valid_rects );
1990
1991     if (!set_window_pos( winpos->hwnd, winpos->hwndInsertAfter, winpos->flags,
1992                          &newWindowRect, &newClientRect, valid_rects ))
1993         return FALSE;
1994
1995     /* erase parent when hiding or resizing child */
1996     if (!(orig_flags & SWP_DEFERERASE) &&
1997         ((orig_flags & SWP_HIDEWINDOW) ||
1998          (!(orig_flags & SWP_SHOWWINDOW) &&
1999           (winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE)))
2000     {
2001         HWND parent = GetAncestor( winpos->hwnd, GA_PARENT );
2002         if (!parent || parent == GetDesktopWindow()) parent = winpos->hwnd;
2003         erase_now( parent, 0 );
2004     }
2005
2006     if( winpos->flags & SWP_HIDEWINDOW )
2007         HideCaret(winpos->hwnd);
2008     else if (winpos->flags & SWP_SHOWWINDOW)
2009         ShowCaret(winpos->hwnd);
2010
2011     if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2012     {
2013         /* child windows get WM_CHILDACTIVATE message */
2014         if ((GetWindowLongW( winpos->hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2015             SendMessageW( winpos->hwnd, WM_CHILDACTIVATE, 0, 0 );
2016         else
2017             SetForegroundWindow( winpos->hwnd );
2018     }
2019
2020       /* And last, send the WM_WINDOWPOSCHANGED message */
2021
2022     TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
2023
2024     if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE))
2025     {
2026         /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2027            and always contains final window position.
2028          */
2029         winpos->x = newWindowRect.left;
2030         winpos->y = newWindowRect.top;
2031         winpos->cx = newWindowRect.right - newWindowRect.left;
2032         winpos->cy = newWindowRect.bottom - newWindowRect.top;
2033         SendMessageW( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
2034     }
2035     return TRUE;
2036 }
2037
2038 /***********************************************************************
2039  *              SetWindowPos (USER32.@)
2040  */
2041 BOOL WINAPI SetWindowPos( HWND hwnd, HWND hwndInsertAfter,
2042                           INT x, INT y, INT cx, INT cy, UINT flags )
2043 {
2044     WINDOWPOS winpos;
2045
2046     TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2047           hwnd, hwndInsertAfter, x, y, cx, cy, flags);
2048     if(TRACE_ON(win)) dump_winpos_flags(flags);
2049
2050     if (is_broadcast(hwnd))
2051     {
2052         SetLastError( ERROR_INVALID_PARAMETER );
2053         return FALSE;
2054     }
2055
2056     winpos.hwnd = WIN_GetFullHandle(hwnd);
2057     winpos.hwndInsertAfter = WIN_GetFullHandle(hwndInsertAfter);
2058     winpos.x = x;
2059     winpos.y = y;
2060     winpos.cx = cx;
2061     winpos.cy = cy;
2062     winpos.flags = flags;
2063     
2064     if (WIN_IsCurrentThread( hwnd ))
2065         return USER_SetWindowPos(&winpos);
2066
2067     return SendMessageW( winpos.hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)&winpos );
2068 }
2069
2070
2071 /***********************************************************************
2072  *              BeginDeferWindowPos (USER32.@)
2073  */
2074 HDWP WINAPI BeginDeferWindowPos( INT count )
2075 {
2076     HDWP handle;
2077     DWP *pDWP;
2078
2079     TRACE("%d\n", count);
2080
2081     if (count < 0)
2082     {
2083         SetLastError(ERROR_INVALID_PARAMETER);
2084         return 0;
2085     }
2086     /* Windows allows zero count, in which case it allocates context for 8 moves */
2087     if (count == 0) count = 8;
2088
2089     handle = USER_HEAP_ALLOC( sizeof(DWP) + (count-1)*sizeof(WINDOWPOS) );
2090     if (!handle) return 0;
2091     pDWP = USER_HEAP_LIN_ADDR( handle );
2092     pDWP->actualCount    = 0;
2093     pDWP->suggestedCount = count;
2094     pDWP->valid          = TRUE;
2095     pDWP->wMagic         = DWP_MAGIC;
2096     pDWP->hwndParent     = 0;
2097
2098     TRACE("returning hdwp %p\n", handle);
2099     return handle;
2100 }
2101
2102
2103 /***********************************************************************
2104  *              DeferWindowPos (USER32.@)
2105  */
2106 HDWP WINAPI DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter,
2107                                 INT x, INT y, INT cx, INT cy,
2108                                 UINT flags )
2109 {
2110     DWP *pDWP;
2111     int i;
2112     HDWP newhdwp = hdwp,retvalue;
2113
2114     TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2115           hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2116
2117     hwnd = WIN_GetFullHandle( hwnd );
2118     if (is_desktop_window( hwnd )) return 0;
2119
2120     if (!(pDWP = USER_HEAP_LIN_ADDR( hdwp ))) return 0;
2121
2122     USER_Lock();
2123
2124     for (i = 0; i < pDWP->actualCount; i++)
2125     {
2126         if (pDWP->winPos[i].hwnd == hwnd)
2127         {
2128               /* Merge with the other changes */
2129             if (!(flags & SWP_NOZORDER))
2130             {
2131                 pDWP->winPos[i].hwndInsertAfter = WIN_GetFullHandle(hwndAfter);
2132             }
2133             if (!(flags & SWP_NOMOVE))
2134             {
2135                 pDWP->winPos[i].x = x;
2136                 pDWP->winPos[i].y = y;
2137             }
2138             if (!(flags & SWP_NOSIZE))
2139             {
2140                 pDWP->winPos[i].cx = cx;
2141                 pDWP->winPos[i].cy = cy;
2142             }
2143             pDWP->winPos[i].flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2144                                                SWP_NOZORDER | SWP_NOREDRAW |
2145                                                SWP_NOACTIVATE | SWP_NOCOPYBITS|
2146                                                SWP_NOOWNERZORDER);
2147             pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2148                                               SWP_FRAMECHANGED);
2149             retvalue = hdwp;
2150             goto END;
2151         }
2152     }
2153     if (pDWP->actualCount >= pDWP->suggestedCount)
2154     {
2155         newhdwp = USER_HEAP_REALLOC( hdwp,
2156                       sizeof(DWP) + pDWP->suggestedCount*sizeof(WINDOWPOS) );
2157         if (!newhdwp)
2158         {
2159             retvalue = 0;
2160             goto END;
2161         }
2162         pDWP = USER_HEAP_LIN_ADDR( newhdwp );
2163         pDWP->suggestedCount++;
2164     }
2165     pDWP->winPos[pDWP->actualCount].hwnd = hwnd;
2166     pDWP->winPos[pDWP->actualCount].hwndInsertAfter = hwndAfter;
2167     pDWP->winPos[pDWP->actualCount].x = x;
2168     pDWP->winPos[pDWP->actualCount].y = y;
2169     pDWP->winPos[pDWP->actualCount].cx = cx;
2170     pDWP->winPos[pDWP->actualCount].cy = cy;
2171     pDWP->winPos[pDWP->actualCount].flags = flags;
2172     pDWP->actualCount++;
2173     retvalue = newhdwp;
2174 END:
2175     USER_Unlock();
2176     return retvalue;
2177 }
2178
2179
2180 /***********************************************************************
2181  *              EndDeferWindowPos (USER32.@)
2182  */
2183 BOOL WINAPI EndDeferWindowPos( HDWP hdwp )
2184 {
2185     DWP *pDWP;
2186     WINDOWPOS *winpos;
2187     BOOL res = TRUE;
2188     int i;
2189
2190     TRACE("%p\n", hdwp);
2191
2192     pDWP = USER_HEAP_LIN_ADDR( hdwp );
2193     if (!pDWP) return FALSE;
2194     for (i = 0, winpos = pDWP->winPos; res && i < pDWP->actualCount; i++, winpos++)
2195     {
2196         TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2197                winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
2198                winpos->cx, winpos->cy, winpos->flags);
2199
2200         if (WIN_IsCurrentThread( winpos->hwnd ))
2201             res = USER_SetWindowPos( winpos );
2202         else
2203             res = SendMessageW( winpos->hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)winpos );
2204     }
2205     USER_HEAP_FREE( hdwp );
2206     return res;
2207 }
2208
2209
2210 /***********************************************************************
2211  *              ArrangeIconicWindows (USER32.@)
2212  */
2213 UINT WINAPI ArrangeIconicWindows( HWND parent )
2214 {
2215     RECT rectParent;
2216     HWND hwndChild;
2217     INT x, y, xspacing, yspacing;
2218
2219     GetClientRect( parent, &rectParent );
2220     x = rectParent.left;
2221     y = rectParent.bottom;
2222     xspacing = GetSystemMetrics(SM_CXICONSPACING);
2223     yspacing = GetSystemMetrics(SM_CYICONSPACING);
2224
2225     hwndChild = GetWindow( parent, GW_CHILD );
2226     while (hwndChild)
2227     {
2228         if( IsIconic( hwndChild ) )
2229         {
2230             WINPOS_ShowIconTitle( hwndChild, FALSE );
2231
2232             SetWindowPos( hwndChild, 0, x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2,
2233                             y - yspacing - GetSystemMetrics(SM_CYICON)/2, 0, 0,
2234                             SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
2235             if( IsWindow(hwndChild) )
2236                 WINPOS_ShowIconTitle(hwndChild , TRUE );
2237
2238             if (x <= rectParent.right - xspacing) x += xspacing;
2239             else
2240             {
2241                 x = rectParent.left;
2242                 y -= yspacing;
2243             }
2244         }
2245         hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
2246     }
2247     return yspacing;
2248 }
2249
2250
2251 /***********************************************************************
2252  *           draw_moving_frame
2253  *
2254  * Draw the frame used when moving or resizing window.
2255  */
2256 static void draw_moving_frame( HDC hdc, RECT *rect, BOOL thickframe )
2257 {
2258     if (thickframe)
2259     {
2260         const int width = GetSystemMetrics(SM_CXFRAME);
2261         const int height = GetSystemMetrics(SM_CYFRAME);
2262
2263         HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
2264         PatBlt( hdc, rect->left, rect->top,
2265                 rect->right - rect->left - width, height, PATINVERT );
2266         PatBlt( hdc, rect->left, rect->top + height, width,
2267                 rect->bottom - rect->top - height, PATINVERT );
2268         PatBlt( hdc, rect->left + width, rect->bottom - 1,
2269                 rect->right - rect->left - width, -height, PATINVERT );
2270         PatBlt( hdc, rect->right - 1, rect->top, -width,
2271                 rect->bottom - rect->top - height, PATINVERT );
2272         SelectObject( hdc, hbrush );
2273     }
2274     else DrawFocusRect( hdc, rect );
2275 }
2276
2277
2278 /***********************************************************************
2279  *           start_size_move
2280  *
2281  * Initialization of a move or resize, when initiated from a menu choice.
2282  * Return hit test code for caption or sizing border.
2283  */
2284 static LONG start_size_move( HWND hwnd, WPARAM wParam, POINT *capturePoint, LONG style )
2285 {
2286     LONG hittest = 0;
2287     POINT pt;
2288     MSG msg;
2289     RECT rectWindow;
2290
2291     GetWindowRect( hwnd, &rectWindow );
2292
2293     if ((wParam & 0xfff0) == SC_MOVE)
2294     {
2295         /* Move pointer at the center of the caption */
2296         RECT rect = rectWindow;
2297         /* Note: to be exactly centered we should take the different types
2298          * of border into account, but it shouldn't make more than a few pixels
2299          * of difference so let's not bother with that */
2300         rect.top += GetSystemMetrics(SM_CYBORDER);
2301         if (style & WS_SYSMENU)
2302             rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
2303         if (style & WS_MINIMIZEBOX)
2304             rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
2305         if (style & WS_MAXIMIZEBOX)
2306             rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
2307         pt.x = (rect.right + rect.left) / 2;
2308         pt.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
2309         hittest = HTCAPTION;
2310         *capturePoint = pt;
2311     }
2312     else  /* SC_SIZE */
2313     {
2314         SetCursor( LoadCursorW( 0, (LPWSTR)IDC_SIZEALL ) );
2315         pt.x = pt.y = 0;
2316         while(!hittest)
2317         {
2318             if (!GetMessageW( &msg, 0, 0, 0 )) return 0;
2319             if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
2320
2321             switch(msg.message)
2322             {
2323             case WM_MOUSEMOVE:
2324                 pt.x = min( max( msg.pt.x, rectWindow.left ), rectWindow.right - 1 );
2325                 pt.y = min( max( msg.pt.y, rectWindow.top ), rectWindow.bottom - 1 );
2326                 hittest = SendMessageW( hwnd, WM_NCHITTEST, 0, MAKELONG( pt.x, pt.y ) );
2327                 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) hittest = 0;
2328                 break;
2329
2330             case WM_LBUTTONUP:
2331                 return 0;
2332
2333             case WM_KEYDOWN:
2334                 switch(msg.wParam)
2335                 {
2336                 case VK_UP:
2337                     hittest = HTTOP;
2338                     pt.x =(rectWindow.left+rectWindow.right)/2;
2339                     pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
2340                     break;
2341                 case VK_DOWN:
2342                     hittest = HTBOTTOM;
2343                     pt.x =(rectWindow.left+rectWindow.right)/2;
2344                     pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
2345                     break;
2346                 case VK_LEFT:
2347                     hittest = HTLEFT;
2348                     pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
2349                     pt.y =(rectWindow.top+rectWindow.bottom)/2;
2350                     break;
2351                 case VK_RIGHT:
2352                     hittest = HTRIGHT;
2353                     pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
2354                     pt.y =(rectWindow.top+rectWindow.bottom)/2;
2355                     break;
2356                 case VK_RETURN:
2357                 case VK_ESCAPE:
2358                     return 0;
2359                 }
2360                 break;
2361             default:
2362                 TranslateMessage( &msg );
2363                 DispatchMessageW( &msg );
2364                 break;
2365             }
2366         }
2367         *capturePoint = pt;
2368     }
2369     SetCursorPos( pt.x, pt.y );
2370     SendMessageW( hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
2371     return hittest;
2372 }
2373
2374
2375 /***********************************************************************
2376  *           WINPOS_SysCommandSizeMove
2377  *
2378  * Perform SC_MOVE and SC_SIZE commands.
2379  */
2380 void WINPOS_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
2381 {
2382     MSG msg;
2383     RECT sizingRect, mouseRect, origRect;
2384     HDC hdc;
2385     HWND parent;
2386     LONG hittest = (LONG)(wParam & 0x0f);
2387     WPARAM syscommand = wParam & 0xfff0;
2388     HCURSOR hDragCursor = 0, hOldCursor = 0;
2389     POINT minTrack, maxTrack;
2390     POINT capturePoint, pt;
2391     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2392     BOOL    thickframe = HAS_THICKFRAME( style );
2393     BOOL    iconic = style & WS_MINIMIZE;
2394     BOOL    moved = FALSE;
2395     DWORD     dwPoint = GetMessagePos ();
2396     BOOL DragFullWindows = TRUE;
2397
2398     if (IsZoomed(hwnd) || !IsWindowVisible(hwnd)) return;
2399
2400     pt.x = (short)LOWORD(dwPoint);
2401     pt.y = (short)HIWORD(dwPoint);
2402     capturePoint = pt;
2403
2404     TRACE("hwnd %p command %04lx, hittest %d, pos %d,%d\n",
2405           hwnd, syscommand, hittest, pt.x, pt.y);
2406
2407     if (syscommand == SC_MOVE)
2408     {
2409         if (!hittest) hittest = start_size_move( hwnd, wParam, &capturePoint, style );
2410         if (!hittest) return;
2411     }
2412     else  /* SC_SIZE */
2413     {
2414         if ( hittest && (syscommand != SC_MOUSEMENU) )
2415             hittest += (HTLEFT - WMSZ_LEFT);
2416         else
2417         {
2418             set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
2419             hittest = start_size_move( hwnd, wParam, &capturePoint, style );
2420             if (!hittest)
2421             {
2422                 set_capture_window( 0, GUI_INMOVESIZE, NULL );
2423                 return;
2424             }
2425         }
2426     }
2427
2428       /* Get min/max info */
2429
2430     WINPOS_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack );
2431     GetWindowRect( hwnd, &sizingRect );
2432     if (style & WS_CHILD)
2433     {
2434         parent = GetParent(hwnd);
2435         /* make sizing rect relative to parent */
2436         MapWindowPoints( 0, parent, (POINT*)&sizingRect, 2 );
2437         GetClientRect( parent, &mouseRect );
2438     }
2439     else
2440     {
2441         parent = 0;
2442         GetClientRect( GetDesktopWindow(), &mouseRect );
2443         mouseRect.left = GetSystemMetrics( SM_XVIRTUALSCREEN );
2444         mouseRect.top = GetSystemMetrics( SM_YVIRTUALSCREEN );
2445         mouseRect.right = mouseRect.left + GetSystemMetrics( SM_CXVIRTUALSCREEN );
2446         mouseRect.bottom = mouseRect.top + GetSystemMetrics( SM_CYVIRTUALSCREEN );
2447     }
2448     origRect = sizingRect;
2449
2450     if (ON_LEFT_BORDER(hittest))
2451     {
2452         mouseRect.left  = max( mouseRect.left, sizingRect.right-maxTrack.x );
2453         mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x );
2454     }
2455     else if (ON_RIGHT_BORDER(hittest))
2456     {
2457         mouseRect.left  = max( mouseRect.left, sizingRect.left+minTrack.x );
2458         mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x );
2459     }
2460     if (ON_TOP_BORDER(hittest))
2461     {
2462         mouseRect.top    = max( mouseRect.top, sizingRect.bottom-maxTrack.y );
2463         mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y);
2464     }
2465     else if (ON_BOTTOM_BORDER(hittest))
2466     {
2467         mouseRect.top    = max( mouseRect.top, sizingRect.top+minTrack.y );
2468         mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y );
2469     }
2470     if (parent) MapWindowPoints( parent, 0, (LPPOINT)&mouseRect, 2 );
2471
2472     /* Retrieve a default cache DC (without using the window style) */
2473     hdc = GetDCEx( parent, 0, DCX_CACHE );
2474
2475     if( iconic ) /* create a cursor for dragging */
2476     {
2477         hDragCursor = (HCURSOR)GetClassLongPtrW( hwnd, GCLP_HICON);
2478         if( !hDragCursor ) hDragCursor = (HCURSOR)SendMessageW( hwnd, WM_QUERYDRAGICON, 0, 0L);
2479         if( !hDragCursor ) iconic = FALSE;
2480     }
2481
2482     /* we only allow disabling the full window drag for child windows */
2483     if (parent) SystemParametersInfoW( SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0 );
2484
2485     /* repaint the window before moving it around */
2486     RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
2487
2488     SendMessageW( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
2489     set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
2490
2491     while(1)
2492     {
2493         int dx = 0, dy = 0;
2494
2495         if (!GetMessageW( &msg, 0, 0, 0 )) break;
2496         if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
2497
2498         /* Exit on button-up, Return, or Esc */
2499         if ((msg.message == WM_LBUTTONUP) ||
2500             ((msg.message == WM_KEYDOWN) &&
2501              ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
2502
2503         if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
2504         {
2505             TranslateMessage( &msg );
2506             DispatchMessageW( &msg );
2507             continue;  /* We are not interested in other messages */
2508         }
2509
2510         pt = msg.pt;
2511
2512         if (msg.message == WM_KEYDOWN) switch(msg.wParam)
2513         {
2514         case VK_UP:    pt.y -= 8; break;
2515         case VK_DOWN:  pt.y += 8; break;
2516         case VK_LEFT:  pt.x -= 8; break;
2517         case VK_RIGHT: pt.x += 8; break;
2518         }
2519
2520         pt.x = max( pt.x, mouseRect.left );
2521         pt.x = min( pt.x, mouseRect.right );
2522         pt.y = max( pt.y, mouseRect.top );
2523         pt.y = min( pt.y, mouseRect.bottom );
2524
2525         dx = pt.x - capturePoint.x;
2526         dy = pt.y - capturePoint.y;
2527
2528         if (dx || dy)
2529         {
2530             if( !moved )
2531             {
2532                 moved = TRUE;
2533
2534                 if( iconic ) /* ok, no system popup tracking */
2535                 {
2536                     hOldCursor = SetCursor(hDragCursor);
2537                     ShowCursor( TRUE );
2538                     WINPOS_ShowIconTitle( hwnd, FALSE );
2539                 }
2540                 else if(!DragFullWindows)
2541                     draw_moving_frame( hdc, &sizingRect, thickframe );
2542             }
2543
2544             if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
2545             else
2546             {
2547                 RECT newRect = sizingRect;
2548                 WPARAM wpSizingHit = 0;
2549
2550                 if (hittest == HTCAPTION) OffsetRect( &newRect, dx, dy );
2551                 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
2552                 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
2553                 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
2554                 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
2555                 if(!iconic && !DragFullWindows) draw_moving_frame( hdc, &sizingRect, thickframe );
2556                 capturePoint = pt;
2557
2558                 /* determine the hit location */
2559                 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
2560                     wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
2561                 SendMessageW( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&newRect );
2562
2563                 if (!iconic)
2564                 {
2565                     if(!DragFullWindows)
2566                         draw_moving_frame( hdc, &newRect, thickframe );
2567                     else
2568                         SetWindowPos( hwnd, 0, newRect.left, newRect.top,
2569                                       newRect.right - newRect.left,
2570                                       newRect.bottom - newRect.top,
2571                                       ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
2572                 }
2573                 sizingRect = newRect;
2574             }
2575         }
2576     }
2577
2578     if( iconic )
2579     {
2580         if( moved ) /* restore cursors, show icon title later on */
2581         {
2582             ShowCursor( FALSE );
2583             SetCursor( hOldCursor );
2584         }
2585     }
2586     else if (moved && !DragFullWindows)
2587     {
2588         draw_moving_frame( hdc, &sizingRect, thickframe );
2589     }
2590
2591     set_capture_window( 0, GUI_INMOVESIZE, NULL );
2592     ReleaseDC( parent, hdc );
2593
2594     if (HOOK_CallHooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect, TRUE ))
2595         moved = FALSE;
2596
2597     SendMessageW( hwnd, WM_EXITSIZEMOVE, 0, 0 );
2598     SendMessageW( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
2599
2600     /* window moved or resized */
2601     if (moved)
2602     {
2603         /* if the moving/resizing isn't canceled call SetWindowPos
2604          * with the new position or the new size of the window
2605          */
2606         if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
2607         {
2608             /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
2609             if(!DragFullWindows || iconic)
2610                 SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
2611                               sizingRect.right - sizingRect.left,
2612                               sizingRect.bottom - sizingRect.top,
2613                               ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
2614         }
2615         else
2616         { /* restore previous size/position */
2617             if(DragFullWindows)
2618                 SetWindowPos( hwnd, 0, origRect.left, origRect.top,
2619                               origRect.right - origRect.left,
2620                               origRect.bottom - origRect.top,
2621                               ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
2622         }
2623     }
2624
2625     if (IsIconic(hwnd))
2626     {
2627         /* Single click brings up the system menu when iconized */
2628
2629         if( !moved )
2630         {
2631             if(style & WS_SYSMENU )
2632                 SendMessageW( hwnd, WM_SYSCOMMAND,
2633                               SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
2634         }
2635         else WINPOS_ShowIconTitle( hwnd, TRUE );
2636     }
2637 }