winex11.drv: Update a comment.
[wine.git] / dlls / user32 / winpos.c
blob9e5a0c238afccc8b89218ff3eca7b20ecb0f2097
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 SetWindowPos( hwnd, 0, 0, 0, 0, 0, swp_flags );
221 USER_Driver->pSetWindowRgn( hwnd, hrgn, bRedraw );
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;
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 if (MinMax.ptMaxSize.x == GetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
758 MinMax.ptMaxSize.y == GetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
760 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
761 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
763 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
765 MinMax.ptMaxPosition.x = rc_work.left - xinc;
766 MinMax.ptMaxPosition.y = rc_work.top - yinc;
770 /* Some sanity checks */
772 TRACE("%d %d / %d %d / %d %d / %d %d\n",
773 MinMax.ptMaxSize.x, MinMax.ptMaxSize.y,
774 MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y,
775 MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y,
776 MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y);
777 MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x,
778 MinMax.ptMinTrackSize.x );
779 MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y,
780 MinMax.ptMinTrackSize.y );
782 SetThreadDpiAwarenessContext( context );
783 return MinMax;
786 static POINT get_first_minimized_child_pos( const RECT *parent, const MINIMIZEDMETRICS *mm,
787 int width, int height )
789 POINT ret;
791 if (mm->iArrange & ARW_STARTRIGHT)
792 ret.x = parent->right - mm->iHorzGap - width;
793 else
794 ret.x = parent->left + mm->iHorzGap;
795 if (mm->iArrange & ARW_STARTTOP)
796 ret.y = parent->top + mm->iVertGap;
797 else
798 ret.y = parent->bottom - mm->iVertGap - height;
800 return ret;
803 static void get_next_minimized_child_pos( const RECT *parent, const MINIMIZEDMETRICS *mm,
804 int width, int height, POINT *pos )
806 BOOL next;
808 if (mm->iArrange & ARW_UP) /* == ARW_DOWN */
810 if (mm->iArrange & ARW_STARTTOP)
812 pos->y += height + mm->iVertGap;
813 if ((next = pos->y + height > parent->bottom))
814 pos->y = parent->top + mm->iVertGap;
816 else
818 pos->y -= height + mm->iVertGap;
819 if ((next = pos->y < parent->top))
820 pos->y = parent->bottom - mm->iVertGap - height;
823 if (next)
825 if (mm->iArrange & ARW_STARTRIGHT)
826 pos->x -= width + mm->iHorzGap;
827 else
828 pos->x += width + mm->iHorzGap;
831 else
833 if (mm->iArrange & ARW_STARTRIGHT)
835 pos->x -= width + mm->iHorzGap;
836 if ((next = pos->x < parent->left))
837 pos->x = parent->right - mm->iHorzGap - width;
839 else
841 pos->x += width + mm->iHorzGap;
842 if ((next = pos->x + width > parent->right))
843 pos->x = parent->left + mm->iHorzGap;
846 if (next)
848 if (mm->iArrange & ARW_STARTTOP)
849 pos->y += height + mm->iVertGap;
850 else
851 pos->y -= height + mm->iVertGap;
856 static POINT get_minimized_pos( HWND hwnd, POINT pt )
858 RECT rect, rectParent;
859 HWND parent, child;
860 HRGN hrgn, tmp;
861 MINIMIZEDMETRICS metrics;
862 int width, height;
864 parent = GetAncestor( hwnd, GA_PARENT );
865 if (parent == GetDesktopWindow())
867 MONITORINFO mon_info;
868 HMONITOR monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY );
870 mon_info.cbSize = sizeof( mon_info );
871 GetMonitorInfoW( monitor, &mon_info );
872 rectParent = mon_info.rcWork;
874 else GetClientRect( parent, &rectParent );
876 if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics( SM_CXMINIMIZED ) < rectParent.right) &&
877 (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics( SM_CYMINIMIZED ) < rectParent.bottom))
878 return pt; /* The icon already has a suitable position */
880 width = GetSystemMetrics( SM_CXMINIMIZED );
881 height = GetSystemMetrics( SM_CYMINIMIZED );
883 metrics.cbSize = sizeof(metrics);
884 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(metrics), &metrics, 0 );
886 /* Check if another icon already occupies this spot */
887 /* FIXME: this is completely inefficient */
889 hrgn = CreateRectRgn( 0, 0, 0, 0 );
890 tmp = CreateRectRgn( 0, 0, 0, 0 );
891 for (child = GetWindow( parent, GW_CHILD ); child; child = GetWindow( child, GW_HWNDNEXT ))
893 if (child == hwnd) continue;
894 if ((GetWindowLongW( child, GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE))
895 continue;
896 if (WIN_GetRectangles( child, COORDS_PARENT, &rect, NULL ))
898 SetRectRgn( tmp, rect.left, rect.top, rect.right, rect.bottom );
899 CombineRgn( hrgn, hrgn, tmp, RGN_OR );
902 DeleteObject( tmp );
904 pt = get_first_minimized_child_pos( &rectParent, &metrics, width, height );
905 for (;;)
907 SetRect( &rect, pt.x, pt.y, pt.x + width, pt.y + height );
908 if (!RectInRegion( hrgn, &rect ))
909 break;
911 get_next_minimized_child_pos( &rectParent, &metrics, width, height, &pt );
914 DeleteObject( hrgn );
915 return pt;
919 /***********************************************************************
920 * WINPOS_MinMaximize
922 UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
924 UINT swpFlags = 0;
925 LONG old_style;
926 MINMAXINFO minmax;
927 WINDOWPLACEMENT wpl;
929 TRACE("%p %u\n", hwnd, cmd );
931 wpl.length = sizeof(wpl);
932 GetWindowPlacement( hwnd, &wpl );
934 if (HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd, TRUE ))
935 return SWP_NOSIZE | SWP_NOMOVE;
937 if (IsIconic( hwnd ))
939 switch (cmd)
941 case SW_SHOWMINNOACTIVE:
942 case SW_SHOWMINIMIZED:
943 case SW_FORCEMINIMIZE:
944 case SW_MINIMIZE:
945 wpl.ptMinPosition = get_minimized_pos( hwnd, wpl.ptMinPosition );
947 SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
948 wpl.ptMinPosition.x + GetSystemMetrics(SM_CXMINIMIZED),
949 wpl.ptMinPosition.y + GetSystemMetrics(SM_CYMINIMIZED) );
950 return SWP_NOSIZE | SWP_NOMOVE;
952 if (!SendMessageW( hwnd, WM_QUERYOPEN, 0, 0 )) return SWP_NOSIZE | SWP_NOMOVE;
953 swpFlags |= SWP_NOCOPYBITS;
956 switch( cmd )
958 case SW_SHOWMINNOACTIVE:
959 case SW_SHOWMINIMIZED:
960 case SW_FORCEMINIMIZE:
961 case SW_MINIMIZE:
962 if (IsZoomed( hwnd )) win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
963 else win_set_flags( hwnd, 0, WIN_RESTORE_MAX );
965 if (GetFocus() == hwnd)
967 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_CHILD)
968 SetFocus(GetAncestor(hwnd, GA_PARENT));
969 else
970 SetFocus(0);
973 old_style = WIN_SetStyle( hwnd, WS_MINIMIZE, WS_MAXIMIZE );
975 wpl.ptMinPosition = get_minimized_pos( hwnd, wpl.ptMinPosition );
977 if (!(old_style & WS_MINIMIZE)) swpFlags |= SWP_STATECHANGED;
978 SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
979 wpl.ptMinPosition.x + GetSystemMetrics(SM_CXMINIMIZED),
980 wpl.ptMinPosition.y + GetSystemMetrics(SM_CYMINIMIZED) );
981 swpFlags |= SWP_NOCOPYBITS;
982 break;
984 case SW_MAXIMIZE:
985 old_style = GetWindowLongW( hwnd, GWL_STYLE );
986 if ((old_style & WS_MAXIMIZE) && (old_style & WS_VISIBLE)) return SWP_NOSIZE | SWP_NOMOVE;
988 minmax = WINPOS_GetMinMaxInfo( hwnd );
990 old_style = WIN_SetStyle( hwnd, WS_MAXIMIZE, WS_MINIMIZE );
991 if (old_style & WS_MINIMIZE)
992 win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
994 if (!(old_style & WS_MAXIMIZE)) swpFlags |= SWP_STATECHANGED;
995 SetRect( rect, minmax.ptMaxPosition.x, minmax.ptMaxPosition.y,
996 minmax.ptMaxPosition.x + minmax.ptMaxSize.x, minmax.ptMaxPosition.y + minmax.ptMaxSize.y );
997 break;
999 case SW_SHOWNOACTIVATE:
1000 win_set_flags( hwnd, 0, WIN_RESTORE_MAX );
1001 /* fall through */
1002 case SW_SHOWNORMAL:
1003 case SW_RESTORE:
1004 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1005 old_style = WIN_SetStyle( hwnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
1006 if (old_style & WS_MINIMIZE)
1008 if (win_get_flags( hwnd ) & WIN_RESTORE_MAX)
1010 /* Restore to maximized position */
1011 minmax = WINPOS_GetMinMaxInfo( hwnd );
1012 WIN_SetStyle( hwnd, WS_MAXIMIZE, 0 );
1013 swpFlags |= SWP_STATECHANGED;
1014 SetRect( rect, minmax.ptMaxPosition.x, minmax.ptMaxPosition.y,
1015 minmax.ptMaxPosition.x + minmax.ptMaxSize.x, minmax.ptMaxPosition.y + minmax.ptMaxSize.y );
1016 break;
1019 else if (!(old_style & WS_MAXIMIZE)) break;
1021 swpFlags |= SWP_STATECHANGED;
1023 /* Restore to normal position */
1025 *rect = wpl.rcNormalPosition;
1026 break;
1029 return swpFlags;
1033 /***********************************************************************
1034 * show_window
1036 * Implementation of ShowWindow and ShowWindowAsync.
1038 static BOOL show_window( HWND hwnd, INT cmd )
1040 WND *wndPtr;
1041 HWND parent;
1042 DPI_AWARENESS_CONTEXT context;
1043 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1044 BOOL wasVisible = (style & WS_VISIBLE) != 0;
1045 BOOL showFlag = TRUE;
1046 RECT newPos = {0, 0, 0, 0};
1047 UINT swp = 0;
1049 TRACE("hwnd=%p, cmd=%d, wasVisible %d\n", hwnd, cmd, wasVisible);
1051 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
1053 switch(cmd)
1055 case SW_HIDE:
1056 if (!wasVisible) goto done;
1057 showFlag = FALSE;
1058 swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1059 if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1060 break;
1062 case SW_SHOWMINNOACTIVE:
1063 case SW_MINIMIZE:
1064 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
1065 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1066 /* fall through */
1067 case SW_SHOWMINIMIZED:
1068 swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1069 swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
1070 if ((style & WS_MINIMIZE) && wasVisible) goto done;
1071 break;
1073 case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
1074 if (!wasVisible) swp |= SWP_SHOWWINDOW;
1075 swp |= SWP_FRAMECHANGED;
1076 swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
1077 if ((style & WS_MAXIMIZE) && wasVisible) goto done;
1078 break;
1080 case SW_SHOWNA:
1081 swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1082 if (style & WS_CHILD) swp |= SWP_NOZORDER;
1083 break;
1084 case SW_SHOW:
1085 if (wasVisible) goto done;
1086 swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1087 if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1088 break;
1090 case SW_SHOWNOACTIVATE:
1091 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1092 /* fall through */
1093 case SW_RESTORE:
1094 /* fall through */
1095 case SW_SHOWNORMAL: /* same as SW_NORMAL: */
1096 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1097 if (!wasVisible) swp |= SWP_SHOWWINDOW;
1098 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1100 swp |= SWP_FRAMECHANGED;
1101 swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
1103 else
1105 if (wasVisible) goto done;
1106 swp |= SWP_NOSIZE | SWP_NOMOVE;
1108 if (style & WS_CHILD && !(swp & SWP_STATECHANGED)) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1109 break;
1110 default:
1111 goto done;
1114 if ((showFlag != wasVisible || cmd == SW_SHOWNA) && cmd != SW_SHOWMAXIMIZED && !(swp & SWP_STATECHANGED))
1116 SendMessageW( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1117 if (!IsWindow( hwnd )) goto done;
1120 swp = USER_Driver->pShowWindow( hwnd, cmd, &newPos, swp );
1122 parent = GetAncestor( hwnd, GA_PARENT );
1123 if (parent && !IsWindowVisible( parent ) && !(swp & SWP_STATECHANGED))
1125 /* if parent is not visible simply toggle WS_VISIBLE and return */
1126 if (showFlag) WIN_SetStyle( hwnd, WS_VISIBLE, 0 );
1127 else WIN_SetStyle( hwnd, 0, WS_VISIBLE );
1129 else
1130 SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
1131 newPos.right - newPos.left, newPos.bottom - newPos.top, swp );
1133 if (cmd == SW_HIDE)
1135 HWND hFocus;
1137 /* FIXME: This will cause the window to be activated irrespective
1138 * of whether it is owned by the same thread. Has to be done
1139 * asynchronously.
1142 if (hwnd == GetActiveWindow())
1143 WINPOS_ActivateOtherWindow(hwnd);
1145 /* Revert focus to parent */
1146 hFocus = GetFocus();
1147 if (hwnd == hFocus)
1149 HWND parent = GetAncestor(hwnd, GA_PARENT);
1150 if (parent == GetDesktopWindow()) parent = 0;
1151 SetFocus(parent);
1153 goto done;
1156 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) goto done;
1158 if (wndPtr->flags & WIN_NEED_SIZE)
1160 /* should happen only in CreateWindowEx() */
1161 int wParam = SIZE_RESTORED;
1162 RECT client;
1163 LPARAM lparam;
1165 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &client );
1166 lparam = MAKELONG( client.right - client.left, client.bottom - client.top );
1167 wndPtr->flags &= ~WIN_NEED_SIZE;
1168 if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
1169 else if (wndPtr->dwStyle & WS_MINIMIZE)
1171 wParam = SIZE_MINIMIZED;
1172 lparam = 0;
1174 WIN_ReleasePtr( wndPtr );
1176 SendMessageW( hwnd, WM_SIZE, wParam, lparam );
1177 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( client.left, client.top ));
1179 else WIN_ReleasePtr( wndPtr );
1181 /* if previous state was minimized Windows sets focus to the window */
1182 if (style & WS_MINIMIZE) SetFocus( hwnd );
1184 done:
1185 SetThreadDpiAwarenessContext( context );
1186 return wasVisible;
1190 /***********************************************************************
1191 * ShowWindowAsync (USER32.@)
1193 * doesn't wait; returns immediately.
1194 * used by threads to toggle windows in other (possibly hanging) threads
1196 BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd )
1198 HWND full_handle;
1200 if (is_broadcast(hwnd))
1202 SetLastError( ERROR_INVALID_PARAMETER );
1203 return FALSE;
1206 if ((full_handle = WIN_IsCurrentThread( hwnd )))
1207 return show_window( full_handle, cmd );
1209 return SendNotifyMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
1213 /***********************************************************************
1214 * ShowWindow (USER32.@)
1216 BOOL WINAPI ShowWindow( HWND hwnd, INT cmd )
1218 HWND full_handle;
1220 if (is_broadcast(hwnd))
1222 SetLastError( ERROR_INVALID_PARAMETER );
1223 return FALSE;
1225 if ((full_handle = WIN_IsCurrentThread( hwnd )))
1226 return show_window( full_handle, cmd );
1228 if ((cmd == SW_HIDE) && !(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
1229 return FALSE;
1231 if ((cmd == SW_SHOW) && (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
1232 return TRUE;
1234 return SendMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
1238 /***********************************************************************
1239 * GetInternalWindowPos (USER32.@)
1241 UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd,
1242 LPPOINT ptIcon )
1244 WINDOWPLACEMENT wndpl;
1246 wndpl.length = sizeof(wndpl);
1247 if (GetWindowPlacement( hwnd, &wndpl ))
1249 if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
1250 if (ptIcon) *ptIcon = wndpl.ptMinPosition;
1251 return wndpl.showCmd;
1253 return 0;
1257 /***********************************************************************
1258 * GetWindowPlacement (USER32.@)
1260 * Win95:
1261 * Fails if wndpl->length of Win95 (!) apps is invalid.
1263 BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
1265 WND *pWnd = WIN_GetPtr( hwnd );
1267 if (!pWnd) return FALSE;
1269 if (pWnd == WND_DESKTOP)
1271 wndpl->length = sizeof(*wndpl);
1272 wndpl->showCmd = SW_SHOWNORMAL;
1273 wndpl->flags = 0;
1274 wndpl->ptMinPosition.x = -1;
1275 wndpl->ptMinPosition.y = -1;
1276 wndpl->ptMaxPosition.x = -1;
1277 wndpl->ptMaxPosition.y = -1;
1278 GetWindowRect( hwnd, &wndpl->rcNormalPosition );
1279 return TRUE;
1281 if (pWnd == WND_OTHER_PROCESS)
1283 RECT normal_position;
1284 DWORD style;
1286 if (!GetWindowRect(hwnd, &normal_position))
1287 return FALSE;
1289 FIXME("not fully supported on other process window %p.\n", hwnd);
1291 wndpl->length = sizeof(*wndpl);
1292 style = GetWindowLongW(hwnd, GWL_STYLE);
1293 if (style & WS_MINIMIZE)
1294 wndpl->showCmd = SW_SHOWMINIMIZED;
1295 else
1296 wndpl->showCmd = (style & WS_MAXIMIZE) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL;
1297 /* provide some dummy information */
1298 wndpl->flags = 0;
1299 wndpl->ptMinPosition.x = -1;
1300 wndpl->ptMinPosition.y = -1;
1301 wndpl->ptMaxPosition.x = -1;
1302 wndpl->ptMaxPosition.y = -1;
1303 wndpl->rcNormalPosition = normal_position;
1304 return TRUE;
1307 /* update the placement according to the current style */
1308 if (pWnd->dwStyle & WS_MINIMIZE)
1310 pWnd->min_pos.x = pWnd->window_rect.left;
1311 pWnd->min_pos.y = pWnd->window_rect.top;
1313 else if (pWnd->dwStyle & WS_MAXIMIZE)
1315 pWnd->max_pos.x = pWnd->window_rect.left;
1316 pWnd->max_pos.y = pWnd->window_rect.top;
1318 else
1320 pWnd->normal_rect = pWnd->window_rect;
1323 wndpl->length = sizeof(*wndpl);
1324 if( pWnd->dwStyle & WS_MINIMIZE )
1325 wndpl->showCmd = SW_SHOWMINIMIZED;
1326 else
1327 wndpl->showCmd = ( pWnd->dwStyle & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
1328 if( pWnd->flags & WIN_RESTORE_MAX )
1329 wndpl->flags = WPF_RESTORETOMAXIMIZED;
1330 else
1331 wndpl->flags = 0;
1332 wndpl->ptMinPosition = EMPTYPOINT(pWnd->min_pos) ? pWnd->min_pos : point_win_to_thread_dpi( hwnd, pWnd->min_pos );
1333 wndpl->ptMaxPosition = EMPTYPOINT(pWnd->max_pos) ? pWnd->max_pos : point_win_to_thread_dpi( hwnd, pWnd->max_pos );
1334 wndpl->rcNormalPosition = rect_win_to_thread_dpi( hwnd, pWnd->normal_rect );
1335 WIN_ReleasePtr( pWnd );
1337 TRACE( "%p: returning min %d,%d max %d,%d normal %s\n",
1338 hwnd, wndpl->ptMinPosition.x, wndpl->ptMinPosition.y,
1339 wndpl->ptMaxPosition.x, wndpl->ptMaxPosition.y,
1340 wine_dbgstr_rect(&wndpl->rcNormalPosition) );
1341 return TRUE;
1344 /* make sure the specified rect is visible on screen */
1345 static void make_rect_onscreen( RECT *rect )
1347 MONITORINFO info;
1348 HMONITOR monitor = MonitorFromRect( rect, MONITOR_DEFAULTTONEAREST );
1350 info.cbSize = sizeof(info);
1351 if (!monitor || !GetMonitorInfoW( monitor, &info )) return;
1352 /* FIXME: map coordinates from rcWork to rcMonitor */
1353 if (rect->right <= info.rcWork.left)
1355 rect->right += info.rcWork.left - rect->left;
1356 rect->left = info.rcWork.left;
1358 else if (rect->left >= info.rcWork.right)
1360 rect->left += info.rcWork.right - rect->right;
1361 rect->right = info.rcWork.right;
1363 if (rect->bottom <= info.rcWork.top)
1365 rect->bottom += info.rcWork.top - rect->top;
1366 rect->top = info.rcWork.top;
1368 else if (rect->top >= info.rcWork.bottom)
1370 rect->top += info.rcWork.bottom - rect->bottom;
1371 rect->bottom = info.rcWork.bottom;
1375 /* make sure the specified point is visible on screen */
1376 static void make_point_onscreen( POINT *pt )
1378 RECT rect;
1380 SetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 );
1381 make_rect_onscreen( &rect );
1382 pt->x = rect.left;
1383 pt->y = rect.top;
1387 /***********************************************************************
1388 * WINPOS_SetPlacement
1390 static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT flags )
1392 DWORD style;
1393 WND *pWnd = WIN_GetPtr( hwnd );
1394 WINDOWPLACEMENT wp = *wndpl;
1396 if (flags & PLACE_MIN) make_point_onscreen( &wp.ptMinPosition );
1397 if (flags & PLACE_MAX) make_point_onscreen( &wp.ptMaxPosition );
1398 if (flags & PLACE_RECT) make_rect_onscreen( &wp.rcNormalPosition );
1400 TRACE( "%p: setting min %d,%d max %d,%d normal %s flags %x adjusted to min %d,%d max %d,%d normal %s\n",
1401 hwnd, wndpl->ptMinPosition.x, wndpl->ptMinPosition.y,
1402 wndpl->ptMaxPosition.x, wndpl->ptMaxPosition.y,
1403 wine_dbgstr_rect(&wndpl->rcNormalPosition), flags,
1404 wp.ptMinPosition.x, wp.ptMinPosition.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y,
1405 wine_dbgstr_rect(&wp.rcNormalPosition) );
1407 if (!pWnd || pWnd == WND_OTHER_PROCESS || pWnd == WND_DESKTOP) return FALSE;
1409 if (flags & PLACE_MIN) pWnd->min_pos = point_thread_to_win_dpi( hwnd, wp.ptMinPosition );
1410 if (flags & PLACE_MAX) pWnd->max_pos = point_thread_to_win_dpi( hwnd, wp.ptMaxPosition );
1411 if (flags & PLACE_RECT) pWnd->normal_rect = rect_thread_to_win_dpi( hwnd, wp.rcNormalPosition );
1413 style = pWnd->dwStyle;
1415 WIN_ReleasePtr( pWnd );
1417 if( style & WS_MINIMIZE )
1419 if (flags & PLACE_MIN)
1421 SetWindowPos( hwnd, 0, wp.ptMinPosition.x, wp.ptMinPosition.y, 0, 0,
1422 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1425 else if( style & WS_MAXIMIZE )
1427 if (flags & PLACE_MAX)
1428 SetWindowPos( hwnd, 0, wp.ptMaxPosition.x, wp.ptMaxPosition.y, 0, 0,
1429 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1431 else if( flags & PLACE_RECT )
1432 SetWindowPos( hwnd, 0, wp.rcNormalPosition.left, wp.rcNormalPosition.top,
1433 wp.rcNormalPosition.right - wp.rcNormalPosition.left,
1434 wp.rcNormalPosition.bottom - wp.rcNormalPosition.top,
1435 SWP_NOZORDER | SWP_NOACTIVATE );
1437 ShowWindow( hwnd, wndpl->showCmd );
1439 if (IsIconic( hwnd ))
1441 /* SDK: ...valid only the next time... */
1442 if( wndpl->flags & WPF_RESTORETOMAXIMIZED )
1443 win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
1445 return TRUE;
1449 /***********************************************************************
1450 * SetWindowPlacement (USER32.@)
1452 * Win95:
1453 * Fails if wndpl->length of Win95 (!) apps is invalid.
1455 BOOL WINAPI SetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl )
1457 UINT flags = PLACE_MAX | PLACE_RECT;
1458 if (!wpl) return FALSE;
1459 if (wpl->flags & WPF_SETMINPOSITION) flags |= PLACE_MIN;
1460 return WINPOS_SetPlacement( hwnd, wpl, flags );
1464 /***********************************************************************
1465 * AnimateWindow (USER32.@)
1466 * Shows/Hides a window with an animation
1467 * NO ANIMATION YET
1469 BOOL WINAPI AnimateWindow(HWND hwnd, DWORD dwTime, DWORD dwFlags)
1471 FIXME("partial stub\n");
1473 /* If trying to show/hide and it's already *
1474 * shown/hidden or invalid window, fail with *
1475 * invalid parameter */
1476 if(!IsWindow(hwnd) ||
1477 (IsWindowVisible(hwnd) && !(dwFlags & AW_HIDE)) ||
1478 (!IsWindowVisible(hwnd) && (dwFlags & AW_HIDE)))
1480 SetLastError(ERROR_INVALID_PARAMETER);
1481 return FALSE;
1484 ShowWindow(hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA));
1486 return TRUE;
1489 /***********************************************************************
1490 * SetInternalWindowPos (USER32.@)
1492 void WINAPI SetInternalWindowPos( HWND hwnd, UINT showCmd,
1493 LPRECT rect, LPPOINT pt )
1495 WINDOWPLACEMENT wndpl;
1496 UINT flags;
1498 wndpl.length = sizeof(wndpl);
1499 wndpl.showCmd = showCmd;
1500 wndpl.flags = flags = 0;
1502 if( pt )
1504 flags |= PLACE_MIN;
1505 wndpl.flags |= WPF_SETMINPOSITION;
1506 wndpl.ptMinPosition = *pt;
1508 if( rect )
1510 flags |= PLACE_RECT;
1511 wndpl.rcNormalPosition = *rect;
1513 WINPOS_SetPlacement( hwnd, &wndpl, flags );
1517 /*******************************************************************
1518 * can_activate_window
1520 * Check if we can activate the specified window.
1522 static BOOL can_activate_window( HWND hwnd )
1524 LONG style;
1526 if (!hwnd) return FALSE;
1527 style = GetWindowLongW( hwnd, GWL_STYLE );
1528 if (!(style & WS_VISIBLE)) return FALSE;
1529 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
1530 return !(style & WS_DISABLED);
1534 /*******************************************************************
1535 * WINPOS_ActivateOtherWindow
1537 * Activates window other than pWnd.
1539 void WINPOS_ActivateOtherWindow(HWND hwnd)
1541 HWND hwndTo, fg;
1543 if ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) && (hwndTo = GetWindow( hwnd, GW_OWNER )))
1545 hwndTo = GetAncestor( hwndTo, GA_ROOT );
1546 if (can_activate_window( hwndTo )) goto done;
1549 hwndTo = hwnd;
1550 for (;;)
1552 if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break;
1553 if (can_activate_window( hwndTo )) goto done;
1556 hwndTo = GetTopWindow( 0 );
1557 for (;;)
1559 if (hwndTo == hwnd)
1561 hwndTo = 0;
1562 break;
1564 if (can_activate_window( hwndTo )) goto done;
1565 if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break;
1568 done:
1569 fg = GetForegroundWindow();
1570 TRACE("win = %p fg = %p\n", hwndTo, fg);
1571 if (!fg || (hwnd == fg))
1573 if (SetForegroundWindow( hwndTo )) return;
1575 if (!SetActiveWindow( hwndTo )) SetActiveWindow(0);
1579 /***********************************************************************
1580 * WINPOS_HandleWindowPosChanging
1582 * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
1584 LONG WINPOS_HandleWindowPosChanging( HWND hwnd, WINDOWPOS *winpos )
1586 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1588 if (winpos->flags & SWP_NOSIZE) return 0;
1589 if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0))
1591 MINMAXINFO info = WINPOS_GetMinMaxInfo( hwnd );
1592 winpos->cx = min( winpos->cx, info.ptMaxTrackSize.x );
1593 winpos->cy = min( winpos->cy, info.ptMaxTrackSize.y );
1594 if (!(style & WS_MINIMIZE))
1596 winpos->cx = max( winpos->cx, info.ptMinTrackSize.x );
1597 winpos->cy = max( winpos->cy, info.ptMinTrackSize.y );
1600 return 0;
1604 /***********************************************************************
1605 * dump_winpos_flags
1607 static void dump_winpos_flags(UINT flags)
1609 static const DWORD dumped_flags = (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW |
1610 SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW |
1611 SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOOWNERZORDER |
1612 SWP_NOSENDCHANGING | SWP_DEFERERASE | SWP_ASYNCWINDOWPOS |
1613 SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_STATECHANGED);
1614 TRACE("flags:");
1615 if(flags & SWP_NOSIZE) TRACE(" SWP_NOSIZE");
1616 if(flags & SWP_NOMOVE) TRACE(" SWP_NOMOVE");
1617 if(flags & SWP_NOZORDER) TRACE(" SWP_NOZORDER");
1618 if(flags & SWP_NOREDRAW) TRACE(" SWP_NOREDRAW");
1619 if(flags & SWP_NOACTIVATE) TRACE(" SWP_NOACTIVATE");
1620 if(flags & SWP_FRAMECHANGED) TRACE(" SWP_FRAMECHANGED");
1621 if(flags & SWP_SHOWWINDOW) TRACE(" SWP_SHOWWINDOW");
1622 if(flags & SWP_HIDEWINDOW) TRACE(" SWP_HIDEWINDOW");
1623 if(flags & SWP_NOCOPYBITS) TRACE(" SWP_NOCOPYBITS");
1624 if(flags & SWP_NOOWNERZORDER) TRACE(" SWP_NOOWNERZORDER");
1625 if(flags & SWP_NOSENDCHANGING) TRACE(" SWP_NOSENDCHANGING");
1626 if(flags & SWP_DEFERERASE) TRACE(" SWP_DEFERERASE");
1627 if(flags & SWP_ASYNCWINDOWPOS) TRACE(" SWP_ASYNCWINDOWPOS");
1628 if(flags & SWP_NOCLIENTSIZE) TRACE(" SWP_NOCLIENTSIZE");
1629 if(flags & SWP_NOCLIENTMOVE) TRACE(" SWP_NOCLIENTMOVE");
1630 if(flags & SWP_STATECHANGED) TRACE(" SWP_STATECHANGED");
1632 if(flags & ~dumped_flags) TRACE(" %08x", flags & ~dumped_flags);
1633 TRACE("\n");
1637 /***********************************************************************
1638 * map_dpi_winpos
1640 static void map_dpi_winpos( WINDOWPOS *winpos )
1642 UINT dpi_from = get_thread_dpi();
1643 UINT dpi_to = GetDpiForWindow( winpos->hwnd );
1645 if (!dpi_from) dpi_from = get_win_monitor_dpi( winpos->hwnd );
1646 if (dpi_from == dpi_to) return;
1647 winpos->x = MulDiv( winpos->x, dpi_to, dpi_from );
1648 winpos->y = MulDiv( winpos->y, dpi_to, dpi_from );
1649 winpos->cx = MulDiv( winpos->cx, dpi_to, dpi_from );
1650 winpos->cy = MulDiv( winpos->cy, dpi_to, dpi_from );
1653 /***********************************************************************
1654 * SWP_DoWinPosChanging
1656 static BOOL SWP_DoWinPosChanging( WINDOWPOS *pWinpos, RECT *old_window_rect, RECT *old_client_rect,
1657 RECT *new_window_rect, RECT *new_client_rect )
1659 WND *wndPtr;
1661 /* Send WM_WINDOWPOSCHANGING message */
1663 if (!(pWinpos->flags & SWP_NOSENDCHANGING)
1664 && !((pWinpos->flags & SWP_AGG_NOCLIENTCHANGE) && (pWinpos->flags & SWP_SHOWWINDOW)))
1665 SendMessageW( pWinpos->hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
1667 if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) ||
1668 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
1670 /* Calculate new position and size */
1672 WIN_GetRectangles( pWinpos->hwnd, COORDS_PARENT, old_window_rect, old_client_rect );
1673 *new_window_rect = *old_window_rect;
1674 *new_client_rect = *old_client_rect;
1676 if (!(pWinpos->flags & SWP_NOSIZE))
1678 if (wndPtr->dwStyle & WS_MINIMIZE)
1680 new_window_rect->right = new_window_rect->left + GetSystemMetrics(SM_CXMINIMIZED);
1681 new_window_rect->bottom = new_window_rect->top + GetSystemMetrics(SM_CYMINIMIZED);
1683 else
1685 new_window_rect->right = new_window_rect->left + pWinpos->cx;
1686 new_window_rect->bottom = new_window_rect->top + pWinpos->cy;
1689 if (!(pWinpos->flags & SWP_NOMOVE))
1691 new_window_rect->left = pWinpos->x;
1692 new_window_rect->top = pWinpos->y;
1693 new_window_rect->right += pWinpos->x - old_window_rect->left;
1694 new_window_rect->bottom += pWinpos->y - old_window_rect->top;
1696 OffsetRect( new_client_rect, pWinpos->x - old_window_rect->left,
1697 pWinpos->y - old_window_rect->top );
1699 pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1701 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x current %s style %08x new %s\n",
1702 pWinpos->hwnd, pWinpos->hwndInsertAfter, pWinpos->x, pWinpos->y,
1703 pWinpos->cx, pWinpos->cy, pWinpos->flags,
1704 wine_dbgstr_rect( old_window_rect ), wndPtr->dwStyle,
1705 wine_dbgstr_rect( new_window_rect ));
1707 WIN_ReleasePtr( wndPtr );
1708 return TRUE;
1711 /***********************************************************************
1712 * get_valid_rects
1714 * Compute the valid rects from the old and new client rect and WVR_* flags.
1715 * Helper for WM_NCCALCSIZE handling.
1717 static inline void get_valid_rects( const RECT *old_client, const RECT *new_client, UINT flags,
1718 RECT *valid )
1720 int cx, cy;
1722 if (flags & WVR_REDRAW)
1724 SetRectEmpty( &valid[0] );
1725 SetRectEmpty( &valid[1] );
1726 return;
1729 if (flags & WVR_VALIDRECTS)
1731 if (!IntersectRect( &valid[0], &valid[0], new_client ) ||
1732 !IntersectRect( &valid[1], &valid[1], old_client ))
1734 SetRectEmpty( &valid[0] );
1735 SetRectEmpty( &valid[1] );
1736 return;
1738 flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
1740 else
1742 valid[0] = *new_client;
1743 valid[1] = *old_client;
1746 /* make sure the rectangles have the same size */
1747 cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
1748 cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
1750 if (flags & WVR_ALIGNBOTTOM)
1752 valid[0].top = valid[0].bottom - cy;
1753 valid[1].top = valid[1].bottom - cy;
1755 else
1757 valid[0].bottom = valid[0].top + cy;
1758 valid[1].bottom = valid[1].top + cy;
1760 if (flags & WVR_ALIGNRIGHT)
1762 valid[0].left = valid[0].right - cx;
1763 valid[1].left = valid[1].right - cx;
1765 else
1767 valid[0].right = valid[0].left + cx;
1768 valid[1].right = valid[1].left + cx;
1773 /***********************************************************************
1774 * SWP_DoOwnedPopups
1776 * fix Z order taking into account owned popups -
1777 * basically we need to maintain them above the window that owns them
1779 * FIXME: hide/show owned popups when owner visibility changes.
1781 static HWND SWP_DoOwnedPopups(HWND hwnd, HWND hwndInsertAfter)
1783 HWND owner, *list = NULL;
1784 unsigned int i;
1786 TRACE("(%p) hInsertAfter = %p\n", hwnd, hwndInsertAfter );
1788 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return hwndInsertAfter;
1790 if ((owner = GetWindow( hwnd, GW_OWNER )))
1792 /* make sure this popup stays above the owner */
1794 if (hwndInsertAfter != HWND_TOPMOST)
1796 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return hwndInsertAfter;
1798 for (i = 0; list[i]; i++)
1800 BOOL topmost = (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TOPMOST) != 0;
1802 if (list[i] == owner)
1804 if (i > 0) hwndInsertAfter = list[i-1];
1805 else hwndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
1806 break;
1809 if (hwndInsertAfter == HWND_TOP || hwndInsertAfter == HWND_NOTOPMOST)
1811 if (!topmost) break;
1813 else if (list[i] == hwndInsertAfter) break;
1818 if (hwndInsertAfter == HWND_BOTTOM) goto done;
1819 if (!list && !(list = WIN_ListChildren( GetDesktopWindow() ))) goto done;
1821 i = 0;
1822 if (hwndInsertAfter == HWND_TOP || hwndInsertAfter == HWND_NOTOPMOST)
1824 if (hwndInsertAfter == HWND_NOTOPMOST || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST))
1826 /* skip all the topmost windows */
1827 while (list[i] && (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TOPMOST)) i++;
1830 else if (hwndInsertAfter != HWND_TOPMOST)
1832 /* skip windows that are already placed correctly */
1833 for (i = 0; list[i]; i++)
1835 if (list[i] == hwndInsertAfter) break;
1836 if (list[i] == hwnd) goto done; /* nothing to do if window is moving backwards in z-order */
1840 for ( ; list[i]; i++)
1842 if (list[i] == hwnd) break;
1843 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1844 TRACE( "moving %p owned by %p after %p\n", list[i], hwnd, hwndInsertAfter );
1845 SetWindowPos( list[i], hwndInsertAfter, 0, 0, 0, 0,
1846 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE );
1847 hwndInsertAfter = list[i];
1850 done:
1851 HeapFree( GetProcessHeap(), 0, list );
1852 return hwndInsertAfter;
1855 /***********************************************************************
1856 * SWP_DoNCCalcSize
1858 static UINT SWP_DoNCCalcSize( WINDOWPOS *pWinpos, const RECT *old_window_rect, const RECT *old_client_rect,
1859 const RECT *new_window_rect, RECT *new_client_rect, RECT *validRects,
1860 int parent_x, int parent_y )
1862 UINT wvrFlags = 0;
1864 /* Send WM_NCCALCSIZE message to get new client area */
1865 if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
1867 NCCALCSIZE_PARAMS params;
1868 WINDOWPOS winposCopy;
1870 params.rgrc[0] = *new_window_rect;
1871 params.rgrc[1] = *old_window_rect;
1872 params.rgrc[2] = *old_client_rect;
1873 params.lppos = &winposCopy;
1874 winposCopy = *pWinpos;
1876 if (pWinpos->flags & SWP_NOMOVE)
1878 winposCopy.x = old_window_rect->left;
1879 winposCopy.y = old_window_rect->top;
1882 if (pWinpos->flags & SWP_NOSIZE)
1884 winposCopy.cx = old_window_rect->right - old_window_rect->left;
1885 winposCopy.cy = old_window_rect->bottom - old_window_rect->top;
1888 wvrFlags = SendMessageW( pWinpos->hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)&params );
1890 *new_client_rect = params.rgrc[0];
1892 TRACE( "hwnd %p old win %s old client %s new win %s new client %s\n", pWinpos->hwnd,
1893 wine_dbgstr_rect(old_window_rect), wine_dbgstr_rect(old_client_rect),
1894 wine_dbgstr_rect(new_window_rect), wine_dbgstr_rect(new_client_rect) );
1896 if (new_client_rect->left != old_client_rect->left - parent_x ||
1897 new_client_rect->top != old_client_rect->top - parent_y)
1898 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
1900 if( (new_client_rect->right - new_client_rect->left !=
1901 old_client_rect->right - old_client_rect->left))
1902 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
1903 else
1904 wvrFlags &= ~WVR_HREDRAW;
1906 if (new_client_rect->bottom - new_client_rect->top !=
1907 old_client_rect->bottom - old_client_rect->top)
1908 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
1909 else
1910 wvrFlags &= ~WVR_VREDRAW;
1912 validRects[0] = params.rgrc[1];
1913 validRects[1] = params.rgrc[2];
1915 else
1917 if (!(pWinpos->flags & SWP_NOMOVE) &&
1918 (new_client_rect->left != old_client_rect->left - parent_x ||
1919 new_client_rect->top != old_client_rect->top - parent_y))
1920 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
1923 if (pWinpos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
1925 SetRectEmpty( &validRects[0] );
1926 SetRectEmpty( &validRects[1] );
1928 else get_valid_rects( old_client_rect, new_client_rect, wvrFlags, validRects );
1930 return wvrFlags;
1933 /* fix redundant flags and values in the WINDOWPOS structure */
1934 static BOOL fixup_flags( WINDOWPOS *winpos, const RECT *old_window_rect, int parent_x, int parent_y )
1936 HWND parent;
1937 WND *wndPtr = WIN_GetPtr( winpos->hwnd );
1938 BOOL ret = TRUE;
1940 if (!wndPtr || wndPtr == WND_OTHER_PROCESS)
1942 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1943 return FALSE;
1945 winpos->hwnd = wndPtr->obj.handle; /* make it a full handle */
1947 /* Finally make sure that all coordinates are valid */
1948 if (winpos->x < -32768) winpos->x = -32768;
1949 else if (winpos->x > 32767) winpos->x = 32767;
1950 if (winpos->y < -32768) winpos->y = -32768;
1951 else if (winpos->y > 32767) winpos->y = 32767;
1953 if (winpos->cx < 0) winpos->cx = 0;
1954 else if (winpos->cx > 32767) winpos->cx = 32767;
1955 if (winpos->cy < 0) winpos->cy = 0;
1956 else if (winpos->cy > 32767) winpos->cy = 32767;
1958 parent = GetAncestor( winpos->hwnd, GA_PARENT );
1959 if (!IsWindowVisible( parent )) winpos->flags |= SWP_NOREDRAW;
1961 if (wndPtr->dwStyle & WS_VISIBLE) winpos->flags &= ~SWP_SHOWWINDOW;
1962 else
1964 winpos->flags &= ~SWP_HIDEWINDOW;
1965 if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
1968 if ((old_window_rect->right - old_window_rect->left == winpos->cx) &&
1969 (old_window_rect->bottom - old_window_rect->top == winpos->cy))
1970 winpos->flags |= SWP_NOSIZE; /* Already the right size */
1972 if ((old_window_rect->left - parent_x == winpos->x) && (old_window_rect->top - parent_y == winpos->y))
1973 winpos->flags |= SWP_NOMOVE; /* Already the right position */
1975 if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1977 if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) && /* Bring to the top when activating */
1978 (winpos->flags & SWP_NOZORDER ||
1979 (winpos->hwndInsertAfter != HWND_TOPMOST && winpos->hwndInsertAfter != HWND_NOTOPMOST)))
1981 winpos->flags &= ~SWP_NOZORDER;
1982 winpos->hwndInsertAfter = HWND_TOP;
1986 /* Check hwndInsertAfter */
1987 if (winpos->flags & SWP_NOZORDER) goto done;
1989 if (winpos->hwndInsertAfter == HWND_TOP)
1991 if (GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
1992 winpos->flags |= SWP_NOZORDER;
1994 else if (winpos->hwndInsertAfter == HWND_BOTTOM)
1996 if (!(wndPtr->dwExStyle & WS_EX_TOPMOST) && GetWindow(winpos->hwnd, GW_HWNDLAST) == winpos->hwnd)
1997 winpos->flags |= SWP_NOZORDER;
1999 else if (winpos->hwndInsertAfter == HWND_TOPMOST)
2001 if ((wndPtr->dwExStyle & WS_EX_TOPMOST) && GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
2002 winpos->flags |= SWP_NOZORDER;
2004 else if (winpos->hwndInsertAfter == HWND_NOTOPMOST)
2006 if (!(wndPtr->dwExStyle & WS_EX_TOPMOST))
2007 winpos->flags |= SWP_NOZORDER;
2009 else
2011 if ((winpos->hwnd == winpos->hwndInsertAfter) ||
2012 (winpos->hwnd == GetWindow( winpos->hwndInsertAfter, GW_HWNDNEXT )))
2013 winpos->flags |= SWP_NOZORDER;
2015 done:
2016 WIN_ReleasePtr( wndPtr );
2017 return ret;
2021 /***********************************************************************
2022 * update_surface_region
2024 static void update_surface_region( HWND hwnd )
2026 NTSTATUS status;
2027 HRGN region = 0;
2028 RGNDATA *data;
2029 size_t size = 256;
2030 WND *win = WIN_GetPtr( hwnd );
2032 if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS) return;
2033 if (!win->surface) goto done;
2037 if (!(data = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( RGNDATA, Buffer[size] )))) goto done;
2039 SERVER_START_REQ( get_surface_region )
2041 req->window = wine_server_user_handle( hwnd );
2042 wine_server_set_reply( req, data->Buffer, size );
2043 if (!(status = wine_server_call( req )))
2045 size_t reply_size = wine_server_reply_size( reply );
2046 if (reply_size)
2048 data->rdh.dwSize = sizeof(data->rdh);
2049 data->rdh.iType = RDH_RECTANGLES;
2050 data->rdh.nCount = reply_size / sizeof(RECT);
2051 data->rdh.nRgnSize = reply_size;
2052 region = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
2053 OffsetRgn( region, -reply->visible_rect.left, -reply->visible_rect.top );
2056 else size = reply->total_size;
2058 SERVER_END_REQ;
2059 HeapFree( GetProcessHeap(), 0, data );
2060 } while (status == STATUS_BUFFER_OVERFLOW);
2062 if (status) goto done;
2064 win->surface->funcs->set_region( win->surface, region );
2065 if (region) DeleteObject( region );
2067 done:
2068 WIN_ReleasePtr( win );
2072 /***********************************************************************
2073 * set_window_pos
2075 * Backend implementation of SetWindowPos.
2077 BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags,
2078 const RECT *window_rect, const RECT *client_rect, const RECT *valid_rects )
2080 WND *win;
2081 HWND surface_win = 0, parent = GetAncestor( hwnd, GA_PARENT );
2082 BOOL ret, needs_update = FALSE;
2083 RECT visible_rect, old_visible_rect, old_window_rect, old_client_rect, extra_rects[3];
2084 struct window_surface *old_surface, *new_surface = NULL;
2086 if (!parent || parent == GetDesktopWindow())
2088 new_surface = &dummy_surface; /* provide a default surface for top-level windows */
2089 window_surface_add_ref( new_surface );
2091 visible_rect = *window_rect;
2092 USER_Driver->pWindowPosChanging( hwnd, insert_after, swp_flags,
2093 window_rect, client_rect, &visible_rect, &new_surface );
2095 WIN_GetRectangles( hwnd, COORDS_SCREEN, &old_window_rect, NULL );
2096 if (IsRectEmpty( &valid_rects[0] )) valid_rects = NULL;
2098 if (!(win = WIN_GetPtr( hwnd )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
2100 if (new_surface) window_surface_release( new_surface );
2101 return FALSE;
2103 old_visible_rect = win->visible_rect;
2104 old_client_rect = win->client_rect;
2105 old_surface = win->surface;
2106 if (old_surface != new_surface) swp_flags |= SWP_FRAMECHANGED; /* force refreshing non-client area */
2107 if (new_surface == &dummy_surface) swp_flags |= SWP_NOREDRAW;
2108 else if (old_surface == &dummy_surface)
2110 swp_flags |= SWP_NOCOPYBITS;
2111 valid_rects = NULL;
2114 SERVER_START_REQ( set_window_pos )
2116 req->handle = wine_server_user_handle( hwnd );
2117 req->previous = wine_server_user_handle( insert_after );
2118 req->swp_flags = swp_flags;
2119 req->window.left = window_rect->left;
2120 req->window.top = window_rect->top;
2121 req->window.right = window_rect->right;
2122 req->window.bottom = window_rect->bottom;
2123 req->client.left = client_rect->left;
2124 req->client.top = client_rect->top;
2125 req->client.right = client_rect->right;
2126 req->client.bottom = client_rect->bottom;
2127 if (!EqualRect( window_rect, &visible_rect ) || new_surface || valid_rects)
2129 extra_rects[0] = extra_rects[1] = visible_rect;
2130 if (new_surface)
2132 extra_rects[1] = new_surface->rect;
2133 OffsetRect( &extra_rects[1], visible_rect.left, visible_rect.top );
2135 if (valid_rects) extra_rects[2] = valid_rects[0];
2136 else SetRectEmpty( &extra_rects[2] );
2137 wine_server_add_data( req, extra_rects, sizeof(extra_rects) );
2139 if (new_surface) req->paint_flags |= SET_WINPOS_PAINT_SURFACE;
2140 if (win->pixel_format) req->paint_flags |= SET_WINPOS_PIXEL_FORMAT;
2142 if ((ret = !wine_server_call( req )))
2144 win->dwStyle = reply->new_style;
2145 win->dwExStyle = reply->new_ex_style;
2146 win->window_rect = *window_rect;
2147 win->client_rect = *client_rect;
2148 win->visible_rect = visible_rect;
2149 win->surface = new_surface;
2150 surface_win = wine_server_ptr_handle( reply->surface_win );
2151 needs_update = reply->needs_update;
2152 if (GetWindowLongW( win->parent, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
2154 RECT client;
2155 GetClientRect( win->parent, &client );
2156 mirror_rect( &client, &win->window_rect );
2157 mirror_rect( &client, &win->client_rect );
2158 mirror_rect( &client, &win->visible_rect );
2160 /* if an RTL window is resized the children have moved */
2161 if (win->dwExStyle & WS_EX_LAYOUTRTL &&
2162 client_rect->right - client_rect->left != old_client_rect.right - old_client_rect.left)
2163 win->flags |= WIN_CHILDREN_MOVED;
2166 SERVER_END_REQ;
2168 if (ret)
2170 if (needs_update) update_surface_region( surface_win );
2171 if (((swp_flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) ||
2172 (swp_flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW | SWP_STATECHANGED | SWP_FRAMECHANGED)))
2173 invalidate_dce( win, &old_window_rect );
2176 WIN_ReleasePtr( win );
2178 if (ret)
2180 TRACE( "win %p surface %p -> %p\n", hwnd, old_surface, new_surface );
2181 register_window_surface( old_surface, new_surface );
2182 if (old_surface)
2184 if (valid_rects)
2186 move_window_bits( hwnd, old_surface, new_surface, &visible_rect,
2187 &old_visible_rect, window_rect, valid_rects );
2188 valid_rects = NULL; /* prevent the driver from trying to also move the bits */
2190 window_surface_release( old_surface );
2192 else if (surface_win && surface_win != hwnd)
2194 if (valid_rects)
2196 RECT rects[2];
2197 int x_offset = old_visible_rect.left - visible_rect.left;
2198 int y_offset = old_visible_rect.top - visible_rect.top;
2200 /* if all that happened is that the whole window moved, copy everything */
2201 if (!(swp_flags & SWP_FRAMECHANGED) &&
2202 old_visible_rect.right - visible_rect.right == x_offset &&
2203 old_visible_rect.bottom - visible_rect.bottom == y_offset &&
2204 old_client_rect.left - client_rect->left == x_offset &&
2205 old_client_rect.right - client_rect->right == x_offset &&
2206 old_client_rect.top - client_rect->top == y_offset &&
2207 old_client_rect.bottom - client_rect->bottom == y_offset &&
2208 EqualRect( &valid_rects[0], client_rect ))
2210 rects[0] = visible_rect;
2211 rects[1] = old_visible_rect;
2212 valid_rects = rects;
2214 move_window_bits_parent( hwnd, surface_win, window_rect, valid_rects );
2215 valid_rects = NULL; /* prevent the driver from trying to also move the bits */
2219 USER_Driver->pWindowPosChanged( hwnd, insert_after, swp_flags, window_rect,
2220 client_rect, &visible_rect, valid_rects, new_surface );
2222 else if (new_surface) window_surface_release( new_surface );
2224 return ret;
2228 /***********************************************************************
2229 * USER_SetWindowPos
2231 * User32 internal function
2233 BOOL USER_SetWindowPos( WINDOWPOS * winpos, int parent_x, int parent_y )
2235 RECT old_window_rect, old_client_rect, new_window_rect, new_client_rect, valid_rects[2];
2236 UINT orig_flags;
2237 BOOL ret = FALSE;
2238 DPI_AWARENESS_CONTEXT context;
2240 orig_flags = winpos->flags;
2242 /* First, check z-order arguments. */
2243 if (!(winpos->flags & SWP_NOZORDER))
2245 /* fix sign extension */
2246 if (winpos->hwndInsertAfter == (HWND)0xffff) winpos->hwndInsertAfter = HWND_TOPMOST;
2247 else if (winpos->hwndInsertAfter == (HWND)0xfffe) winpos->hwndInsertAfter = HWND_NOTOPMOST;
2249 if (!(winpos->hwndInsertAfter == HWND_TOP ||
2250 winpos->hwndInsertAfter == HWND_BOTTOM ||
2251 winpos->hwndInsertAfter == HWND_TOPMOST ||
2252 winpos->hwndInsertAfter == HWND_NOTOPMOST))
2254 HWND parent = GetAncestor( winpos->hwnd, GA_PARENT );
2255 HWND insertafter_parent = GetAncestor( winpos->hwndInsertAfter, GA_PARENT );
2257 /* hwndInsertAfter must be a sibling of the window */
2258 if (!insertafter_parent) return FALSE;
2259 if (insertafter_parent != parent) return TRUE;
2263 /* Make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
2264 if (!(winpos->flags & SWP_NOMOVE))
2266 if (winpos->x < -32768) winpos->x = -32768;
2267 else if (winpos->x > 32767) winpos->x = 32767;
2268 if (winpos->y < -32768) winpos->y = -32768;
2269 else if (winpos->y > 32767) winpos->y = 32767;
2271 if (!(winpos->flags & SWP_NOSIZE))
2273 if (winpos->cx < 0) winpos->cx = 0;
2274 else if (winpos->cx > 32767) winpos->cx = 32767;
2275 if (winpos->cy < 0) winpos->cy = 0;
2276 else if (winpos->cy > 32767) winpos->cy = 32767;
2279 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( winpos->hwnd ));
2281 if (!SWP_DoWinPosChanging( winpos, &old_window_rect, &old_client_rect,
2282 &new_window_rect, &new_client_rect )) goto done;
2284 /* Fix redundant flags */
2285 if (!fixup_flags( winpos, &old_window_rect, parent_x, parent_y )) goto done;
2287 if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
2289 if (GetAncestor( winpos->hwnd, GA_PARENT ) == GetDesktopWindow())
2290 winpos->hwndInsertAfter = SWP_DoOwnedPopups( winpos->hwnd, winpos->hwndInsertAfter );
2293 /* Common operations */
2295 SWP_DoNCCalcSize( winpos, &old_window_rect, &old_client_rect,
2296 &new_window_rect, &new_client_rect, valid_rects, parent_x, parent_y );
2298 if (!set_window_pos( winpos->hwnd, winpos->hwndInsertAfter, winpos->flags,
2299 &new_window_rect, &new_client_rect, valid_rects ))
2300 goto done;
2303 if( winpos->flags & SWP_HIDEWINDOW )
2304 HideCaret(winpos->hwnd);
2305 else if (winpos->flags & SWP_SHOWWINDOW)
2306 ShowCaret(winpos->hwnd);
2308 if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2310 /* child windows get WM_CHILDACTIVATE message */
2311 if ((GetWindowLongW( winpos->hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2312 SendMessageW( winpos->hwnd, WM_CHILDACTIVATE, 0, 0 );
2313 else
2314 SetForegroundWindow( winpos->hwnd );
2317 if(!(orig_flags & SWP_DEFERERASE))
2319 /* erase parent when hiding or resizing child */
2320 if ((orig_flags & SWP_HIDEWINDOW) ||
2321 (!(orig_flags & SWP_SHOWWINDOW) &&
2322 (winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE))
2324 HWND parent = GetAncestor( winpos->hwnd, GA_PARENT );
2325 if (!parent || parent == GetDesktopWindow()) parent = winpos->hwnd;
2326 erase_now( parent, 0 );
2329 /* Give newly shown windows a chance to redraw */
2330 if(((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2331 && !(orig_flags & SWP_AGG_NOCLIENTCHANGE) && (orig_flags & SWP_SHOWWINDOW))
2333 erase_now(winpos->hwnd, 0);
2337 /* And last, send the WM_WINDOWPOSCHANGED message */
2339 TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
2341 if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2342 && !((orig_flags & SWP_AGG_NOCLIENTCHANGE) && (orig_flags & SWP_SHOWWINDOW)))
2344 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2345 and always contains final window position.
2347 winpos->x = new_window_rect.left;
2348 winpos->y = new_window_rect.top;
2349 winpos->cx = new_window_rect.right - new_window_rect.left;
2350 winpos->cy = new_window_rect.bottom - new_window_rect.top;
2351 SendMessageW( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
2353 ret = TRUE;
2354 done:
2355 SetThreadDpiAwarenessContext( context );
2356 return ret;
2359 /***********************************************************************
2360 * SetWindowPos (USER32.@)
2362 BOOL WINAPI SetWindowPos( HWND hwnd, HWND hwndInsertAfter,
2363 INT x, INT y, INT cx, INT cy, UINT flags )
2365 WINDOWPOS winpos;
2367 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2368 hwnd, hwndInsertAfter, x, y, cx, cy, flags);
2369 if(TRACE_ON(win)) dump_winpos_flags(flags);
2371 if (is_broadcast(hwnd))
2373 SetLastError( ERROR_INVALID_PARAMETER );
2374 return FALSE;
2377 winpos.hwnd = WIN_GetFullHandle(hwnd);
2378 winpos.hwndInsertAfter = WIN_GetFullHandle(hwndInsertAfter);
2379 winpos.x = x;
2380 winpos.y = y;
2381 winpos.cx = cx;
2382 winpos.cy = cy;
2383 winpos.flags = flags;
2385 map_dpi_winpos( &winpos );
2387 if (WIN_IsCurrentThread( hwnd ))
2388 return USER_SetWindowPos( &winpos, 0, 0 );
2390 if (flags & SWP_ASYNCWINDOWPOS)
2391 return SendNotifyMessageW( winpos.hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)&winpos );
2392 else
2393 return SendMessageW( winpos.hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)&winpos );
2397 /***********************************************************************
2398 * BeginDeferWindowPos (USER32.@)
2400 HDWP WINAPI BeginDeferWindowPos( INT count )
2402 HDWP handle = 0;
2403 DWP *pDWP;
2405 TRACE("%d\n", count);
2407 if (count < 0)
2409 SetLastError(ERROR_INVALID_PARAMETER);
2410 return 0;
2412 /* Windows allows zero count, in which case it allocates context for 8 moves */
2413 if (count == 0) count = 8;
2415 if (!(pDWP = HeapAlloc( GetProcessHeap(), 0, sizeof(DWP)))) return 0;
2417 pDWP->actualCount = 0;
2418 pDWP->suggestedCount = count;
2419 pDWP->hwndParent = 0;
2421 if (!(pDWP->winPos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WINDOWPOS) )) ||
2422 !(handle = alloc_user_handle( &pDWP->obj, USER_DWP )))
2424 HeapFree( GetProcessHeap(), 0, pDWP->winPos );
2425 HeapFree( GetProcessHeap(), 0, pDWP );
2428 TRACE("returning hdwp %p\n", handle);
2429 return handle;
2433 /***********************************************************************
2434 * DeferWindowPos (USER32.@)
2436 HDWP WINAPI DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter,
2437 INT x, INT y, INT cx, INT cy,
2438 UINT flags )
2440 DWP *pDWP;
2441 int i;
2442 HDWP retvalue = hdwp;
2443 WINDOWPOS winpos;
2445 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2446 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2448 winpos.hwnd = WIN_GetFullHandle( hwnd );
2449 if (is_desktop_window( winpos.hwnd ) || !IsWindow( winpos.hwnd ))
2451 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2452 return 0;
2455 winpos.hwndInsertAfter = WIN_GetFullHandle(hwndAfter);
2456 winpos.flags = flags;
2457 winpos.x = x;
2458 winpos.y = y;
2459 winpos.cx = cx;
2460 winpos.cy = cy;
2461 map_dpi_winpos( &winpos );
2463 if (!(pDWP = get_user_handle_ptr( hdwp, USER_DWP ))) return 0;
2464 if (pDWP == OBJ_OTHER_PROCESS)
2466 FIXME( "other process handle %p?\n", hdwp );
2467 return 0;
2470 for (i = 0; i < pDWP->actualCount; i++)
2472 if (pDWP->winPos[i].hwnd == winpos.hwnd)
2474 /* Merge with the other changes */
2475 if (!(flags & SWP_NOZORDER))
2477 pDWP->winPos[i].hwndInsertAfter = winpos.hwndInsertAfter;
2479 if (!(flags & SWP_NOMOVE))
2481 pDWP->winPos[i].x = winpos.x;
2482 pDWP->winPos[i].y = winpos.y;
2484 if (!(flags & SWP_NOSIZE))
2486 pDWP->winPos[i].cx = winpos.cx;
2487 pDWP->winPos[i].cy = winpos.cy;
2489 pDWP->winPos[i].flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2490 SWP_NOZORDER | SWP_NOREDRAW |
2491 SWP_NOACTIVATE | SWP_NOCOPYBITS|
2492 SWP_NOOWNERZORDER);
2493 pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2494 SWP_FRAMECHANGED);
2495 goto END;
2498 if (pDWP->actualCount >= pDWP->suggestedCount)
2500 WINDOWPOS *newpos = HeapReAlloc( GetProcessHeap(), 0, pDWP->winPos,
2501 pDWP->suggestedCount * 2 * sizeof(WINDOWPOS) );
2502 if (!newpos)
2504 retvalue = 0;
2505 goto END;
2507 pDWP->suggestedCount *= 2;
2508 pDWP->winPos = newpos;
2510 pDWP->winPos[pDWP->actualCount++] = winpos;
2511 END:
2512 release_user_handle_ptr( pDWP );
2513 return retvalue;
2517 /***********************************************************************
2518 * EndDeferWindowPos (USER32.@)
2520 BOOL WINAPI EndDeferWindowPos( HDWP hdwp )
2522 DWP *pDWP;
2523 WINDOWPOS *winpos;
2524 int i;
2526 TRACE("%p\n", hdwp);
2528 if (!(pDWP = free_user_handle( hdwp, USER_DWP ))) return FALSE;
2529 if (pDWP == OBJ_OTHER_PROCESS)
2531 FIXME( "other process handle %p?\n", hdwp );
2532 return FALSE;
2535 for (i = 0, winpos = pDWP->winPos; i < pDWP->actualCount; i++, winpos++)
2537 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2538 winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
2539 winpos->cx, winpos->cy, winpos->flags);
2541 if (WIN_IsCurrentThread( winpos->hwnd ))
2542 USER_SetWindowPos( winpos, 0, 0 );
2543 else
2544 SendMessageW( winpos->hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)winpos );
2546 HeapFree( GetProcessHeap(), 0, pDWP->winPos );
2547 HeapFree( GetProcessHeap(), 0, pDWP );
2548 return TRUE;
2552 /***********************************************************************
2553 * ArrangeIconicWindows (USER32.@)
2555 UINT WINAPI ArrangeIconicWindows( HWND parent )
2557 int width, height, count = 0;
2558 RECT rectParent;
2559 HWND hwndChild;
2560 POINT pt;
2561 MINIMIZEDMETRICS metrics;
2563 metrics.cbSize = sizeof(metrics);
2564 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(metrics), &metrics, 0 );
2565 width = GetSystemMetrics( SM_CXMINIMIZED );
2566 height = GetSystemMetrics( SM_CYMINIMIZED );
2568 if (parent == GetDesktopWindow())
2570 MONITORINFO mon_info;
2571 HMONITOR monitor = MonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY );
2573 mon_info.cbSize = sizeof( mon_info );
2574 GetMonitorInfoW( monitor, &mon_info );
2575 rectParent = mon_info.rcWork;
2577 else GetClientRect( parent, &rectParent );
2579 pt = get_first_minimized_child_pos( &rectParent, &metrics, width, height );
2581 hwndChild = GetWindow( parent, GW_CHILD );
2582 while (hwndChild)
2584 if( IsIconic( hwndChild ) )
2586 SetWindowPos( hwndChild, 0, pt.x, pt.y, 0, 0,
2587 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
2588 get_next_minimized_child_pos( &rectParent, &metrics, width, height, &pt );
2589 count++;
2591 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
2593 return count;
2597 /***********************************************************************
2598 * draw_moving_frame
2600 * Draw the frame used when moving or resizing window.
2602 static void draw_moving_frame( HWND parent, HDC hdc, RECT *screen_rect, BOOL thickframe )
2604 RECT rect = *screen_rect;
2606 if (parent) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
2607 if (thickframe)
2609 const int width = GetSystemMetrics(SM_CXFRAME);
2610 const int height = GetSystemMetrics(SM_CYFRAME);
2612 HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
2613 PatBlt( hdc, rect.left, rect.top,
2614 rect.right - rect.left - width, height, PATINVERT );
2615 PatBlt( hdc, rect.left, rect.top + height, width,
2616 rect.bottom - rect.top - height, PATINVERT );
2617 PatBlt( hdc, rect.left + width, rect.bottom - 1,
2618 rect.right - rect.left - width, -height, PATINVERT );
2619 PatBlt( hdc, rect.right - 1, rect.top, -width,
2620 rect.bottom - rect.top - height, PATINVERT );
2621 SelectObject( hdc, hbrush );
2623 else DrawFocusRect( hdc, &rect );
2627 /***********************************************************************
2628 * start_size_move
2630 * Initialization of a move or resize, when initiated from a menu choice.
2631 * Return hit test code for caption or sizing border.
2633 static LONG start_size_move( HWND hwnd, WPARAM wParam, POINT *capturePoint, LONG style )
2635 LONG hittest = 0;
2636 POINT pt;
2637 MSG msg;
2638 RECT rectWindow;
2640 GetWindowRect( hwnd, &rectWindow );
2642 if ((wParam & 0xfff0) == SC_MOVE)
2644 /* Move pointer at the center of the caption */
2645 RECT rect = rectWindow;
2646 /* Note: to be exactly centered we should take the different types
2647 * of border into account, but it shouldn't make more than a few pixels
2648 * of difference so let's not bother with that */
2649 rect.top += GetSystemMetrics(SM_CYBORDER);
2650 if (style & WS_SYSMENU)
2651 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
2652 if (style & WS_MINIMIZEBOX)
2653 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
2654 if (style & WS_MAXIMIZEBOX)
2655 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
2656 pt.x = (rect.right + rect.left) / 2;
2657 pt.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
2658 hittest = HTCAPTION;
2659 *capturePoint = pt;
2661 else /* SC_SIZE */
2663 SetCursor( LoadCursorW( 0, (LPWSTR)IDC_SIZEALL ) );
2664 pt.x = pt.y = 0;
2665 while(!hittest)
2667 if (!GetMessageW( &msg, 0, 0, 0 )) return 0;
2668 if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
2670 switch(msg.message)
2672 case WM_MOUSEMOVE:
2673 pt.x = min( max( msg.pt.x, rectWindow.left ), rectWindow.right - 1 );
2674 pt.y = min( max( msg.pt.y, rectWindow.top ), rectWindow.bottom - 1 );
2675 hittest = SendMessageW( hwnd, WM_NCHITTEST, 0, MAKELONG( pt.x, pt.y ) );
2676 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) hittest = 0;
2677 break;
2679 case WM_LBUTTONUP:
2680 return 0;
2682 case WM_KEYDOWN:
2683 switch(msg.wParam)
2685 case VK_UP:
2686 hittest = HTTOP;
2687 pt.x =(rectWindow.left+rectWindow.right)/2;
2688 pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
2689 break;
2690 case VK_DOWN:
2691 hittest = HTBOTTOM;
2692 pt.x =(rectWindow.left+rectWindow.right)/2;
2693 pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
2694 break;
2695 case VK_LEFT:
2696 hittest = HTLEFT;
2697 pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
2698 pt.y =(rectWindow.top+rectWindow.bottom)/2;
2699 break;
2700 case VK_RIGHT:
2701 hittest = HTRIGHT;
2702 pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
2703 pt.y =(rectWindow.top+rectWindow.bottom)/2;
2704 break;
2705 case VK_RETURN:
2706 case VK_ESCAPE:
2707 return 0;
2709 break;
2710 default:
2711 TranslateMessage( &msg );
2712 DispatchMessageW( &msg );
2713 break;
2716 *capturePoint = pt;
2718 SetCursorPos( pt.x, pt.y );
2719 SendMessageW( hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
2720 return hittest;
2724 /***********************************************************************
2725 * WINPOS_SysCommandSizeMove
2727 * Perform SC_MOVE and SC_SIZE commands.
2729 void WINPOS_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
2731 MSG msg;
2732 RECT sizingRect, mouseRect, origRect;
2733 HDC hdc;
2734 HWND parent;
2735 LONG hittest = (LONG)(wParam & 0x0f);
2736 WPARAM syscommand = wParam & 0xfff0;
2737 MINMAXINFO minmax;
2738 POINT capturePoint, pt;
2739 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2740 BOOL thickframe = HAS_THICKFRAME( style );
2741 BOOL moved = FALSE;
2742 DWORD dwPoint = GetMessagePos ();
2743 BOOL DragFullWindows = TRUE;
2744 HMONITOR mon = 0;
2746 if (IsZoomed(hwnd) || !IsWindowVisible(hwnd)) return;
2748 pt.x = (short)LOWORD(dwPoint);
2749 pt.y = (short)HIWORD(dwPoint);
2750 capturePoint = pt;
2751 ClipCursor( NULL );
2753 TRACE("hwnd %p command %04lx, hittest %d, pos %d,%d\n",
2754 hwnd, syscommand, hittest, pt.x, pt.y);
2756 if (syscommand == SC_MOVE)
2758 if (!hittest) hittest = start_size_move( hwnd, wParam, &capturePoint, style );
2759 if (!hittest) return;
2761 else /* SC_SIZE */
2763 if ( hittest && (syscommand != SC_MOUSEMENU) )
2764 hittest += (HTLEFT - WMSZ_LEFT);
2765 else
2767 set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
2768 hittest = start_size_move( hwnd, wParam, &capturePoint, style );
2769 if (!hittest)
2771 set_capture_window( 0, GUI_INMOVESIZE, NULL );
2772 return;
2777 /* Get min/max info */
2779 minmax = WINPOS_GetMinMaxInfo( hwnd );
2780 WIN_GetRectangles( hwnd, COORDS_PARENT, &sizingRect, NULL );
2781 origRect = sizingRect;
2782 if (style & WS_CHILD)
2784 parent = GetParent(hwnd);
2785 GetClientRect( parent, &mouseRect );
2786 MapWindowPoints( parent, 0, (LPPOINT)&mouseRect, 2 );
2787 MapWindowPoints( parent, 0, (LPPOINT)&sizingRect, 2 );
2789 else
2791 parent = 0;
2792 mouseRect = get_virtual_screen_rect();
2793 mon = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
2796 if (ON_LEFT_BORDER(hittest))
2798 mouseRect.left = max( mouseRect.left, sizingRect.right-minmax.ptMaxTrackSize.x+capturePoint.x-sizingRect.left );
2799 mouseRect.right = min( mouseRect.right, sizingRect.right-minmax.ptMinTrackSize.x+capturePoint.x-sizingRect.left );
2801 else if (ON_RIGHT_BORDER(hittest))
2803 mouseRect.left = max( mouseRect.left, sizingRect.left+minmax.ptMinTrackSize.x+capturePoint.x-sizingRect.right );
2804 mouseRect.right = min( mouseRect.right, sizingRect.left+minmax.ptMaxTrackSize.x+capturePoint.x-sizingRect.right );
2806 if (ON_TOP_BORDER(hittest))
2808 mouseRect.top = max( mouseRect.top, sizingRect.bottom-minmax.ptMaxTrackSize.y+capturePoint.y-sizingRect.top );
2809 mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minmax.ptMinTrackSize.y+capturePoint.y-sizingRect.top);
2811 else if (ON_BOTTOM_BORDER(hittest))
2813 mouseRect.top = max( mouseRect.top, sizingRect.top+minmax.ptMinTrackSize.y+capturePoint.y-sizingRect.bottom );
2814 mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+minmax.ptMaxTrackSize.y+capturePoint.y-sizingRect.bottom );
2817 /* Retrieve a default cache DC (without using the window style) */
2818 hdc = GetDCEx( parent, 0, DCX_CACHE );
2820 /* we only allow disabling the full window drag for child windows */
2821 if (parent) SystemParametersInfoW( SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0 );
2823 /* repaint the window before moving it around */
2824 RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
2826 SendMessageW( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
2827 set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
2829 while(1)
2831 int dx = 0, dy = 0;
2833 if (!GetMessageW( &msg, 0, 0, 0 )) break;
2834 if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
2836 /* Exit on button-up, Return, or Esc */
2837 if ((msg.message == WM_LBUTTONUP) ||
2838 ((msg.message == WM_KEYDOWN) &&
2839 ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
2841 if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
2843 TranslateMessage( &msg );
2844 DispatchMessageW( &msg );
2845 continue; /* We are not interested in other messages */
2848 pt = msg.pt;
2850 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
2852 case VK_UP: pt.y -= 8; break;
2853 case VK_DOWN: pt.y += 8; break;
2854 case VK_LEFT: pt.x -= 8; break;
2855 case VK_RIGHT: pt.x += 8; break;
2858 pt.x = max( pt.x, mouseRect.left );
2859 pt.x = min( pt.x, mouseRect.right - 1 );
2860 pt.y = max( pt.y, mouseRect.top );
2861 pt.y = min( pt.y, mouseRect.bottom - 1 );
2863 if (!parent)
2865 HMONITOR newmon;
2866 MONITORINFO info;
2868 if ((newmon = MonitorFromPoint( pt, MONITOR_DEFAULTTONULL )))
2869 mon = newmon;
2871 info.cbSize = sizeof(info);
2872 if (mon && GetMonitorInfoW( mon, &info ))
2874 pt.x = max( pt.x, info.rcWork.left );
2875 pt.x = min( pt.x, info.rcWork.right - 1 );
2876 pt.y = max( pt.y, info.rcWork.top );
2877 pt.y = min( pt.y, info.rcWork.bottom - 1 );
2881 dx = pt.x - capturePoint.x;
2882 dy = pt.y - capturePoint.y;
2884 if (dx || dy)
2886 if( !moved )
2888 moved = TRUE;
2889 if (!DragFullWindows)
2890 draw_moving_frame( parent, hdc, &sizingRect, thickframe );
2893 if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
2894 else
2896 if (!DragFullWindows) draw_moving_frame( parent, hdc, &sizingRect, thickframe );
2897 if (hittest == HTCAPTION || hittest == HTBORDER) OffsetRect( &sizingRect, dx, dy );
2898 if (ON_LEFT_BORDER(hittest)) sizingRect.left += dx;
2899 else if (ON_RIGHT_BORDER(hittest)) sizingRect.right += dx;
2900 if (ON_TOP_BORDER(hittest)) sizingRect.top += dy;
2901 else if (ON_BOTTOM_BORDER(hittest)) sizingRect.bottom += dy;
2902 capturePoint = pt;
2904 /* determine the hit location */
2905 if (syscommand == SC_SIZE && hittest != HTBORDER)
2907 WPARAM wpSizingHit = 0;
2909 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
2910 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
2911 SendMessageW( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&sizingRect );
2913 else
2914 SendMessageW( hwnd, WM_MOVING, 0, (LPARAM)&sizingRect );
2916 if (!DragFullWindows)
2917 draw_moving_frame( parent, hdc, &sizingRect, thickframe );
2918 else
2920 RECT rect = sizingRect;
2921 MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
2922 SetWindowPos( hwnd, 0, rect.left, rect.top,
2923 rect.right - rect.left, rect.bottom - rect.top,
2924 (hittest == HTCAPTION) ? SWP_NOSIZE : 0 );
2930 if (moved && !DragFullWindows)
2932 draw_moving_frame( parent, hdc, &sizingRect, thickframe );
2935 set_capture_window( 0, GUI_INMOVESIZE, NULL );
2936 ReleaseDC( parent, hdc );
2937 if (parent) MapWindowPoints( 0, parent, (POINT *)&sizingRect, 2 );
2939 if (HOOK_CallHooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect, TRUE ))
2940 moved = FALSE;
2942 SendMessageW( hwnd, WM_EXITSIZEMOVE, 0, 0 );
2943 SendMessageW( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
2945 /* window moved or resized */
2946 if (moved)
2948 /* if the moving/resizing isn't canceled call SetWindowPos
2949 * with the new position or the new size of the window
2951 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
2953 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
2954 if (!DragFullWindows)
2955 SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
2956 sizingRect.right - sizingRect.left,
2957 sizingRect.bottom - sizingRect.top,
2958 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
2960 else
2961 { /* restore previous size/position */
2962 if(DragFullWindows)
2963 SetWindowPos( hwnd, 0, origRect.left, origRect.top,
2964 origRect.right - origRect.left,
2965 origRect.bottom - origRect.top,
2966 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
2970 if (IsIconic(hwnd))
2972 /* Single click brings up the system menu when iconized */
2974 if( !moved )
2976 if(style & WS_SYSMENU )
2977 SendMessageW( hwnd, WM_SYSCOMMAND,
2978 SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));