hidclass.sys: Return STATUS_INVALID_USER_BUFFER if buffer_len is 0.
[wine.git] / dlls / user32 / winpos.c
blob6e96a4b5964c7a4c696ea2d88b376c33b1a2f0b5
1 /*
2 * Window position related functions.
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
5 * 1995, 1996, 1999 Alex Korobka
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.
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.
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
22 #include <stdarg.h>
23 #include <string.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winerror.h"
30 #include "wine/server.h"
31 #include "controls.h"
32 #include "user_private.h"
33 #include "wine/gdi_driver.h"
34 #include "win.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(win);
39 #define SWP_AGG_NOGEOMETRYCHANGE \
40 (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER)
41 #define SWP_AGG_NOPOSCHANGE \
42 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
43 #define SWP_AGG_STATUSFLAGS \
44 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
45 #define SWP_AGG_NOCLIENTCHANGE \
46 (SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
48 #define HAS_DLGFRAME(style,exStyle) \
49 (((exStyle) & WS_EX_DLGMODALFRAME) || \
50 (((style) & WS_DLGFRAME) && !((style) & WS_BORDER)))
52 #define HAS_THICKFRAME(style) \
53 (((style) & WS_THICKFRAME) && \
54 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
56 #define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1)
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))
67 #define PLACE_MIN 0x0001
68 #define PLACE_MAX 0x0002
69 #define PLACE_RECT 0x0004
71 typedef struct
73 struct user_object obj;
74 INT actualCount;
75 INT suggestedCount;
76 HWND hwndParent;
77 WINDOWPOS *winPos;
78 } DWP;
81 /***********************************************************************
82 * SwitchToThisWindow (USER32.@)
84 void WINAPI SwitchToThisWindow( HWND hwnd, BOOL alt_tab )
86 if (IsIconic( hwnd )) ShowWindow( hwnd, SW_RESTORE );
87 else BringWindowToTop( hwnd );
91 /***********************************************************************
92 * GetWindowRect (USER32.@)
94 BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect )
96 BOOL ret = WIN_GetRectangles( hwnd, COORDS_SCREEN, rect, NULL );
97 if (ret) TRACE( "hwnd %p %s\n", hwnd, wine_dbgstr_rect(rect) );
98 return ret;
102 /***********************************************************************
103 * GetWindowRgn (USER32.@)
105 int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn )
107 int nRet = ERROR;
108 NTSTATUS status;
109 HRGN win_rgn = 0;
110 RGNDATA *data;
111 size_t size = 256;
115 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 )))
117 SetLastError( ERROR_OUTOFMEMORY );
118 return ERROR;
120 SERVER_START_REQ( get_window_region )
122 req->window = wine_server_user_handle( hwnd );
123 wine_server_set_reply( req, data->Buffer, size );
124 if (!(status = wine_server_call( req )))
126 size_t reply_size = wine_server_reply_size( reply );
127 if (reply_size)
129 data->rdh.dwSize = sizeof(data->rdh);
130 data->rdh.iType = RDH_RECTANGLES;
131 data->rdh.nCount = reply_size / sizeof(RECT);
132 data->rdh.nRgnSize = reply_size;
133 win_rgn = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
136 else size = reply->total_size;
138 SERVER_END_REQ;
139 HeapFree( GetProcessHeap(), 0, data );
140 } while (status == STATUS_BUFFER_OVERFLOW);
142 if (status) SetLastError( RtlNtStatusToDosError(status) );
143 else if (win_rgn)
145 nRet = CombineRgn( hrgn, win_rgn, 0, RGN_COPY );
146 DeleteObject( win_rgn );
148 return nRet;
151 /***********************************************************************
152 * GetWindowRgnBox (USER32.@)
154 int WINAPI GetWindowRgnBox( HWND hwnd, LPRECT prect )
156 int ret = ERROR;
157 HRGN hrgn;
159 if (!prect)
160 return ERROR;
162 if ((hrgn = CreateRectRgn(0, 0, 0, 0)))
164 if ((ret = GetWindowRgn( hwnd, hrgn )) != ERROR )
165 ret = GetRgnBox( hrgn, prect );
166 DeleteObject(hrgn);
169 return ret;
172 /***********************************************************************
173 * SetWindowRgn (USER32.@)
175 int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw )
177 static const RECT empty_rect;
178 BOOL ret;
180 if (hrgn)
182 RGNDATA *data;
183 DWORD size;
185 if (!(size = GetRegionData( hrgn, 0, NULL ))) return FALSE;
186 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
187 if (!GetRegionData( hrgn, size, data ))
189 HeapFree( GetProcessHeap(), 0, data );
190 return FALSE;
192 SERVER_START_REQ( set_window_region )
194 req->window = wine_server_user_handle( hwnd );
195 req->redraw = (bRedraw != 0);
196 if (data->rdh.nCount)
197 wine_server_add_data( req, data->Buffer, data->rdh.nCount * sizeof(RECT) );
198 else
199 wine_server_add_data( req, &empty_rect, sizeof(empty_rect) );
200 ret = !wine_server_call_err( req );
202 SERVER_END_REQ;
203 HeapFree( GetProcessHeap(), 0, data );
205 else /* clear existing region */
207 SERVER_START_REQ( set_window_region )
209 req->window = wine_server_user_handle( hwnd );
210 req->redraw = (bRedraw != 0);
211 ret = !wine_server_call_err( req );
213 SERVER_END_REQ;
216 if (ret)
218 UINT swp_flags = SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE;
219 if (!bRedraw) swp_flags |= SWP_NOREDRAW;
220 USER_Driver->pSetWindowRgn( hwnd, hrgn, bRedraw );
221 SetWindowPos( hwnd, 0, 0, 0, 0, 0, swp_flags );
222 if (hrgn) DeleteObject( hrgn );
224 return ret;
228 /***********************************************************************
229 * GetClientRect (USER32.@)
231 BOOL WINAPI GetClientRect( HWND hwnd, LPRECT rect )
233 return WIN_GetRectangles( hwnd, COORDS_CLIENT, NULL, rect );
237 /***********************************************************************
238 * list_children_from_point
240 * Get the list of children that can contain point from the server.
241 * Point is in screen coordinates.
242 * Returned list must be freed by caller.
244 static HWND *list_children_from_point( HWND hwnd, POINT pt )
246 HWND *list;
247 int i, size = 128;
249 for (;;)
251 int count = 0;
253 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
255 SERVER_START_REQ( get_window_children_from_point )
257 req->parent = wine_server_user_handle( hwnd );
258 req->x = pt.x;
259 req->y = pt.y;
260 req->dpi = get_thread_dpi();
261 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
262 if (!wine_server_call( req )) count = reply->count;
264 SERVER_END_REQ;
265 if (count && count < size)
267 /* start from the end since HWND is potentially larger than user_handle_t */
268 for (i = count - 1; i >= 0; i--)
269 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
270 list[count] = 0;
271 return list;
273 HeapFree( GetProcessHeap(), 0, list );
274 if (!count) break;
275 size = count + 1; /* restart with a large enough buffer */
277 return NULL;
281 /***********************************************************************
282 * WINPOS_WindowFromPoint
284 * Find the window and hittest for a given point.
286 HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
288 int i, res;
289 HWND ret, *list;
290 POINT win_pt;
292 if (!hwndScope) hwndScope = GetDesktopWindow();
294 *hittest = HTNOWHERE;
296 if (!(list = list_children_from_point( hwndScope, pt ))) return 0;
298 /* now determine the hittest */
300 for (i = 0; list[i]; i++)
302 LONG style = GetWindowLongW( list[i], GWL_STYLE );
304 /* If window is minimized or disabled, return at once */
305 if (style & WS_DISABLED)
307 *hittest = HTERROR;
308 break;
310 /* Send WM_NCCHITTEST (if same thread) */
311 if (!WIN_IsCurrentThread( list[i] ))
313 *hittest = HTCLIENT;
314 break;
316 win_pt = point_thread_to_win_dpi( list[i], pt );
317 res = SendMessageW( list[i], WM_NCHITTEST, 0, MAKELPARAM( win_pt.x, win_pt.y ));
318 if (res != HTTRANSPARENT)
320 *hittest = res; /* Found the window */
321 break;
323 /* continue search with next window in z-order */
325 ret = list[i];
326 HeapFree( GetProcessHeap(), 0, list );
327 TRACE( "scope %p (%d,%d) returning %p\n", hwndScope, pt.x, pt.y, ret );
328 return ret;
332 /*******************************************************************
333 * WindowFromPoint (USER32.@)
335 HWND WINAPI WindowFromPoint( POINT pt )
337 INT hittest;
338 return WINPOS_WindowFromPoint( 0, pt, &hittest );
342 /*******************************************************************
343 * ChildWindowFromPoint (USER32.@)
345 HWND WINAPI ChildWindowFromPoint( HWND hwndParent, POINT pt )
347 return ChildWindowFromPointEx( hwndParent, pt, CWP_ALL );
350 /*******************************************************************
351 * RealChildWindowFromPoint (USER32.@)
353 HWND WINAPI RealChildWindowFromPoint( HWND hwndParent, POINT pt )
355 return ChildWindowFromPointEx( hwndParent, pt, CWP_SKIPTRANSPARENT | CWP_SKIPINVISIBLE );
358 /*******************************************************************
359 * ChildWindowFromPointEx (USER32.@)
361 HWND WINAPI ChildWindowFromPointEx( HWND hwndParent, POINT pt, UINT uFlags)
363 /* pt is in the client coordinates */
364 HWND *list;
365 int i;
366 RECT rect;
367 HWND retvalue;
369 GetClientRect( hwndParent, &rect );
370 if (!PtInRect( &rect, pt )) return 0;
371 if (!(list = WIN_ListChildren( hwndParent ))) return hwndParent;
373 for (i = 0; list[i]; i++)
375 if (!WIN_GetRectangles( list[i], COORDS_PARENT, &rect, NULL )) continue;
376 if (!PtInRect( &rect, pt )) continue;
377 if (uFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
379 LONG style = GetWindowLongW( list[i], GWL_STYLE );
380 if ((uFlags & CWP_SKIPINVISIBLE) && !(style & WS_VISIBLE)) continue;
381 if ((uFlags & CWP_SKIPDISABLED) && (style & WS_DISABLED)) continue;
383 if (uFlags & CWP_SKIPTRANSPARENT)
385 if (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TRANSPARENT) continue;
387 break;
389 retvalue = list[i];
390 HeapFree( GetProcessHeap(), 0, list );
391 if (!retvalue) retvalue = hwndParent;
392 return retvalue;
396 /*******************************************************************
397 * WINPOS_GetWinOffset
399 * Calculate the offset between the origin of the two windows. Used
400 * to implement MapWindowPoints.
402 static BOOL WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, BOOL *mirrored, POINT *ret_offset )
404 WND * wndPtr;
405 POINT offset;
406 BOOL mirror_from, mirror_to, ret;
407 HWND hwnd;
409 offset.x = offset.y = 0;
410 *mirrored = mirror_from = mirror_to = FALSE;
412 /* Translate source window origin to screen coords */
413 if (hwndFrom)
415 if (!(wndPtr = WIN_GetPtr( hwndFrom )))
417 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
418 return FALSE;
420 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
421 if (wndPtr != WND_DESKTOP)
423 if (wndPtr->dwExStyle & WS_EX_LAYOUTRTL)
425 mirror_from = TRUE;
426 offset.x += wndPtr->client_rect.right - wndPtr->client_rect.left;
428 while (wndPtr->parent)
430 offset.x += wndPtr->client_rect.left;
431 offset.y += wndPtr->client_rect.top;
432 hwnd = wndPtr->parent;
433 WIN_ReleasePtr( wndPtr );
434 if (!(wndPtr = WIN_GetPtr( hwnd ))) break;
435 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
436 if (wndPtr == WND_DESKTOP) break;
437 if (wndPtr->flags & WIN_CHILDREN_MOVED)
439 WIN_ReleasePtr( wndPtr );
440 goto other_process;
443 if (wndPtr && wndPtr != WND_DESKTOP) WIN_ReleasePtr( wndPtr );
444 offset = point_win_to_thread_dpi( hwndFrom, offset );
448 /* Translate origin to destination window coords */
449 if (hwndTo)
451 if (!(wndPtr = WIN_GetPtr( hwndTo )))
453 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
454 return FALSE;
456 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
457 if (wndPtr != WND_DESKTOP)
459 POINT pt = { 0, 0 };
460 if (wndPtr->dwExStyle & WS_EX_LAYOUTRTL)
462 mirror_to = TRUE;
463 pt.x += wndPtr->client_rect.right - wndPtr->client_rect.left;
465 while (wndPtr->parent)
467 pt.x += wndPtr->client_rect.left;
468 pt.y += wndPtr->client_rect.top;
469 hwnd = wndPtr->parent;
470 WIN_ReleasePtr( wndPtr );
471 if (!(wndPtr = WIN_GetPtr( hwnd ))) break;
472 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
473 if (wndPtr == WND_DESKTOP) break;
474 if (wndPtr->flags & WIN_CHILDREN_MOVED)
476 WIN_ReleasePtr( wndPtr );
477 goto other_process;
480 if (wndPtr && wndPtr != WND_DESKTOP) WIN_ReleasePtr( wndPtr );
481 pt = point_win_to_thread_dpi( hwndTo, pt );
482 offset.x -= pt.x;
483 offset.y -= pt.y;
487 *mirrored = mirror_from ^ mirror_to;
488 if (mirror_from) offset.x = -offset.x;
489 *ret_offset = offset;
490 return TRUE;
492 other_process: /* one of the parents may belong to another process, do it the hard way */
493 SERVER_START_REQ( get_windows_offset )
495 req->from = wine_server_user_handle( hwndFrom );
496 req->to = wine_server_user_handle( hwndTo );
497 req->dpi = get_thread_dpi();
498 if ((ret = !wine_server_call_err( req )))
500 ret_offset->x = reply->x;
501 ret_offset->y = reply->y;
502 *mirrored = reply->mirror;
505 SERVER_END_REQ;
506 return ret;
509 /* map coordinates of a window region */
510 void map_window_region( HWND from, HWND to, HRGN hrgn )
512 BOOL mirrored;
513 POINT offset;
514 UINT i, size;
515 RGNDATA *data;
516 HRGN new_rgn;
517 RECT *rect;
519 if (!WINPOS_GetWinOffset( from, to, &mirrored, &offset )) return;
521 if (!mirrored)
523 OffsetRgn( hrgn, offset.x, offset.y );
524 return;
526 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
527 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
528 GetRegionData( hrgn, size, data );
529 rect = (RECT *)data->Buffer;
530 for (i = 0; i < data->rdh.nCount; i++)
532 int tmp = -(rect[i].left + offset.x);
533 rect[i].left = -(rect[i].right + offset.x);
534 rect[i].right = tmp;
535 rect[i].top += offset.y;
536 rect[i].bottom += offset.y;
538 if ((new_rgn = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data )))
540 CombineRgn( hrgn, new_rgn, 0, RGN_COPY );
541 DeleteObject( new_rgn );
543 HeapFree( GetProcessHeap(), 0, data );
547 /*******************************************************************
548 * MapWindowPoints (USER32.@)
550 INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT count )
552 BOOL mirrored;
553 POINT offset;
554 UINT i;
556 if (!WINPOS_GetWinOffset( hwndFrom, hwndTo, &mirrored, &offset )) return 0;
558 for (i = 0; i < count; i++)
560 lppt[i].x += offset.x;
561 lppt[i].y += offset.y;
562 if (mirrored) lppt[i].x = -lppt[i].x;
564 if (mirrored && count == 2) /* special case for rectangle */
566 int tmp = lppt[0].x;
567 lppt[0].x = lppt[1].x;
568 lppt[1].x = tmp;
570 return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) );
574 /*******************************************************************
575 * ClientToScreen (USER32.@)
577 BOOL WINAPI ClientToScreen( HWND hwnd, LPPOINT lppnt )
579 POINT offset;
580 BOOL mirrored;
582 if (!hwnd)
584 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
585 return FALSE;
587 if (!WINPOS_GetWinOffset( hwnd, 0, &mirrored, &offset )) return FALSE;
588 lppnt->x += offset.x;
589 lppnt->y += offset.y;
590 if (mirrored) lppnt->x = -lppnt->x;
591 return TRUE;
595 /*******************************************************************
596 * ScreenToClient (USER32.@)
598 BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
600 POINT offset;
601 BOOL mirrored;
603 if (!hwnd)
605 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
606 return FALSE;
608 if (!WINPOS_GetWinOffset( 0, hwnd, &mirrored, &offset )) return FALSE;
609 lppnt->x += offset.x;
610 lppnt->y += offset.y;
611 if (mirrored) lppnt->x = -lppnt->x;
612 return TRUE;
616 /***********************************************************************
617 * IsIconic (USER32.@)
619 BOOL WINAPI IsIconic(HWND hWnd)
621 return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MINIMIZE) != 0;
625 /***********************************************************************
626 * IsZoomed (USER32.@)
628 BOOL WINAPI IsZoomed(HWND hWnd)
630 return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MAXIMIZE) != 0;
634 /*******************************************************************
635 * AllowSetForegroundWindow (USER32.@)
637 BOOL WINAPI AllowSetForegroundWindow( DWORD procid )
639 /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
640 * implemented, then fix this function. */
641 return TRUE;
645 /*******************************************************************
646 * LockSetForegroundWindow (USER32.@)
648 BOOL WINAPI LockSetForegroundWindow( UINT lockcode )
650 /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
651 * implemented, then fix this function. */
652 return TRUE;
656 /***********************************************************************
657 * BringWindowToTop (USER32.@)
659 BOOL WINAPI BringWindowToTop( HWND hwnd )
661 return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
665 /***********************************************************************
666 * MoveWindow (USER32.@)
668 BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
669 BOOL repaint )
671 int flags = SWP_NOZORDER | SWP_NOACTIVATE;
672 if (!repaint) flags |= SWP_NOREDRAW;
673 TRACE("%p %d,%d %dx%d %d\n", hwnd, x, y, cx, cy, repaint );
674 return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
678 /*******************************************************************
679 * WINPOS_GetMinMaxInfo
681 * Get the minimized and maximized information for a window.
683 MINMAXINFO WINPOS_GetMinMaxInfo( HWND hwnd )
685 DPI_AWARENESS_CONTEXT context;
686 MINMAXINFO MinMax;
687 HMONITOR monitor;
688 INT xinc, yinc;
689 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
690 LONG adjustedStyle;
691 LONG exstyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
692 RECT rc;
693 WND *win;
695 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
697 /* Compute default values */
699 GetWindowRect(hwnd, &rc);
700 MinMax.ptReserved.x = rc.left;
701 MinMax.ptReserved.y = rc.top;
703 if ((style & WS_CAPTION) == WS_CAPTION)
704 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
705 else
706 adjustedStyle = style;
708 GetClientRect(GetAncestor(hwnd,GA_PARENT), &rc);
709 AdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
711 xinc = -rc.left;
712 yinc = -rc.top;
714 MinMax.ptMaxSize.x = rc.right - rc.left;
715 MinMax.ptMaxSize.y = rc.bottom - rc.top;
716 if (style & (WS_DLGFRAME | WS_BORDER))
718 MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
719 MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
721 else
723 MinMax.ptMinTrackSize.x = 2 * xinc;
724 MinMax.ptMinTrackSize.y = 2 * yinc;
726 MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
727 MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
728 MinMax.ptMaxPosition.x = -xinc;
729 MinMax.ptMaxPosition.y = -yinc;
731 if ((win = WIN_GetPtr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS)
733 if (!EMPTYPOINT(win->max_pos)) MinMax.ptMaxPosition = win->max_pos;
734 WIN_ReleasePtr( win );
737 SendMessageW( hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
739 /* if the app didn't change the values, adapt them for the current monitor */
741 if ((monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY )))
743 RECT rc_work, rc_primary;
744 MONITORINFO mon_info;
746 mon_info.cbSize = sizeof(mon_info);
747 GetMonitorInfoW( monitor, &mon_info );
749 rc_work = mon_info.rcMonitor;
751 if (style & WS_MAXIMIZEBOX)
753 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
754 rc_work = mon_info.rcWork;
757 rc_primary = get_primary_monitor_rect();
758 if (MinMax.ptMaxSize.x == (rc_primary.right - rc_primary.left) + 2 * xinc &&
759 MinMax.ptMaxSize.y == (rc_primary.bottom - rc_primary.top) + 2 * yinc)
761 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
762 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
764 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
766 MinMax.ptMaxPosition.x = rc_work.left - xinc;
767 MinMax.ptMaxPosition.y = rc_work.top - yinc;
771 /* Some sanity checks */
773 TRACE("%d %d / %d %d / %d %d / %d %d\n",
774 MinMax.ptMaxSize.x, MinMax.ptMaxSize.y,
775 MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y,
776 MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y,
777 MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y);
778 MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x,
779 MinMax.ptMinTrackSize.x );
780 MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y,
781 MinMax.ptMinTrackSize.y );
783 SetThreadDpiAwarenessContext( context );
784 return MinMax;
787 static POINT get_first_minimized_child_pos( const RECT *parent, const MINIMIZEDMETRICS *mm,
788 int width, int height )
790 POINT ret;
792 if (mm->iArrange & ARW_STARTRIGHT)
793 ret.x = parent->right - mm->iHorzGap - width;
794 else
795 ret.x = parent->left + mm->iHorzGap;
796 if (mm->iArrange & ARW_STARTTOP)
797 ret.y = parent->top + mm->iVertGap;
798 else
799 ret.y = parent->bottom - mm->iVertGap - height;
801 return ret;
804 static void get_next_minimized_child_pos( const RECT *parent, const MINIMIZEDMETRICS *mm,
805 int width, int height, POINT *pos )
807 BOOL next;
809 if (mm->iArrange & ARW_UP) /* == ARW_DOWN */
811 if (mm->iArrange & ARW_STARTTOP)
813 pos->y += height + mm->iVertGap;
814 if ((next = pos->y + height > parent->bottom))
815 pos->y = parent->top + mm->iVertGap;
817 else
819 pos->y -= height + mm->iVertGap;
820 if ((next = pos->y < parent->top))
821 pos->y = parent->bottom - mm->iVertGap - height;
824 if (next)
826 if (mm->iArrange & ARW_STARTRIGHT)
827 pos->x -= width + mm->iHorzGap;
828 else
829 pos->x += width + mm->iHorzGap;
832 else
834 if (mm->iArrange & ARW_STARTRIGHT)
836 pos->x -= width + mm->iHorzGap;
837 if ((next = pos->x < parent->left))
838 pos->x = parent->right - mm->iHorzGap - width;
840 else
842 pos->x += width + mm->iHorzGap;
843 if ((next = pos->x + width > parent->right))
844 pos->x = parent->left + mm->iHorzGap;
847 if (next)
849 if (mm->iArrange & ARW_STARTTOP)
850 pos->y += height + mm->iVertGap;
851 else
852 pos->y -= height + mm->iVertGap;
857 static POINT get_minimized_pos( HWND hwnd, POINT pt )
859 RECT rect, rectParent;
860 HWND parent, child;
861 HRGN hrgn, tmp;
862 MINIMIZEDMETRICS metrics;
863 int width, height;
865 parent = GetAncestor( hwnd, GA_PARENT );
866 if (parent == GetDesktopWindow())
868 MONITORINFO mon_info;
869 HMONITOR monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY );
871 mon_info.cbSize = sizeof( mon_info );
872 GetMonitorInfoW( monitor, &mon_info );
873 rectParent = mon_info.rcWork;
875 else GetClientRect( parent, &rectParent );
877 if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics( SM_CXMINIMIZED ) < rectParent.right) &&
878 (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics( SM_CYMINIMIZED ) < rectParent.bottom))
879 return pt; /* The icon already has a suitable position */
881 width = GetSystemMetrics( SM_CXMINIMIZED );
882 height = GetSystemMetrics( SM_CYMINIMIZED );
884 metrics.cbSize = sizeof(metrics);
885 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(metrics), &metrics, 0 );
887 /* Check if another icon already occupies this spot */
888 /* FIXME: this is completely inefficient */
890 hrgn = CreateRectRgn( 0, 0, 0, 0 );
891 tmp = CreateRectRgn( 0, 0, 0, 0 );
892 for (child = GetWindow( parent, GW_CHILD ); child; child = GetWindow( child, GW_HWNDNEXT ))
894 if (child == hwnd) continue;
895 if ((GetWindowLongW( child, GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE))
896 continue;
897 if (WIN_GetRectangles( child, COORDS_PARENT, &rect, NULL ))
899 SetRectRgn( tmp, rect.left, rect.top, rect.right, rect.bottom );
900 CombineRgn( hrgn, hrgn, tmp, RGN_OR );
903 DeleteObject( tmp );
905 pt = get_first_minimized_child_pos( &rectParent, &metrics, width, height );
906 for (;;)
908 SetRect( &rect, pt.x, pt.y, pt.x + width, pt.y + height );
909 if (!RectInRegion( hrgn, &rect ))
910 break;
912 get_next_minimized_child_pos( &rectParent, &metrics, width, height, &pt );
915 DeleteObject( hrgn );
916 return pt;
920 /***********************************************************************
921 * WINPOS_MinMaximize
923 UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
925 UINT swpFlags = 0;
926 LONG old_style;
927 MINMAXINFO minmax;
928 WINDOWPLACEMENT wpl;
930 TRACE("%p %u\n", hwnd, cmd );
932 wpl.length = sizeof(wpl);
933 GetWindowPlacement( hwnd, &wpl );
935 if (HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd, TRUE ))
936 return SWP_NOSIZE | SWP_NOMOVE;
938 if (IsIconic( hwnd ))
940 switch (cmd)
942 case SW_SHOWMINNOACTIVE:
943 case SW_SHOWMINIMIZED:
944 case SW_FORCEMINIMIZE:
945 case SW_MINIMIZE:
946 wpl.ptMinPosition = get_minimized_pos( hwnd, wpl.ptMinPosition );
948 SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
949 wpl.ptMinPosition.x + GetSystemMetrics(SM_CXMINIMIZED),
950 wpl.ptMinPosition.y + GetSystemMetrics(SM_CYMINIMIZED) );
951 return SWP_NOSIZE | SWP_NOMOVE;
953 if (!SendMessageW( hwnd, WM_QUERYOPEN, 0, 0 )) return SWP_NOSIZE | SWP_NOMOVE;
954 swpFlags |= SWP_NOCOPYBITS;
957 switch( cmd )
959 case SW_SHOWMINNOACTIVE:
960 case SW_SHOWMINIMIZED:
961 case SW_FORCEMINIMIZE:
962 case SW_MINIMIZE:
963 if (IsZoomed( hwnd )) win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
964 else win_set_flags( hwnd, 0, WIN_RESTORE_MAX );
966 if (GetFocus() == hwnd)
968 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_CHILD)
969 SetFocus(GetAncestor(hwnd, GA_PARENT));
970 else
971 SetFocus(0);
974 old_style = WIN_SetStyle( hwnd, WS_MINIMIZE, WS_MAXIMIZE );
976 wpl.ptMinPosition = get_minimized_pos( hwnd, wpl.ptMinPosition );
978 if (!(old_style & WS_MINIMIZE)) swpFlags |= SWP_STATECHANGED;
979 SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
980 wpl.ptMinPosition.x + GetSystemMetrics(SM_CXMINIMIZED),
981 wpl.ptMinPosition.y + GetSystemMetrics(SM_CYMINIMIZED) );
982 swpFlags |= SWP_NOCOPYBITS;
983 break;
985 case SW_MAXIMIZE:
986 old_style = GetWindowLongW( hwnd, GWL_STYLE );
987 if ((old_style & WS_MAXIMIZE) && (old_style & WS_VISIBLE)) return SWP_NOSIZE | SWP_NOMOVE;
989 minmax = WINPOS_GetMinMaxInfo( hwnd );
991 old_style = WIN_SetStyle( hwnd, WS_MAXIMIZE, WS_MINIMIZE );
992 if (old_style & WS_MINIMIZE)
993 win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
995 if (!(old_style & WS_MAXIMIZE)) swpFlags |= SWP_STATECHANGED;
996 SetRect( rect, minmax.ptMaxPosition.x, minmax.ptMaxPosition.y,
997 minmax.ptMaxPosition.x + minmax.ptMaxSize.x, minmax.ptMaxPosition.y + minmax.ptMaxSize.y );
998 break;
1000 case SW_SHOWNOACTIVATE:
1001 win_set_flags( hwnd, 0, WIN_RESTORE_MAX );
1002 /* fall through */
1003 case SW_SHOWNORMAL:
1004 case SW_RESTORE:
1005 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1006 old_style = WIN_SetStyle( hwnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
1007 if (old_style & WS_MINIMIZE)
1009 if (win_get_flags( hwnd ) & WIN_RESTORE_MAX)
1011 /* Restore to maximized position */
1012 minmax = WINPOS_GetMinMaxInfo( hwnd );
1013 WIN_SetStyle( hwnd, WS_MAXIMIZE, 0 );
1014 swpFlags |= SWP_STATECHANGED;
1015 SetRect( rect, minmax.ptMaxPosition.x, minmax.ptMaxPosition.y,
1016 minmax.ptMaxPosition.x + minmax.ptMaxSize.x, minmax.ptMaxPosition.y + minmax.ptMaxSize.y );
1017 break;
1020 else if (!(old_style & WS_MAXIMIZE)) break;
1022 swpFlags |= SWP_STATECHANGED;
1024 /* Restore to normal position */
1026 *rect = wpl.rcNormalPosition;
1027 break;
1030 return swpFlags;
1034 /***********************************************************************
1035 * show_window
1037 * Implementation of ShowWindow and ShowWindowAsync.
1039 static BOOL show_window( HWND hwnd, INT cmd )
1041 WND *wndPtr;
1042 HWND parent;
1043 DPI_AWARENESS_CONTEXT context;
1044 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1045 BOOL wasVisible = (style & WS_VISIBLE) != 0;
1046 BOOL showFlag = TRUE;
1047 RECT newPos = {0, 0, 0, 0};
1048 UINT new_swp, swp = 0;
1050 TRACE("hwnd=%p, cmd=%d, wasVisible %d\n", hwnd, cmd, wasVisible);
1052 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
1054 switch(cmd)
1056 case SW_HIDE:
1057 if (!wasVisible) goto done;
1058 showFlag = FALSE;
1059 swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1060 if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1061 break;
1063 case SW_SHOWMINNOACTIVE:
1064 case SW_MINIMIZE:
1065 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
1066 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1067 /* fall through */
1068 case SW_SHOWMINIMIZED:
1069 swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1070 swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
1071 if ((style & WS_MINIMIZE) && wasVisible) goto done;
1072 break;
1074 case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
1075 if (!wasVisible) swp |= SWP_SHOWWINDOW;
1076 swp |= SWP_FRAMECHANGED;
1077 swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
1078 if ((style & WS_MAXIMIZE) && wasVisible) goto done;
1079 break;
1081 case SW_SHOWNA:
1082 swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1083 if (style & WS_CHILD) swp |= SWP_NOZORDER;
1084 break;
1085 case SW_SHOW:
1086 if (wasVisible) goto done;
1087 swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1088 if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1089 break;
1091 case SW_SHOWNOACTIVATE:
1092 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1093 /* fall through */
1094 case SW_RESTORE:
1095 /* fall through */
1096 case SW_SHOWNORMAL: /* same as SW_NORMAL: */
1097 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1098 if (!wasVisible) swp |= SWP_SHOWWINDOW;
1099 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1101 swp |= SWP_FRAMECHANGED;
1102 swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
1104 else
1106 if (wasVisible) goto done;
1107 swp |= SWP_NOSIZE | SWP_NOMOVE;
1109 if (style & WS_CHILD && !(swp & SWP_STATECHANGED)) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1110 break;
1111 default:
1112 goto done;
1115 if ((showFlag != wasVisible || cmd == SW_SHOWNA) && cmd != SW_SHOWMAXIMIZED && !(swp & SWP_STATECHANGED))
1117 SendMessageW( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1118 if (!IsWindow( hwnd )) goto done;
1121 if (IsRectEmpty( &newPos )) new_swp = swp;
1122 else if ((new_swp = USER_Driver->pShowWindow( hwnd, cmd, &newPos, swp )) == ~0)
1124 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) new_swp = swp;
1125 else if (IsIconic( hwnd ) && (newPos.left != -32000 || newPos.top != -32000))
1127 OffsetRect( &newPos, -32000 - newPos.left, -32000 - newPos.top );
1128 new_swp = swp & ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1130 else new_swp = swp;
1132 swp = new_swp;
1134 parent = GetAncestor( hwnd, GA_PARENT );
1135 if (parent && !IsWindowVisible( parent ) && !(swp & SWP_STATECHANGED))
1137 /* if parent is not visible simply toggle WS_VISIBLE and return */
1138 if (showFlag) WIN_SetStyle( hwnd, WS_VISIBLE, 0 );
1139 else WIN_SetStyle( hwnd, 0, WS_VISIBLE );
1141 else
1142 SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
1143 newPos.right - newPos.left, newPos.bottom - newPos.top, swp );
1145 if (cmd == SW_HIDE)
1147 HWND hFocus;
1149 /* FIXME: This will cause the window to be activated irrespective
1150 * of whether it is owned by the same thread. Has to be done
1151 * asynchronously.
1154 if (hwnd == GetActiveWindow())
1155 WINPOS_ActivateOtherWindow(hwnd);
1157 /* Revert focus to parent */
1158 hFocus = GetFocus();
1159 if (hwnd == hFocus)
1161 HWND parent = GetAncestor(hwnd, GA_PARENT);
1162 if (parent == GetDesktopWindow()) parent = 0;
1163 SetFocus(parent);
1165 goto done;
1168 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) goto done;
1170 if (wndPtr->flags & WIN_NEED_SIZE)
1172 /* should happen only in CreateWindowEx() */
1173 int wParam = SIZE_RESTORED;
1174 RECT client;
1175 LPARAM lparam;
1177 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &client );
1178 lparam = MAKELONG( client.right - client.left, client.bottom - client.top );
1179 wndPtr->flags &= ~WIN_NEED_SIZE;
1180 if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
1181 else if (wndPtr->dwStyle & WS_MINIMIZE)
1183 wParam = SIZE_MINIMIZED;
1184 lparam = 0;
1186 WIN_ReleasePtr( wndPtr );
1188 SendMessageW( hwnd, WM_SIZE, wParam, lparam );
1189 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( client.left, client.top ));
1191 else WIN_ReleasePtr( wndPtr );
1193 /* if previous state was minimized Windows sets focus to the window */
1194 if (style & WS_MINIMIZE)
1196 SetFocus( hwnd );
1197 /* Send a WM_ACTIVATE message for a top level window, even if the window is already active */
1198 if (GetAncestor( hwnd, GA_ROOT ) == hwnd && !(swp & SWP_NOACTIVATE))
1199 SendMessageW( hwnd, WM_ACTIVATE, WA_ACTIVE, 0 );
1202 done:
1203 SetThreadDpiAwarenessContext( context );
1204 return wasVisible;
1208 /***********************************************************************
1209 * ShowWindowAsync (USER32.@)
1211 * doesn't wait; returns immediately.
1212 * used by threads to toggle windows in other (possibly hanging) threads
1214 BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd )
1216 HWND full_handle;
1218 if (is_broadcast(hwnd))
1220 SetLastError( ERROR_INVALID_PARAMETER );
1221 return FALSE;
1224 if ((full_handle = WIN_IsCurrentThread( hwnd )))
1225 return show_window( full_handle, cmd );
1227 return SendNotifyMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
1231 /***********************************************************************
1232 * ShowWindow (USER32.@)
1234 BOOL WINAPI ShowWindow( HWND hwnd, INT cmd )
1236 HWND full_handle;
1238 if (is_broadcast(hwnd))
1240 SetLastError( ERROR_INVALID_PARAMETER );
1241 return FALSE;
1243 if ((full_handle = WIN_IsCurrentThread( hwnd )))
1244 return show_window( full_handle, cmd );
1246 if ((cmd == SW_HIDE) && !(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
1247 return FALSE;
1249 if ((cmd == SW_SHOW) && (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
1250 return TRUE;
1252 return SendMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
1256 /***********************************************************************
1257 * GetInternalWindowPos (USER32.@)
1259 UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd,
1260 LPPOINT ptIcon )
1262 WINDOWPLACEMENT wndpl;
1264 wndpl.length = sizeof(wndpl);
1265 if (GetWindowPlacement( hwnd, &wndpl ))
1267 if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
1268 if (ptIcon) *ptIcon = wndpl.ptMinPosition;
1269 return wndpl.showCmd;
1271 return 0;
1275 /***********************************************************************
1276 * GetWindowPlacement (USER32.@)
1278 * Win95:
1279 * Fails if wndpl->length of Win95 (!) apps is invalid.
1281 BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
1283 WND *pWnd = WIN_GetPtr( hwnd );
1285 if (!pWnd) return FALSE;
1287 if (pWnd == WND_DESKTOP)
1289 wndpl->length = sizeof(*wndpl);
1290 wndpl->showCmd = SW_SHOWNORMAL;
1291 wndpl->flags = 0;
1292 wndpl->ptMinPosition.x = -1;
1293 wndpl->ptMinPosition.y = -1;
1294 wndpl->ptMaxPosition.x = -1;
1295 wndpl->ptMaxPosition.y = -1;
1296 GetWindowRect( hwnd, &wndpl->rcNormalPosition );
1297 return TRUE;
1299 if (pWnd == WND_OTHER_PROCESS)
1301 RECT normal_position;
1302 DWORD style;
1304 if (!GetWindowRect(hwnd, &normal_position))
1305 return FALSE;
1307 FIXME("not fully supported on other process window %p.\n", hwnd);
1309 wndpl->length = sizeof(*wndpl);
1310 style = GetWindowLongW(hwnd, GWL_STYLE);
1311 if (style & WS_MINIMIZE)
1312 wndpl->showCmd = SW_SHOWMINIMIZED;
1313 else
1314 wndpl->showCmd = (style & WS_MAXIMIZE) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL;
1315 /* provide some dummy information */
1316 wndpl->flags = 0;
1317 wndpl->ptMinPosition.x = -1;
1318 wndpl->ptMinPosition.y = -1;
1319 wndpl->ptMaxPosition.x = -1;
1320 wndpl->ptMaxPosition.y = -1;
1321 wndpl->rcNormalPosition = normal_position;
1322 return TRUE;
1325 /* update the placement according to the current style */
1326 if (pWnd->dwStyle & WS_MINIMIZE)
1328 pWnd->min_pos.x = pWnd->window_rect.left;
1329 pWnd->min_pos.y = pWnd->window_rect.top;
1331 else if (pWnd->dwStyle & WS_MAXIMIZE)
1333 pWnd->max_pos.x = pWnd->window_rect.left;
1334 pWnd->max_pos.y = pWnd->window_rect.top;
1336 else
1338 pWnd->normal_rect = pWnd->window_rect;
1341 wndpl->length = sizeof(*wndpl);
1342 if( pWnd->dwStyle & WS_MINIMIZE )
1343 wndpl->showCmd = SW_SHOWMINIMIZED;
1344 else
1345 wndpl->showCmd = ( pWnd->dwStyle & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
1346 if( pWnd->flags & WIN_RESTORE_MAX )
1347 wndpl->flags = WPF_RESTORETOMAXIMIZED;
1348 else
1349 wndpl->flags = 0;
1350 wndpl->ptMinPosition = EMPTYPOINT(pWnd->min_pos) ? pWnd->min_pos : point_win_to_thread_dpi( hwnd, pWnd->min_pos );
1351 wndpl->ptMaxPosition = EMPTYPOINT(pWnd->max_pos) ? pWnd->max_pos : point_win_to_thread_dpi( hwnd, pWnd->max_pos );
1352 wndpl->rcNormalPosition = rect_win_to_thread_dpi( hwnd, pWnd->normal_rect );
1353 WIN_ReleasePtr( pWnd );
1355 TRACE( "%p: returning min %d,%d max %d,%d normal %s\n",
1356 hwnd, wndpl->ptMinPosition.x, wndpl->ptMinPosition.y,
1357 wndpl->ptMaxPosition.x, wndpl->ptMaxPosition.y,
1358 wine_dbgstr_rect(&wndpl->rcNormalPosition) );
1359 return TRUE;
1362 /* make sure the specified rect is visible on screen */
1363 static void make_rect_onscreen( RECT *rect )
1365 MONITORINFO info;
1366 HMONITOR monitor = MonitorFromRect( rect, MONITOR_DEFAULTTONEAREST );
1368 info.cbSize = sizeof(info);
1369 if (!monitor || !GetMonitorInfoW( monitor, &info )) return;
1370 /* FIXME: map coordinates from rcWork to rcMonitor */
1371 if (rect->right <= info.rcWork.left)
1373 rect->right += info.rcWork.left - rect->left;
1374 rect->left = info.rcWork.left;
1376 else if (rect->left >= info.rcWork.right)
1378 rect->left += info.rcWork.right - rect->right;
1379 rect->right = info.rcWork.right;
1381 if (rect->bottom <= info.rcWork.top)
1383 rect->bottom += info.rcWork.top - rect->top;
1384 rect->top = info.rcWork.top;
1386 else if (rect->top >= info.rcWork.bottom)
1388 rect->top += info.rcWork.bottom - rect->bottom;
1389 rect->bottom = info.rcWork.bottom;
1393 /* make sure the specified point is visible on screen */
1394 static void make_point_onscreen( POINT *pt )
1396 RECT rect;
1398 SetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 );
1399 make_rect_onscreen( &rect );
1400 pt->x = rect.left;
1401 pt->y = rect.top;
1405 /***********************************************************************
1406 * WINPOS_SetPlacement
1408 static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT flags )
1410 DWORD style;
1411 WND *pWnd = WIN_GetPtr( hwnd );
1412 WINDOWPLACEMENT wp = *wndpl;
1414 if (flags & PLACE_MIN) make_point_onscreen( &wp.ptMinPosition );
1415 if (flags & PLACE_MAX) make_point_onscreen( &wp.ptMaxPosition );
1416 if (flags & PLACE_RECT) make_rect_onscreen( &wp.rcNormalPosition );
1418 TRACE( "%p: setting min %d,%d max %d,%d normal %s flags %x adjusted to min %d,%d max %d,%d normal %s\n",
1419 hwnd, wndpl->ptMinPosition.x, wndpl->ptMinPosition.y,
1420 wndpl->ptMaxPosition.x, wndpl->ptMaxPosition.y,
1421 wine_dbgstr_rect(&wndpl->rcNormalPosition), flags,
1422 wp.ptMinPosition.x, wp.ptMinPosition.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y,
1423 wine_dbgstr_rect(&wp.rcNormalPosition) );
1425 if (!pWnd || pWnd == WND_OTHER_PROCESS || pWnd == WND_DESKTOP) return FALSE;
1427 if (flags & PLACE_MIN) pWnd->min_pos = point_thread_to_win_dpi( hwnd, wp.ptMinPosition );
1428 if (flags & PLACE_MAX) pWnd->max_pos = point_thread_to_win_dpi( hwnd, wp.ptMaxPosition );
1429 if (flags & PLACE_RECT) pWnd->normal_rect = rect_thread_to_win_dpi( hwnd, wp.rcNormalPosition );
1431 style = pWnd->dwStyle;
1433 WIN_ReleasePtr( pWnd );
1435 if( style & WS_MINIMIZE )
1437 if (flags & PLACE_MIN)
1439 SetWindowPos( hwnd, 0, wp.ptMinPosition.x, wp.ptMinPosition.y, 0, 0,
1440 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1443 else if( style & WS_MAXIMIZE )
1445 if (flags & PLACE_MAX)
1446 SetWindowPos( hwnd, 0, wp.ptMaxPosition.x, wp.ptMaxPosition.y, 0, 0,
1447 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1449 else if( flags & PLACE_RECT )
1450 SetWindowPos( hwnd, 0, wp.rcNormalPosition.left, wp.rcNormalPosition.top,
1451 wp.rcNormalPosition.right - wp.rcNormalPosition.left,
1452 wp.rcNormalPosition.bottom - wp.rcNormalPosition.top,
1453 SWP_NOZORDER | SWP_NOACTIVATE );
1455 ShowWindow( hwnd, wndpl->showCmd );
1457 if (IsIconic( hwnd ))
1459 /* SDK: ...valid only the next time... */
1460 if( wndpl->flags & WPF_RESTORETOMAXIMIZED )
1461 win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
1463 return TRUE;
1467 /***********************************************************************
1468 * SetWindowPlacement (USER32.@)
1470 * Win95:
1471 * Fails if wndpl->length of Win95 (!) apps is invalid.
1473 BOOL WINAPI SetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl )
1475 UINT flags = PLACE_MAX | PLACE_RECT;
1476 if (!wpl) return FALSE;
1477 if (wpl->flags & WPF_SETMINPOSITION) flags |= PLACE_MIN;
1478 return WINPOS_SetPlacement( hwnd, wpl, flags );
1482 /***********************************************************************
1483 * AnimateWindow (USER32.@)
1484 * Shows/Hides a window with an animation
1485 * NO ANIMATION YET
1487 BOOL WINAPI AnimateWindow(HWND hwnd, DWORD dwTime, DWORD dwFlags)
1489 FIXME("partial stub\n");
1491 /* If trying to show/hide and it's already *
1492 * shown/hidden or invalid window, fail with *
1493 * invalid parameter */
1494 if(!IsWindow(hwnd) ||
1495 (IsWindowVisible(hwnd) && !(dwFlags & AW_HIDE)) ||
1496 (!IsWindowVisible(hwnd) && (dwFlags & AW_HIDE)))
1498 SetLastError(ERROR_INVALID_PARAMETER);
1499 return FALSE;
1502 ShowWindow(hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA));
1504 return TRUE;
1507 /***********************************************************************
1508 * SetInternalWindowPos (USER32.@)
1510 void WINAPI SetInternalWindowPos( HWND hwnd, UINT showCmd,
1511 LPRECT rect, LPPOINT pt )
1513 WINDOWPLACEMENT wndpl;
1514 UINT flags;
1516 wndpl.length = sizeof(wndpl);
1517 wndpl.showCmd = showCmd;
1518 wndpl.flags = flags = 0;
1520 if( pt )
1522 flags |= PLACE_MIN;
1523 wndpl.flags |= WPF_SETMINPOSITION;
1524 wndpl.ptMinPosition = *pt;
1526 if( rect )
1528 flags |= PLACE_RECT;
1529 wndpl.rcNormalPosition = *rect;
1531 WINPOS_SetPlacement( hwnd, &wndpl, flags );
1535 /*******************************************************************
1536 * can_activate_window
1538 * Check if we can activate the specified window.
1540 static BOOL can_activate_window( HWND hwnd )
1542 LONG style;
1544 if (!hwnd) return FALSE;
1545 style = GetWindowLongW( hwnd, GWL_STYLE );
1546 if (!(style & WS_VISIBLE)) return FALSE;
1547 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
1548 return !(style & WS_DISABLED);
1552 /*******************************************************************
1553 * WINPOS_ActivateOtherWindow
1555 * Activates window other than pWnd.
1557 void WINPOS_ActivateOtherWindow(HWND hwnd)
1559 HWND hwndTo, fg;
1561 if ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) && (hwndTo = GetWindow( hwnd, GW_OWNER )))
1563 hwndTo = GetAncestor( hwndTo, GA_ROOT );
1564 if (can_activate_window( hwndTo )) goto done;
1567 hwndTo = hwnd;
1568 for (;;)
1570 if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break;
1571 if (can_activate_window( hwndTo )) goto done;
1574 hwndTo = GetTopWindow( 0 );
1575 for (;;)
1577 if (hwndTo == hwnd)
1579 hwndTo = 0;
1580 break;
1582 if (can_activate_window( hwndTo )) goto done;
1583 if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break;
1586 done:
1587 fg = GetForegroundWindow();
1588 TRACE("win = %p fg = %p\n", hwndTo, fg);
1589 if (!fg || (hwnd == fg))
1591 if (SetForegroundWindow( hwndTo )) return;
1593 if (!SetActiveWindow( hwndTo )) SetActiveWindow(0);
1597 /***********************************************************************
1598 * WINPOS_HandleWindowPosChanging
1600 * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
1602 LONG WINPOS_HandleWindowPosChanging( HWND hwnd, WINDOWPOS *winpos )
1604 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1606 if (winpos->flags & SWP_NOSIZE) return 0;
1607 if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0))
1609 MINMAXINFO info = WINPOS_GetMinMaxInfo( hwnd );
1610 winpos->cx = min( winpos->cx, info.ptMaxTrackSize.x );
1611 winpos->cy = min( winpos->cy, info.ptMaxTrackSize.y );
1612 if (!(style & WS_MINIMIZE))
1614 winpos->cx = max( winpos->cx, info.ptMinTrackSize.x );
1615 winpos->cy = max( winpos->cy, info.ptMinTrackSize.y );
1618 return 0;
1622 /***********************************************************************
1623 * dump_winpos_flags
1625 static void dump_winpos_flags(UINT flags)
1627 static const DWORD dumped_flags = (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW |
1628 SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW |
1629 SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOOWNERZORDER |
1630 SWP_NOSENDCHANGING | SWP_DEFERERASE | SWP_ASYNCWINDOWPOS |
1631 SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_STATECHANGED);
1632 TRACE("flags:");
1633 if(flags & SWP_NOSIZE) TRACE(" SWP_NOSIZE");
1634 if(flags & SWP_NOMOVE) TRACE(" SWP_NOMOVE");
1635 if(flags & SWP_NOZORDER) TRACE(" SWP_NOZORDER");
1636 if(flags & SWP_NOREDRAW) TRACE(" SWP_NOREDRAW");
1637 if(flags & SWP_NOACTIVATE) TRACE(" SWP_NOACTIVATE");
1638 if(flags & SWP_FRAMECHANGED) TRACE(" SWP_FRAMECHANGED");
1639 if(flags & SWP_SHOWWINDOW) TRACE(" SWP_SHOWWINDOW");
1640 if(flags & SWP_HIDEWINDOW) TRACE(" SWP_HIDEWINDOW");
1641 if(flags & SWP_NOCOPYBITS) TRACE(" SWP_NOCOPYBITS");
1642 if(flags & SWP_NOOWNERZORDER) TRACE(" SWP_NOOWNERZORDER");
1643 if(flags & SWP_NOSENDCHANGING) TRACE(" SWP_NOSENDCHANGING");
1644 if(flags & SWP_DEFERERASE) TRACE(" SWP_DEFERERASE");
1645 if(flags & SWP_ASYNCWINDOWPOS) TRACE(" SWP_ASYNCWINDOWPOS");
1646 if(flags & SWP_NOCLIENTSIZE) TRACE(" SWP_NOCLIENTSIZE");
1647 if(flags & SWP_NOCLIENTMOVE) TRACE(" SWP_NOCLIENTMOVE");
1648 if(flags & SWP_STATECHANGED) TRACE(" SWP_STATECHANGED");
1650 if(flags & ~dumped_flags) TRACE(" %08x", flags & ~dumped_flags);
1651 TRACE("\n");
1655 /***********************************************************************
1656 * map_dpi_winpos
1658 static void map_dpi_winpos( WINDOWPOS *winpos )
1660 UINT dpi_from = get_thread_dpi();
1661 UINT dpi_to = GetDpiForWindow( winpos->hwnd );
1663 if (!dpi_from) dpi_from = get_win_monitor_dpi( winpos->hwnd );
1664 if (dpi_from == dpi_to) return;
1665 winpos->x = MulDiv( winpos->x, dpi_to, dpi_from );
1666 winpos->y = MulDiv( winpos->y, dpi_to, dpi_from );
1667 winpos->cx = MulDiv( winpos->cx, dpi_to, dpi_from );
1668 winpos->cy = MulDiv( winpos->cy, dpi_to, dpi_from );
1671 /***********************************************************************
1672 * SWP_DoWinPosChanging
1674 static BOOL SWP_DoWinPosChanging( WINDOWPOS *pWinpos, RECT *old_window_rect, RECT *old_client_rect,
1675 RECT *new_window_rect, RECT *new_client_rect )
1677 WND *wndPtr;
1679 /* Send WM_WINDOWPOSCHANGING message */
1681 if (!(pWinpos->flags & SWP_NOSENDCHANGING)
1682 && !((pWinpos->flags & SWP_AGG_NOCLIENTCHANGE) && (pWinpos->flags & SWP_SHOWWINDOW)))
1683 SendMessageW( pWinpos->hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
1685 if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) ||
1686 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
1688 /* Calculate new position and size */
1690 WIN_GetRectangles( pWinpos->hwnd, COORDS_PARENT, old_window_rect, old_client_rect );
1691 *new_window_rect = *old_window_rect;
1692 *new_client_rect = *old_client_rect;
1694 if (!(pWinpos->flags & SWP_NOSIZE))
1696 if (wndPtr->dwStyle & WS_MINIMIZE)
1698 new_window_rect->right = new_window_rect->left + GetSystemMetrics(SM_CXMINIMIZED);
1699 new_window_rect->bottom = new_window_rect->top + GetSystemMetrics(SM_CYMINIMIZED);
1701 else
1703 new_window_rect->right = new_window_rect->left + pWinpos->cx;
1704 new_window_rect->bottom = new_window_rect->top + pWinpos->cy;
1707 if (!(pWinpos->flags & SWP_NOMOVE))
1709 /* If the window is toplevel minimized off-screen, force keep it there */
1710 if ((wndPtr->dwStyle & WS_MINIMIZE) &&
1711 wndPtr->window_rect.left <= -32000 && wndPtr->window_rect.top <= -32000 &&
1712 (!wndPtr->parent || wndPtr->parent == GetDesktopWindow()))
1714 pWinpos->x = -32000;
1715 pWinpos->y = -32000;
1717 new_window_rect->left = pWinpos->x;
1718 new_window_rect->top = pWinpos->y;
1719 new_window_rect->right += pWinpos->x - old_window_rect->left;
1720 new_window_rect->bottom += pWinpos->y - old_window_rect->top;
1722 OffsetRect( new_client_rect, pWinpos->x - old_window_rect->left,
1723 pWinpos->y - old_window_rect->top );
1725 pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1727 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x current %s style %08x new %s\n",
1728 pWinpos->hwnd, pWinpos->hwndInsertAfter, pWinpos->x, pWinpos->y,
1729 pWinpos->cx, pWinpos->cy, pWinpos->flags,
1730 wine_dbgstr_rect( old_window_rect ), wndPtr->dwStyle,
1731 wine_dbgstr_rect( new_window_rect ));
1733 WIN_ReleasePtr( wndPtr );
1734 return TRUE;
1737 /***********************************************************************
1738 * get_valid_rects
1740 * Compute the valid rects from the old and new client rect and WVR_* flags.
1741 * Helper for WM_NCCALCSIZE handling.
1743 static inline void get_valid_rects( const RECT *old_client, const RECT *new_client, UINT flags,
1744 RECT *valid )
1746 int cx, cy;
1748 if (flags & WVR_REDRAW)
1750 SetRectEmpty( &valid[0] );
1751 SetRectEmpty( &valid[1] );
1752 return;
1755 if (flags & WVR_VALIDRECTS)
1757 if (!IntersectRect( &valid[0], &valid[0], new_client ) ||
1758 !IntersectRect( &valid[1], &valid[1], old_client ))
1760 SetRectEmpty( &valid[0] );
1761 SetRectEmpty( &valid[1] );
1762 return;
1764 flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
1766 else
1768 valid[0] = *new_client;
1769 valid[1] = *old_client;
1772 /* make sure the rectangles have the same size */
1773 cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
1774 cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
1776 if (flags & WVR_ALIGNBOTTOM)
1778 valid[0].top = valid[0].bottom - cy;
1779 valid[1].top = valid[1].bottom - cy;
1781 else
1783 valid[0].bottom = valid[0].top + cy;
1784 valid[1].bottom = valid[1].top + cy;
1786 if (flags & WVR_ALIGNRIGHT)
1788 valid[0].left = valid[0].right - cx;
1789 valid[1].left = valid[1].right - cx;
1791 else
1793 valid[0].right = valid[0].left + cx;
1794 valid[1].right = valid[1].left + cx;
1799 /***********************************************************************
1800 * SWP_DoOwnedPopups
1802 * fix Z order taking into account owned popups -
1803 * basically we need to maintain them above the window that owns them
1805 * FIXME: hide/show owned popups when owner visibility changes.
1807 static HWND SWP_DoOwnedPopups(HWND hwnd, HWND hwndInsertAfter)
1809 HWND owner, *list = NULL;
1810 unsigned int i;
1812 TRACE("(%p) hInsertAfter = %p\n", hwnd, hwndInsertAfter );
1814 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return hwndInsertAfter;
1816 if ((owner = GetWindow( hwnd, GW_OWNER )))
1818 /* make sure this popup stays above the owner */
1820 if (hwndInsertAfter != HWND_TOPMOST)
1822 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return hwndInsertAfter;
1824 for (i = 0; list[i]; i++)
1826 BOOL topmost = (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TOPMOST) != 0;
1828 if (list[i] == owner)
1830 if (i > 0) hwndInsertAfter = list[i-1];
1831 else hwndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
1832 break;
1835 if (hwndInsertAfter == HWND_TOP || hwndInsertAfter == HWND_NOTOPMOST)
1837 if (!topmost) break;
1839 else if (list[i] == hwndInsertAfter) break;
1844 if (hwndInsertAfter == HWND_BOTTOM) goto done;
1845 if (!list && !(list = WIN_ListChildren( GetDesktopWindow() ))) goto done;
1847 i = 0;
1848 if (hwndInsertAfter == HWND_TOP || hwndInsertAfter == HWND_NOTOPMOST)
1850 if (hwndInsertAfter == HWND_NOTOPMOST || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST))
1852 /* skip all the topmost windows */
1853 while (list[i] && (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TOPMOST)) i++;
1856 else if (hwndInsertAfter != HWND_TOPMOST)
1858 /* skip windows that are already placed correctly */
1859 for (i = 0; list[i]; i++)
1861 if (list[i] == hwndInsertAfter) break;
1862 if (list[i] == hwnd) goto done; /* nothing to do if window is moving backwards in z-order */
1866 for ( ; list[i]; i++)
1868 if (list[i] == hwnd) break;
1869 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1870 TRACE( "moving %p owned by %p after %p\n", list[i], hwnd, hwndInsertAfter );
1871 SetWindowPos( list[i], hwndInsertAfter, 0, 0, 0, 0,
1872 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE );
1873 hwndInsertAfter = list[i];
1876 done:
1877 HeapFree( GetProcessHeap(), 0, list );
1878 return hwndInsertAfter;
1881 /***********************************************************************
1882 * SWP_DoNCCalcSize
1884 static UINT SWP_DoNCCalcSize( WINDOWPOS *pWinpos, const RECT *old_window_rect, const RECT *old_client_rect,
1885 const RECT *new_window_rect, RECT *new_client_rect, RECT *validRects,
1886 int parent_x, int parent_y )
1888 UINT wvrFlags = 0;
1890 /* Send WM_NCCALCSIZE message to get new client area */
1891 if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
1893 NCCALCSIZE_PARAMS params;
1894 WINDOWPOS winposCopy;
1896 params.rgrc[0] = *new_window_rect;
1897 params.rgrc[1] = *old_window_rect;
1898 params.rgrc[2] = *old_client_rect;
1899 params.lppos = &winposCopy;
1900 winposCopy = *pWinpos;
1902 if (pWinpos->flags & SWP_NOMOVE)
1904 winposCopy.x = old_window_rect->left;
1905 winposCopy.y = old_window_rect->top;
1908 if (pWinpos->flags & SWP_NOSIZE)
1910 winposCopy.cx = old_window_rect->right - old_window_rect->left;
1911 winposCopy.cy = old_window_rect->bottom - old_window_rect->top;
1914 wvrFlags = SendMessageW( pWinpos->hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)&params );
1916 *new_client_rect = params.rgrc[0];
1918 TRACE( "hwnd %p old win %s old client %s new win %s new client %s\n", pWinpos->hwnd,
1919 wine_dbgstr_rect(old_window_rect), wine_dbgstr_rect(old_client_rect),
1920 wine_dbgstr_rect(new_window_rect), wine_dbgstr_rect(new_client_rect) );
1922 if (new_client_rect->left != old_client_rect->left - parent_x ||
1923 new_client_rect->top != old_client_rect->top - parent_y)
1924 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
1926 if( (new_client_rect->right - new_client_rect->left !=
1927 old_client_rect->right - old_client_rect->left))
1928 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
1929 else
1930 wvrFlags &= ~WVR_HREDRAW;
1932 if (new_client_rect->bottom - new_client_rect->top !=
1933 old_client_rect->bottom - old_client_rect->top)
1934 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
1935 else
1936 wvrFlags &= ~WVR_VREDRAW;
1938 validRects[0] = params.rgrc[1];
1939 validRects[1] = params.rgrc[2];
1941 else
1943 if (!(pWinpos->flags & SWP_NOMOVE) &&
1944 (new_client_rect->left != old_client_rect->left - parent_x ||
1945 new_client_rect->top != old_client_rect->top - parent_y))
1946 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
1949 if (pWinpos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
1951 SetRectEmpty( &validRects[0] );
1952 SetRectEmpty( &validRects[1] );
1954 else get_valid_rects( old_client_rect, new_client_rect, wvrFlags, validRects );
1956 return wvrFlags;
1959 /* fix redundant flags and values in the WINDOWPOS structure */
1960 static BOOL fixup_flags( WINDOWPOS *winpos, const RECT *old_window_rect, int parent_x, int parent_y )
1962 HWND parent;
1963 WND *wndPtr = WIN_GetPtr( winpos->hwnd );
1964 BOOL ret = TRUE;
1966 if (!wndPtr || wndPtr == WND_OTHER_PROCESS)
1968 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1969 return FALSE;
1971 winpos->hwnd = wndPtr->obj.handle; /* make it a full handle */
1973 /* Finally make sure that all coordinates are valid */
1974 if (winpos->x < -32768) winpos->x = -32768;
1975 else if (winpos->x > 32767) winpos->x = 32767;
1976 if (winpos->y < -32768) winpos->y = -32768;
1977 else if (winpos->y > 32767) winpos->y = 32767;
1979 if (winpos->cx < 0) winpos->cx = 0;
1980 else if (winpos->cx > 32767) winpos->cx = 32767;
1981 if (winpos->cy < 0) winpos->cy = 0;
1982 else if (winpos->cy > 32767) winpos->cy = 32767;
1984 parent = GetAncestor( winpos->hwnd, GA_PARENT );
1985 if (!IsWindowVisible( parent )) winpos->flags |= SWP_NOREDRAW;
1987 if (wndPtr->dwStyle & WS_VISIBLE) winpos->flags &= ~SWP_SHOWWINDOW;
1988 else
1990 winpos->flags &= ~SWP_HIDEWINDOW;
1991 if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
1994 if ((old_window_rect->right - old_window_rect->left == winpos->cx) &&
1995 (old_window_rect->bottom - old_window_rect->top == winpos->cy))
1996 winpos->flags |= SWP_NOSIZE; /* Already the right size */
1998 if ((old_window_rect->left - parent_x == winpos->x) && (old_window_rect->top - parent_y == winpos->y))
1999 winpos->flags |= SWP_NOMOVE; /* Already the right position */
2001 if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
2003 if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) && /* Bring to the top when activating */
2004 (winpos->flags & SWP_NOZORDER ||
2005 (winpos->hwndInsertAfter != HWND_TOPMOST && winpos->hwndInsertAfter != HWND_NOTOPMOST)))
2007 winpos->flags &= ~SWP_NOZORDER;
2008 winpos->hwndInsertAfter = HWND_TOP;
2012 /* Check hwndInsertAfter */
2013 if (winpos->flags & SWP_NOZORDER) goto done;
2015 if (winpos->hwndInsertAfter == HWND_TOP)
2017 if (GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
2018 winpos->flags |= SWP_NOZORDER;
2020 else if (winpos->hwndInsertAfter == HWND_BOTTOM)
2022 if (!(wndPtr->dwExStyle & WS_EX_TOPMOST) && GetWindow(winpos->hwnd, GW_HWNDLAST) == winpos->hwnd)
2023 winpos->flags |= SWP_NOZORDER;
2025 else if (winpos->hwndInsertAfter == HWND_TOPMOST)
2027 if ((wndPtr->dwExStyle & WS_EX_TOPMOST) && GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
2028 winpos->flags |= SWP_NOZORDER;
2030 else if (winpos->hwndInsertAfter == HWND_NOTOPMOST)
2032 if (!(wndPtr->dwExStyle & WS_EX_TOPMOST))
2033 winpos->flags |= SWP_NOZORDER;
2035 else
2037 if ((winpos->hwnd == winpos->hwndInsertAfter) ||
2038 (winpos->hwnd == GetWindow( winpos->hwndInsertAfter, GW_HWNDNEXT )))
2039 winpos->flags |= SWP_NOZORDER;
2041 done:
2042 WIN_ReleasePtr( wndPtr );
2043 return ret;
2047 /***********************************************************************
2048 * update_surface_region
2050 static void update_surface_region( HWND hwnd )
2052 NTSTATUS status;
2053 HRGN region = 0;
2054 RGNDATA *data;
2055 size_t size = 256;
2056 WND *win = WIN_GetPtr( hwnd );
2058 if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS) return;
2059 if (!win->surface) goto done;
2063 if (!(data = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( RGNDATA, Buffer[size] )))) goto done;
2065 SERVER_START_REQ( get_surface_region )
2067 req->window = wine_server_user_handle( hwnd );
2068 wine_server_set_reply( req, data->Buffer, size );
2069 if (!(status = wine_server_call( req )))
2071 size_t reply_size = wine_server_reply_size( reply );
2072 if (reply_size)
2074 data->rdh.dwSize = sizeof(data->rdh);
2075 data->rdh.iType = RDH_RECTANGLES;
2076 data->rdh.nCount = reply_size / sizeof(RECT);
2077 data->rdh.nRgnSize = reply_size;
2078 region = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
2079 OffsetRgn( region, -reply->visible_rect.left, -reply->visible_rect.top );
2082 else size = reply->total_size;
2084 SERVER_END_REQ;
2085 HeapFree( GetProcessHeap(), 0, data );
2086 } while (status == STATUS_BUFFER_OVERFLOW);
2088 if (status) goto done;
2090 win->surface->funcs->set_region( win->surface, region );
2091 if (region) DeleteObject( region );
2093 done:
2094 WIN_ReleasePtr( win );
2098 /***********************************************************************
2099 * set_window_pos
2101 * Backend implementation of SetWindowPos.
2103 BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags,
2104 const RECT *window_rect, const RECT *client_rect, const RECT *valid_rects )
2106 WND *win;
2107 HWND surface_win = 0, parent = GetAncestor( hwnd, GA_PARENT );
2108 BOOL ret, needs_update = FALSE;
2109 RECT visible_rect, old_visible_rect, old_window_rect, old_client_rect, extra_rects[3];
2110 struct window_surface *old_surface, *new_surface = NULL;
2112 if (!parent || parent == GetDesktopWindow())
2114 new_surface = &dummy_surface; /* provide a default surface for top-level windows */
2115 window_surface_add_ref( new_surface );
2117 visible_rect = *window_rect;
2118 if (!(ret = USER_Driver->pWindowPosChanging( hwnd, insert_after, swp_flags,
2119 window_rect, client_rect, &visible_rect, &new_surface )))
2121 if (IsRectEmpty( window_rect )) visible_rect = *window_rect;
2122 else
2124 visible_rect = get_virtual_screen_rect();
2125 IntersectRect( &visible_rect, &visible_rect, window_rect );
2129 WIN_GetRectangles( hwnd, COORDS_SCREEN, &old_window_rect, NULL );
2130 if (IsRectEmpty( &valid_rects[0] )) valid_rects = NULL;
2132 if (!(win = WIN_GetPtr( hwnd )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
2134 if (new_surface) window_surface_release( new_surface );
2135 return FALSE;
2138 /* create or update window surface for top-level windows if the driver doesn't implement WindowPosChanging */
2139 if (!ret && new_surface && !IsRectEmpty( &visible_rect ) &&
2140 (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
2141 GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL )))
2143 window_surface_release( new_surface );
2144 if ((new_surface = win->surface)) window_surface_add_ref( new_surface );
2145 create_offscreen_window_surface( &visible_rect, &new_surface );
2148 old_visible_rect = win->visible_rect;
2149 old_client_rect = win->client_rect;
2150 old_surface = win->surface;
2151 if (old_surface != new_surface) swp_flags |= SWP_FRAMECHANGED; /* force refreshing non-client area */
2152 if (new_surface == &dummy_surface) swp_flags |= SWP_NOREDRAW;
2153 else if (old_surface == &dummy_surface)
2155 swp_flags |= SWP_NOCOPYBITS;
2156 valid_rects = NULL;
2159 SERVER_START_REQ( set_window_pos )
2161 req->handle = wine_server_user_handle( hwnd );
2162 req->previous = wine_server_user_handle( insert_after );
2163 req->swp_flags = swp_flags;
2164 req->window.left = window_rect->left;
2165 req->window.top = window_rect->top;
2166 req->window.right = window_rect->right;
2167 req->window.bottom = window_rect->bottom;
2168 req->client.left = client_rect->left;
2169 req->client.top = client_rect->top;
2170 req->client.right = client_rect->right;
2171 req->client.bottom = client_rect->bottom;
2172 if (!EqualRect( window_rect, &visible_rect ) || new_surface || valid_rects)
2174 extra_rects[0] = extra_rects[1] = visible_rect;
2175 if (new_surface)
2177 extra_rects[1] = new_surface->rect;
2178 OffsetRect( &extra_rects[1], visible_rect.left, visible_rect.top );
2180 if (valid_rects) extra_rects[2] = valid_rects[0];
2181 else SetRectEmpty( &extra_rects[2] );
2182 wine_server_add_data( req, extra_rects, sizeof(extra_rects) );
2184 if (new_surface) req->paint_flags |= SET_WINPOS_PAINT_SURFACE;
2185 if (win->pixel_format) req->paint_flags |= SET_WINPOS_PIXEL_FORMAT;
2187 if ((ret = !wine_server_call( req )))
2189 win->dwStyle = reply->new_style;
2190 win->dwExStyle = reply->new_ex_style;
2191 win->window_rect = *window_rect;
2192 win->client_rect = *client_rect;
2193 win->visible_rect = visible_rect;
2194 win->surface = new_surface;
2195 surface_win = wine_server_ptr_handle( reply->surface_win );
2196 needs_update = reply->needs_update;
2197 if (GetWindowLongW( win->parent, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
2199 RECT client;
2200 GetClientRect( win->parent, &client );
2201 mirror_rect( &client, &win->window_rect );
2202 mirror_rect( &client, &win->client_rect );
2203 mirror_rect( &client, &win->visible_rect );
2205 /* if an RTL window is resized the children have moved */
2206 if (win->dwExStyle & WS_EX_LAYOUTRTL &&
2207 client_rect->right - client_rect->left != old_client_rect.right - old_client_rect.left)
2208 win->flags |= WIN_CHILDREN_MOVED;
2211 SERVER_END_REQ;
2213 if (ret)
2215 if (needs_update) update_surface_region( surface_win );
2216 if (((swp_flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) ||
2217 (swp_flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW | SWP_STATECHANGED | SWP_FRAMECHANGED)))
2218 invalidate_dce( win, &old_window_rect );
2221 WIN_ReleasePtr( win );
2223 if (ret)
2225 TRACE( "win %p surface %p -> %p\n", hwnd, old_surface, new_surface );
2226 register_window_surface( old_surface, new_surface );
2227 if (old_surface)
2229 if (valid_rects)
2231 move_window_bits( hwnd, old_surface, new_surface, &visible_rect,
2232 &old_visible_rect, window_rect, valid_rects );
2233 valid_rects = NULL; /* prevent the driver from trying to also move the bits */
2235 window_surface_release( old_surface );
2237 else if (surface_win && surface_win != hwnd)
2239 if (valid_rects)
2241 RECT rects[2];
2242 int x_offset = old_visible_rect.left - visible_rect.left;
2243 int y_offset = old_visible_rect.top - visible_rect.top;
2245 /* if all that happened is that the whole window moved, copy everything */
2246 if (!(swp_flags & SWP_FRAMECHANGED) &&
2247 old_visible_rect.right - visible_rect.right == x_offset &&
2248 old_visible_rect.bottom - visible_rect.bottom == y_offset &&
2249 old_client_rect.left - client_rect->left == x_offset &&
2250 old_client_rect.right - client_rect->right == x_offset &&
2251 old_client_rect.top - client_rect->top == y_offset &&
2252 old_client_rect.bottom - client_rect->bottom == y_offset &&
2253 EqualRect( &valid_rects[0], client_rect ))
2255 rects[0] = visible_rect;
2256 rects[1] = old_visible_rect;
2257 valid_rects = rects;
2259 move_window_bits_parent( hwnd, surface_win, window_rect, valid_rects );
2260 valid_rects = NULL; /* prevent the driver from trying to also move the bits */
2264 USER_Driver->pWindowPosChanged( hwnd, insert_after, swp_flags, window_rect,
2265 client_rect, &visible_rect, valid_rects, new_surface );
2267 else if (new_surface) window_surface_release( new_surface );
2269 return ret;
2273 /***********************************************************************
2274 * USER_SetWindowPos
2276 * User32 internal function
2278 BOOL USER_SetWindowPos( WINDOWPOS * winpos, int parent_x, int parent_y )
2280 RECT old_window_rect, old_client_rect, new_window_rect, new_client_rect, valid_rects[2];
2281 UINT orig_flags;
2282 BOOL ret = FALSE;
2283 DPI_AWARENESS_CONTEXT context;
2285 orig_flags = winpos->flags;
2287 /* First, check z-order arguments. */
2288 if (!(winpos->flags & SWP_NOZORDER))
2290 /* fix sign extension */
2291 if (winpos->hwndInsertAfter == (HWND)0xffff) winpos->hwndInsertAfter = HWND_TOPMOST;
2292 else if (winpos->hwndInsertAfter == (HWND)0xfffe) winpos->hwndInsertAfter = HWND_NOTOPMOST;
2294 if (!(winpos->hwndInsertAfter == HWND_TOP ||
2295 winpos->hwndInsertAfter == HWND_BOTTOM ||
2296 winpos->hwndInsertAfter == HWND_TOPMOST ||
2297 winpos->hwndInsertAfter == HWND_NOTOPMOST))
2299 HWND parent = GetAncestor( winpos->hwnd, GA_PARENT );
2300 HWND insertafter_parent = GetAncestor( winpos->hwndInsertAfter, GA_PARENT );
2302 /* hwndInsertAfter must be a sibling of the window */
2303 if (!insertafter_parent) return FALSE;
2304 if (insertafter_parent != parent) return TRUE;
2308 /* Make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
2309 if (!(winpos->flags & SWP_NOMOVE))
2311 if (winpos->x < -32768) winpos->x = -32768;
2312 else if (winpos->x > 32767) winpos->x = 32767;
2313 if (winpos->y < -32768) winpos->y = -32768;
2314 else if (winpos->y > 32767) winpos->y = 32767;
2316 if (!(winpos->flags & SWP_NOSIZE))
2318 if (winpos->cx < 0) winpos->cx = 0;
2319 else if (winpos->cx > 32767) winpos->cx = 32767;
2320 if (winpos->cy < 0) winpos->cy = 0;
2321 else if (winpos->cy > 32767) winpos->cy = 32767;
2324 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( winpos->hwnd ));
2326 if (!SWP_DoWinPosChanging( winpos, &old_window_rect, &old_client_rect,
2327 &new_window_rect, &new_client_rect )) goto done;
2329 /* Fix redundant flags */
2330 if (!fixup_flags( winpos, &old_window_rect, parent_x, parent_y )) goto done;
2332 if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
2334 if (GetAncestor( winpos->hwnd, GA_PARENT ) == GetDesktopWindow())
2335 winpos->hwndInsertAfter = SWP_DoOwnedPopups( winpos->hwnd, winpos->hwndInsertAfter );
2338 /* Common operations */
2340 SWP_DoNCCalcSize( winpos, &old_window_rect, &old_client_rect,
2341 &new_window_rect, &new_client_rect, valid_rects, parent_x, parent_y );
2343 if (!set_window_pos( winpos->hwnd, winpos->hwndInsertAfter, winpos->flags,
2344 &new_window_rect, &new_client_rect, valid_rects ))
2345 goto done;
2348 if( winpos->flags & SWP_HIDEWINDOW )
2349 HideCaret(winpos->hwnd);
2350 else if (winpos->flags & SWP_SHOWWINDOW)
2351 ShowCaret(winpos->hwnd);
2353 if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2355 /* child windows get WM_CHILDACTIVATE message */
2356 if ((GetWindowLongW( winpos->hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2357 SendMessageW( winpos->hwnd, WM_CHILDACTIVATE, 0, 0 );
2358 else
2359 SetForegroundWindow( winpos->hwnd );
2362 if(!(orig_flags & SWP_DEFERERASE))
2364 /* erase parent when hiding or resizing child */
2365 if ((orig_flags & SWP_HIDEWINDOW) ||
2366 (!(orig_flags & SWP_SHOWWINDOW) &&
2367 (winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE))
2369 HWND parent = GetAncestor( winpos->hwnd, GA_PARENT );
2370 if (!parent || parent == GetDesktopWindow()) parent = winpos->hwnd;
2371 erase_now( parent, 0 );
2374 /* Give newly shown windows a chance to redraw */
2375 if(((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2376 && !(orig_flags & SWP_AGG_NOCLIENTCHANGE) && (orig_flags & SWP_SHOWWINDOW))
2378 erase_now(winpos->hwnd, 0);
2382 /* And last, send the WM_WINDOWPOSCHANGED message */
2384 TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
2386 if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2387 && !((orig_flags & SWP_AGG_NOCLIENTCHANGE) && (orig_flags & SWP_SHOWWINDOW)))
2389 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2390 and always contains final window position.
2392 winpos->x = new_window_rect.left;
2393 winpos->y = new_window_rect.top;
2394 winpos->cx = new_window_rect.right - new_window_rect.left;
2395 winpos->cy = new_window_rect.bottom - new_window_rect.top;
2396 SendMessageW( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
2398 ret = TRUE;
2399 done:
2400 SetThreadDpiAwarenessContext( context );
2401 return ret;
2404 /***********************************************************************
2405 * SetWindowPos (USER32.@)
2407 BOOL WINAPI SetWindowPos( HWND hwnd, HWND hwndInsertAfter,
2408 INT x, INT y, INT cx, INT cy, UINT flags )
2410 WINDOWPOS winpos;
2412 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2413 hwnd, hwndInsertAfter, x, y, cx, cy, flags);
2414 if(TRACE_ON(win)) dump_winpos_flags(flags);
2416 if (is_broadcast(hwnd))
2418 SetLastError( ERROR_INVALID_PARAMETER );
2419 return FALSE;
2422 winpos.hwnd = WIN_GetFullHandle(hwnd);
2423 winpos.hwndInsertAfter = WIN_GetFullHandle(hwndInsertAfter);
2424 winpos.x = x;
2425 winpos.y = y;
2426 winpos.cx = cx;
2427 winpos.cy = cy;
2428 winpos.flags = flags;
2430 map_dpi_winpos( &winpos );
2432 if (WIN_IsCurrentThread( hwnd ))
2433 return USER_SetWindowPos( &winpos, 0, 0 );
2435 if (flags & SWP_ASYNCWINDOWPOS)
2436 return SendNotifyMessageW( winpos.hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)&winpos );
2437 else
2438 return SendMessageW( winpos.hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)&winpos );
2442 /***********************************************************************
2443 * BeginDeferWindowPos (USER32.@)
2445 HDWP WINAPI BeginDeferWindowPos( INT count )
2447 HDWP handle = 0;
2448 DWP *pDWP;
2450 TRACE("%d\n", count);
2452 if (count < 0)
2454 SetLastError(ERROR_INVALID_PARAMETER);
2455 return 0;
2457 /* Windows allows zero count, in which case it allocates context for 8 moves */
2458 if (count == 0) count = 8;
2460 if (!(pDWP = HeapAlloc( GetProcessHeap(), 0, sizeof(DWP)))) return 0;
2462 pDWP->actualCount = 0;
2463 pDWP->suggestedCount = count;
2464 pDWP->hwndParent = 0;
2466 if (!(pDWP->winPos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WINDOWPOS) )) ||
2467 !(handle = alloc_user_handle( &pDWP->obj, USER_DWP )))
2469 HeapFree( GetProcessHeap(), 0, pDWP->winPos );
2470 HeapFree( GetProcessHeap(), 0, pDWP );
2473 TRACE("returning hdwp %p\n", handle);
2474 return handle;
2478 /***********************************************************************
2479 * DeferWindowPos (USER32.@)
2481 HDWP WINAPI DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter,
2482 INT x, INT y, INT cx, INT cy,
2483 UINT flags )
2485 DWP *pDWP;
2486 int i;
2487 HDWP retvalue = hdwp;
2488 WINDOWPOS winpos;
2490 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2491 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2493 winpos.hwnd = WIN_GetFullHandle( hwnd );
2494 if (is_desktop_window( winpos.hwnd ) || !IsWindow( winpos.hwnd ))
2496 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2497 return 0;
2500 winpos.hwndInsertAfter = WIN_GetFullHandle(hwndAfter);
2501 winpos.flags = flags;
2502 winpos.x = x;
2503 winpos.y = y;
2504 winpos.cx = cx;
2505 winpos.cy = cy;
2506 map_dpi_winpos( &winpos );
2508 if (!(pDWP = get_user_handle_ptr( hdwp, USER_DWP ))) return 0;
2509 if (pDWP == OBJ_OTHER_PROCESS)
2511 FIXME( "other process handle %p?\n", hdwp );
2512 return 0;
2515 for (i = 0; i < pDWP->actualCount; i++)
2517 if (pDWP->winPos[i].hwnd == winpos.hwnd)
2519 /* Merge with the other changes */
2520 if (!(flags & SWP_NOZORDER))
2522 pDWP->winPos[i].hwndInsertAfter = winpos.hwndInsertAfter;
2524 if (!(flags & SWP_NOMOVE))
2526 pDWP->winPos[i].x = winpos.x;
2527 pDWP->winPos[i].y = winpos.y;
2529 if (!(flags & SWP_NOSIZE))
2531 pDWP->winPos[i].cx = winpos.cx;
2532 pDWP->winPos[i].cy = winpos.cy;
2534 pDWP->winPos[i].flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2535 SWP_NOZORDER | SWP_NOREDRAW |
2536 SWP_NOACTIVATE | SWP_NOCOPYBITS|
2537 SWP_NOOWNERZORDER);
2538 pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2539 SWP_FRAMECHANGED);
2540 goto END;
2543 if (pDWP->actualCount >= pDWP->suggestedCount)
2545 WINDOWPOS *newpos = HeapReAlloc( GetProcessHeap(), 0, pDWP->winPos,
2546 pDWP->suggestedCount * 2 * sizeof(WINDOWPOS) );
2547 if (!newpos)
2549 retvalue = 0;
2550 goto END;
2552 pDWP->suggestedCount *= 2;
2553 pDWP->winPos = newpos;
2555 pDWP->winPos[pDWP->actualCount++] = winpos;
2556 END:
2557 release_user_handle_ptr( pDWP );
2558 return retvalue;
2562 /***********************************************************************
2563 * EndDeferWindowPos (USER32.@)
2565 BOOL WINAPI EndDeferWindowPos( HDWP hdwp )
2567 DWP *pDWP;
2568 WINDOWPOS *winpos;
2569 int i;
2571 TRACE("%p\n", hdwp);
2573 if (!(pDWP = free_user_handle( hdwp, USER_DWP ))) return FALSE;
2574 if (pDWP == OBJ_OTHER_PROCESS)
2576 FIXME( "other process handle %p?\n", hdwp );
2577 return FALSE;
2580 for (i = 0, winpos = pDWP->winPos; i < pDWP->actualCount; i++, winpos++)
2582 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2583 winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
2584 winpos->cx, winpos->cy, winpos->flags);
2586 if (WIN_IsCurrentThread( winpos->hwnd ))
2587 USER_SetWindowPos( winpos, 0, 0 );
2588 else
2589 SendMessageW( winpos->hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)winpos );
2591 HeapFree( GetProcessHeap(), 0, pDWP->winPos );
2592 HeapFree( GetProcessHeap(), 0, pDWP );
2593 return TRUE;
2597 /***********************************************************************
2598 * ArrangeIconicWindows (USER32.@)
2600 UINT WINAPI ArrangeIconicWindows( HWND parent )
2602 int width, height, count = 0;
2603 RECT rectParent;
2604 HWND hwndChild;
2605 POINT pt;
2606 MINIMIZEDMETRICS metrics;
2608 metrics.cbSize = sizeof(metrics);
2609 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(metrics), &metrics, 0 );
2610 width = GetSystemMetrics( SM_CXMINIMIZED );
2611 height = GetSystemMetrics( SM_CYMINIMIZED );
2613 if (parent == GetDesktopWindow())
2615 MONITORINFO mon_info;
2616 HMONITOR monitor = MonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY );
2618 mon_info.cbSize = sizeof( mon_info );
2619 GetMonitorInfoW( monitor, &mon_info );
2620 rectParent = mon_info.rcWork;
2622 else GetClientRect( parent, &rectParent );
2624 pt = get_first_minimized_child_pos( &rectParent, &metrics, width, height );
2626 hwndChild = GetWindow( parent, GW_CHILD );
2627 while (hwndChild)
2629 if( IsIconic( hwndChild ) )
2631 SetWindowPos( hwndChild, 0, pt.x, pt.y, 0, 0,
2632 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
2633 get_next_minimized_child_pos( &rectParent, &metrics, width, height, &pt );
2634 count++;
2636 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
2638 return count;
2642 /***********************************************************************
2643 * draw_moving_frame
2645 * Draw the frame used when moving or resizing window.
2647 static void draw_moving_frame( HWND parent, HDC hdc, RECT *screen_rect, BOOL thickframe )
2649 RECT rect = *screen_rect;
2651 if (parent) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
2652 if (thickframe)
2654 const int width = GetSystemMetrics(SM_CXFRAME);
2655 const int height = GetSystemMetrics(SM_CYFRAME);
2657 HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
2658 PatBlt( hdc, rect.left, rect.top,
2659 rect.right - rect.left - width, height, PATINVERT );
2660 PatBlt( hdc, rect.left, rect.top + height, width,
2661 rect.bottom - rect.top - height, PATINVERT );
2662 PatBlt( hdc, rect.left + width, rect.bottom - 1,
2663 rect.right - rect.left - width, -height, PATINVERT );
2664 PatBlt( hdc, rect.right - 1, rect.top, -width,
2665 rect.bottom - rect.top - height, PATINVERT );
2666 SelectObject( hdc, hbrush );
2668 else DrawFocusRect( hdc, &rect );
2672 /***********************************************************************
2673 * start_size_move
2675 * Initialization of a move or resize, when initiated from a menu choice.
2676 * Return hit test code for caption or sizing border.
2678 static LONG start_size_move( HWND hwnd, WPARAM wParam, POINT *capturePoint, LONG style )
2680 LONG hittest = 0;
2681 POINT pt;
2682 MSG msg;
2683 RECT rectWindow;
2685 GetWindowRect( hwnd, &rectWindow );
2687 if ((wParam & 0xfff0) == SC_MOVE)
2689 /* Move pointer at the center of the caption */
2690 RECT rect = rectWindow;
2691 /* Note: to be exactly centered we should take the different types
2692 * of border into account, but it shouldn't make more than a few pixels
2693 * of difference so let's not bother with that */
2694 rect.top += GetSystemMetrics(SM_CYBORDER);
2695 if (style & WS_SYSMENU)
2696 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
2697 if (style & WS_MINIMIZEBOX)
2698 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
2699 if (style & WS_MAXIMIZEBOX)
2700 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
2701 pt.x = (rect.right + rect.left) / 2;
2702 pt.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
2703 hittest = HTCAPTION;
2704 *capturePoint = pt;
2706 else /* SC_SIZE */
2708 SetCursor( LoadCursorW( 0, (LPWSTR)IDC_SIZEALL ) );
2709 pt.x = pt.y = 0;
2710 while(!hittest)
2712 if (!GetMessageW( &msg, 0, 0, 0 )) return 0;
2713 if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
2715 switch(msg.message)
2717 case WM_MOUSEMOVE:
2718 pt.x = min( max( msg.pt.x, rectWindow.left ), rectWindow.right - 1 );
2719 pt.y = min( max( msg.pt.y, rectWindow.top ), rectWindow.bottom - 1 );
2720 hittest = SendMessageW( hwnd, WM_NCHITTEST, 0, MAKELONG( pt.x, pt.y ) );
2721 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) hittest = 0;
2722 break;
2724 case WM_LBUTTONUP:
2725 return 0;
2727 case WM_KEYDOWN:
2728 switch(msg.wParam)
2730 case VK_UP:
2731 hittest = HTTOP;
2732 pt.x =(rectWindow.left+rectWindow.right)/2;
2733 pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
2734 break;
2735 case VK_DOWN:
2736 hittest = HTBOTTOM;
2737 pt.x =(rectWindow.left+rectWindow.right)/2;
2738 pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
2739 break;
2740 case VK_LEFT:
2741 hittest = HTLEFT;
2742 pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
2743 pt.y =(rectWindow.top+rectWindow.bottom)/2;
2744 break;
2745 case VK_RIGHT:
2746 hittest = HTRIGHT;
2747 pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
2748 pt.y =(rectWindow.top+rectWindow.bottom)/2;
2749 break;
2750 case VK_RETURN:
2751 case VK_ESCAPE:
2752 return 0;
2754 break;
2755 default:
2756 TranslateMessage( &msg );
2757 DispatchMessageW( &msg );
2758 break;
2761 *capturePoint = pt;
2763 SetCursorPos( pt.x, pt.y );
2764 SendMessageW( hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
2765 return hittest;
2769 /***********************************************************************
2770 * WINPOS_SysCommandSizeMove
2772 * Perform SC_MOVE and SC_SIZE commands.
2774 void WINPOS_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
2776 MSG msg;
2777 RECT sizingRect, mouseRect, origRect;
2778 HDC hdc;
2779 HWND parent;
2780 LONG hittest = (LONG)(wParam & 0x0f);
2781 WPARAM syscommand = wParam & 0xfff0;
2782 MINMAXINFO minmax;
2783 POINT capturePoint, pt;
2784 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2785 BOOL thickframe = HAS_THICKFRAME( style );
2786 BOOL moved = FALSE;
2787 DWORD dwPoint = GetMessagePos ();
2788 BOOL DragFullWindows = TRUE;
2789 HMONITOR mon = 0;
2791 if (IsZoomed(hwnd) || !IsWindowVisible(hwnd)) return;
2793 pt.x = (short)LOWORD(dwPoint);
2794 pt.y = (short)HIWORD(dwPoint);
2795 capturePoint = pt;
2796 ClipCursor( NULL );
2798 TRACE("hwnd %p command %04lx, hittest %d, pos %d,%d\n",
2799 hwnd, syscommand, hittest, pt.x, pt.y);
2801 if (syscommand == SC_MOVE)
2803 if (!hittest) hittest = start_size_move( hwnd, wParam, &capturePoint, style );
2804 if (!hittest) return;
2806 else /* SC_SIZE */
2808 if ( hittest && (syscommand != SC_MOUSEMENU) )
2809 hittest += (HTLEFT - WMSZ_LEFT);
2810 else
2812 set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
2813 hittest = start_size_move( hwnd, wParam, &capturePoint, style );
2814 if (!hittest)
2816 set_capture_window( 0, GUI_INMOVESIZE, NULL );
2817 return;
2822 /* Get min/max info */
2824 minmax = WINPOS_GetMinMaxInfo( hwnd );
2825 WIN_GetRectangles( hwnd, COORDS_PARENT, &sizingRect, NULL );
2826 origRect = sizingRect;
2827 if (style & WS_CHILD)
2829 parent = GetParent(hwnd);
2830 GetClientRect( parent, &mouseRect );
2831 MapWindowPoints( parent, 0, (LPPOINT)&mouseRect, 2 );
2832 MapWindowPoints( parent, 0, (LPPOINT)&sizingRect, 2 );
2834 else
2836 parent = 0;
2837 mouseRect = get_virtual_screen_rect();
2838 mon = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
2841 if (ON_LEFT_BORDER(hittest))
2843 mouseRect.left = max( mouseRect.left, sizingRect.right-minmax.ptMaxTrackSize.x+capturePoint.x-sizingRect.left );
2844 mouseRect.right = min( mouseRect.right, sizingRect.right-minmax.ptMinTrackSize.x+capturePoint.x-sizingRect.left );
2846 else if (ON_RIGHT_BORDER(hittest))
2848 mouseRect.left = max( mouseRect.left, sizingRect.left+minmax.ptMinTrackSize.x+capturePoint.x-sizingRect.right );
2849 mouseRect.right = min( mouseRect.right, sizingRect.left+minmax.ptMaxTrackSize.x+capturePoint.x-sizingRect.right );
2851 if (ON_TOP_BORDER(hittest))
2853 mouseRect.top = max( mouseRect.top, sizingRect.bottom-minmax.ptMaxTrackSize.y+capturePoint.y-sizingRect.top );
2854 mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minmax.ptMinTrackSize.y+capturePoint.y-sizingRect.top);
2856 else if (ON_BOTTOM_BORDER(hittest))
2858 mouseRect.top = max( mouseRect.top, sizingRect.top+minmax.ptMinTrackSize.y+capturePoint.y-sizingRect.bottom );
2859 mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+minmax.ptMaxTrackSize.y+capturePoint.y-sizingRect.bottom );
2862 /* Retrieve a default cache DC (without using the window style) */
2863 hdc = GetDCEx( parent, 0, DCX_CACHE );
2865 /* we only allow disabling the full window drag for child windows */
2866 if (parent) SystemParametersInfoW( SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0 );
2868 /* repaint the window before moving it around */
2869 RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
2871 SendMessageW( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
2872 set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
2874 while(1)
2876 int dx = 0, dy = 0;
2878 if (!GetMessageW( &msg, 0, 0, 0 )) break;
2879 if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
2881 /* Exit on button-up, Return, or Esc */
2882 if ((msg.message == WM_LBUTTONUP) ||
2883 ((msg.message == WM_KEYDOWN) &&
2884 ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
2886 if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
2888 TranslateMessage( &msg );
2889 DispatchMessageW( &msg );
2890 continue; /* We are not interested in other messages */
2893 pt = msg.pt;
2895 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
2897 case VK_UP: pt.y -= 8; break;
2898 case VK_DOWN: pt.y += 8; break;
2899 case VK_LEFT: pt.x -= 8; break;
2900 case VK_RIGHT: pt.x += 8; break;
2903 pt.x = max( pt.x, mouseRect.left );
2904 pt.x = min( pt.x, mouseRect.right - 1 );
2905 pt.y = max( pt.y, mouseRect.top );
2906 pt.y = min( pt.y, mouseRect.bottom - 1 );
2908 if (!parent)
2910 HMONITOR newmon;
2911 MONITORINFO info;
2913 if ((newmon = MonitorFromPoint( pt, MONITOR_DEFAULTTONULL )))
2914 mon = newmon;
2916 info.cbSize = sizeof(info);
2917 if (mon && GetMonitorInfoW( mon, &info ))
2919 pt.x = max( pt.x, info.rcWork.left );
2920 pt.x = min( pt.x, info.rcWork.right - 1 );
2921 pt.y = max( pt.y, info.rcWork.top );
2922 pt.y = min( pt.y, info.rcWork.bottom - 1 );
2926 dx = pt.x - capturePoint.x;
2927 dy = pt.y - capturePoint.y;
2929 if (dx || dy)
2931 if( !moved )
2933 moved = TRUE;
2934 if (!DragFullWindows)
2935 draw_moving_frame( parent, hdc, &sizingRect, thickframe );
2938 if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
2939 else
2941 if (!DragFullWindows) draw_moving_frame( parent, hdc, &sizingRect, thickframe );
2942 if (hittest == HTCAPTION || hittest == HTBORDER) OffsetRect( &sizingRect, dx, dy );
2943 if (ON_LEFT_BORDER(hittest)) sizingRect.left += dx;
2944 else if (ON_RIGHT_BORDER(hittest)) sizingRect.right += dx;
2945 if (ON_TOP_BORDER(hittest)) sizingRect.top += dy;
2946 else if (ON_BOTTOM_BORDER(hittest)) sizingRect.bottom += dy;
2947 capturePoint = pt;
2949 /* determine the hit location */
2950 if (syscommand == SC_SIZE && hittest != HTBORDER)
2952 WPARAM wpSizingHit = 0;
2954 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
2955 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
2956 SendMessageW( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&sizingRect );
2958 else
2959 SendMessageW( hwnd, WM_MOVING, 0, (LPARAM)&sizingRect );
2961 if (!DragFullWindows)
2962 draw_moving_frame( parent, hdc, &sizingRect, thickframe );
2963 else
2965 RECT rect = sizingRect;
2966 MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
2967 SetWindowPos( hwnd, 0, rect.left, rect.top,
2968 rect.right - rect.left, rect.bottom - rect.top,
2969 (hittest == HTCAPTION) ? SWP_NOSIZE : 0 );
2975 if (moved && !DragFullWindows)
2977 draw_moving_frame( parent, hdc, &sizingRect, thickframe );
2980 set_capture_window( 0, GUI_INMOVESIZE, NULL );
2981 ReleaseDC( parent, hdc );
2982 if (parent) MapWindowPoints( 0, parent, (POINT *)&sizingRect, 2 );
2984 if (HOOK_CallHooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect, TRUE ))
2985 moved = FALSE;
2987 SendMessageW( hwnd, WM_EXITSIZEMOVE, 0, 0 );
2988 SendMessageW( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
2990 /* window moved or resized */
2991 if (moved)
2993 /* if the moving/resizing isn't canceled call SetWindowPos
2994 * with the new position or the new size of the window
2996 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
2998 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
2999 if (!DragFullWindows)
3000 SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
3001 sizingRect.right - sizingRect.left,
3002 sizingRect.bottom - sizingRect.top,
3003 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
3005 else
3006 { /* restore previous size/position */
3007 if(DragFullWindows)
3008 SetWindowPos( hwnd, 0, origRect.left, origRect.top,
3009 origRect.right - origRect.left,
3010 origRect.bottom - origRect.top,
3011 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
3015 if (IsIconic(hwnd))
3017 /* Single click brings up the system menu when iconized */
3019 if( !moved )
3021 if(style & WS_SYSMENU )
3022 SendMessageW( hwnd, WM_SYSCOMMAND,
3023 SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));