user32: Add wsprintfW %C tests.
[wine.git] / dlls / user32 / winpos.c
blobb92a20df18ba820dcbc0e3d55d6171dbf76252e6
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 "config.h"
23 #include "wine/port.h"
25 #include <stdarg.h>
26 #include <string.h>
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winerror.h"
33 #include "wine/server.h"
34 #include "controls.h"
35 #include "user_private.h"
36 #include "wine/gdi_driver.h"
37 #include "win.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(win);
42 #define SWP_AGG_NOGEOMETRYCHANGE \
43 (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER)
44 #define SWP_AGG_NOPOSCHANGE \
45 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
46 #define SWP_AGG_STATUSFLAGS \
47 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
48 #define SWP_AGG_NOCLIENTCHANGE \
49 (SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
51 #define HAS_DLGFRAME(style,exStyle) \
52 (((exStyle) & WS_EX_DLGMODALFRAME) || \
53 (((style) & WS_DLGFRAME) && !((style) & WS_BORDER)))
55 #define HAS_THICKFRAME(style) \
56 (((style) & WS_THICKFRAME) && \
57 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
59 #define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1)
61 #define ON_LEFT_BORDER(hit) \
62 (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
63 #define ON_RIGHT_BORDER(hit) \
64 (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
65 #define ON_TOP_BORDER(hit) \
66 (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
67 #define ON_BOTTOM_BORDER(hit) \
68 (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
70 #define PLACE_MIN 0x0001
71 #define PLACE_MAX 0x0002
72 #define PLACE_RECT 0x0004
74 typedef struct
76 struct user_object obj;
77 INT actualCount;
78 INT suggestedCount;
79 HWND hwndParent;
80 WINDOWPOS *winPos;
81 } DWP;
84 /***********************************************************************
85 * SwitchToThisWindow (USER32.@)
87 void WINAPI SwitchToThisWindow( HWND hwnd, BOOL alt_tab )
89 if (IsIconic( hwnd )) ShowWindow( hwnd, SW_RESTORE );
90 else BringWindowToTop( hwnd );
94 /***********************************************************************
95 * GetWindowRect (USER32.@)
97 BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect )
99 BOOL ret = WIN_GetRectangles( hwnd, COORDS_SCREEN, rect, NULL );
100 if (ret) TRACE( "hwnd %p %s\n", hwnd, wine_dbgstr_rect(rect) );
101 return ret;
105 /***********************************************************************
106 * GetWindowRgn (USER32.@)
108 int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn )
110 int nRet = ERROR;
111 NTSTATUS status;
112 HRGN win_rgn = 0;
113 RGNDATA *data;
114 size_t size = 256;
118 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 )))
120 SetLastError( ERROR_OUTOFMEMORY );
121 return ERROR;
123 SERVER_START_REQ( get_window_region )
125 req->window = wine_server_user_handle( hwnd );
126 wine_server_set_reply( req, data->Buffer, size );
127 if (!(status = wine_server_call( req )))
129 size_t reply_size = wine_server_reply_size( reply );
130 if (reply_size)
132 data->rdh.dwSize = sizeof(data->rdh);
133 data->rdh.iType = RDH_RECTANGLES;
134 data->rdh.nCount = reply_size / sizeof(RECT);
135 data->rdh.nRgnSize = reply_size;
136 win_rgn = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
139 else size = reply->total_size;
141 SERVER_END_REQ;
142 HeapFree( GetProcessHeap(), 0, data );
143 } while (status == STATUS_BUFFER_OVERFLOW);
145 if (status) SetLastError( RtlNtStatusToDosError(status) );
146 else if (win_rgn)
148 nRet = CombineRgn( hrgn, win_rgn, 0, RGN_COPY );
149 DeleteObject( win_rgn );
151 return nRet;
154 /***********************************************************************
155 * GetWindowRgnBox (USER32.@)
157 int WINAPI GetWindowRgnBox( HWND hwnd, LPRECT prect )
159 int ret = ERROR;
160 HRGN hrgn;
162 if (!prect)
163 return ERROR;
165 if ((hrgn = CreateRectRgn(0, 0, 0, 0)))
167 if ((ret = GetWindowRgn( hwnd, hrgn )) != ERROR )
168 ret = GetRgnBox( hrgn, prect );
169 DeleteObject(hrgn);
172 return ret;
175 /***********************************************************************
176 * SetWindowRgn (USER32.@)
178 int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw )
180 static const RECT empty_rect;
181 BOOL ret;
183 if (hrgn)
185 RGNDATA *data;
186 DWORD size;
188 if (!(size = GetRegionData( hrgn, 0, NULL ))) return FALSE;
189 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
190 if (!GetRegionData( hrgn, size, data ))
192 HeapFree( GetProcessHeap(), 0, data );
193 return FALSE;
195 SERVER_START_REQ( set_window_region )
197 req->window = wine_server_user_handle( hwnd );
198 req->redraw = (bRedraw != 0);
199 if (data->rdh.nCount)
200 wine_server_add_data( req, data->Buffer, data->rdh.nCount * sizeof(RECT) );
201 else
202 wine_server_add_data( req, &empty_rect, sizeof(empty_rect) );
203 ret = !wine_server_call_err( req );
205 SERVER_END_REQ;
206 HeapFree( GetProcessHeap(), 0, data );
208 else /* clear existing region */
210 SERVER_START_REQ( set_window_region )
212 req->window = wine_server_user_handle( hwnd );
213 req->redraw = (bRedraw != 0);
214 ret = !wine_server_call_err( req );
216 SERVER_END_REQ;
219 if (ret)
221 UINT swp_flags = SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE;
222 if (!bRedraw) swp_flags |= SWP_NOREDRAW;
223 SetWindowPos( hwnd, 0, 0, 0, 0, 0, swp_flags );
224 USER_Driver->pSetWindowRgn( hwnd, hrgn, bRedraw );
225 if (hrgn) DeleteObject( hrgn );
227 return ret;
231 /***********************************************************************
232 * GetClientRect (USER32.@)
234 BOOL WINAPI GetClientRect( HWND hwnd, LPRECT rect )
236 return WIN_GetRectangles( hwnd, COORDS_CLIENT, NULL, rect );
240 /***********************************************************************
241 * list_children_from_point
243 * Get the list of children that can contain point from the server.
244 * Point is in screen coordinates.
245 * Returned list must be freed by caller.
247 static HWND *list_children_from_point( HWND hwnd, POINT pt )
249 HWND *list;
250 int i, size = 128;
252 for (;;)
254 int count = 0;
256 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
258 SERVER_START_REQ( get_window_children_from_point )
260 req->parent = wine_server_user_handle( hwnd );
261 req->x = pt.x;
262 req->y = pt.y;
263 req->dpi = get_thread_dpi();
264 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
265 if (!wine_server_call( req )) count = reply->count;
267 SERVER_END_REQ;
268 if (count && count < size)
270 /* start from the end since HWND is potentially larger than user_handle_t */
271 for (i = count - 1; i >= 0; i--)
272 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
273 list[count] = 0;
274 return list;
276 HeapFree( GetProcessHeap(), 0, list );
277 if (!count) break;
278 size = count + 1; /* restart with a large enough buffer */
280 return NULL;
284 /***********************************************************************
285 * WINPOS_WindowFromPoint
287 * Find the window and hittest for a given point.
289 HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
291 int i, res;
292 HWND ret, *list;
293 POINT win_pt;
295 if (!hwndScope) hwndScope = GetDesktopWindow();
297 *hittest = HTNOWHERE;
299 if (!(list = list_children_from_point( hwndScope, pt ))) return 0;
301 /* now determine the hittest */
303 for (i = 0; list[i]; i++)
305 LONG style = GetWindowLongW( list[i], GWL_STYLE );
307 /* If window is minimized or disabled, return at once */
308 if (style & WS_DISABLED)
310 *hittest = HTERROR;
311 break;
313 /* Send WM_NCCHITTEST (if same thread) */
314 if (!WIN_IsCurrentThread( list[i] ))
316 *hittest = HTCLIENT;
317 break;
319 win_pt = point_thread_to_win_dpi( list[i], pt );
320 res = SendMessageW( list[i], WM_NCHITTEST, 0, MAKELPARAM( win_pt.x, win_pt.y ));
321 if (res != HTTRANSPARENT)
323 *hittest = res; /* Found the window */
324 break;
326 /* continue search with next window in z-order */
328 ret = list[i];
329 HeapFree( GetProcessHeap(), 0, list );
330 TRACE( "scope %p (%d,%d) returning %p\n", hwndScope, pt.x, pt.y, ret );
331 return ret;
335 /*******************************************************************
336 * WindowFromPoint (USER32.@)
338 HWND WINAPI WindowFromPoint( POINT pt )
340 INT hittest;
341 return WINPOS_WindowFromPoint( 0, pt, &hittest );
345 /*******************************************************************
346 * ChildWindowFromPoint (USER32.@)
348 HWND WINAPI ChildWindowFromPoint( HWND hwndParent, POINT pt )
350 return ChildWindowFromPointEx( hwndParent, pt, CWP_ALL );
353 /*******************************************************************
354 * RealChildWindowFromPoint (USER32.@)
356 HWND WINAPI RealChildWindowFromPoint( HWND hwndParent, POINT pt )
358 return ChildWindowFromPointEx( hwndParent, pt, CWP_SKIPTRANSPARENT | CWP_SKIPINVISIBLE );
361 /*******************************************************************
362 * ChildWindowFromPointEx (USER32.@)
364 HWND WINAPI ChildWindowFromPointEx( HWND hwndParent, POINT pt, UINT uFlags)
366 /* pt is in the client coordinates */
367 HWND *list;
368 int i;
369 RECT rect;
370 HWND retvalue;
372 GetClientRect( hwndParent, &rect );
373 if (!PtInRect( &rect, pt )) return 0;
374 if (!(list = WIN_ListChildren( hwndParent ))) return hwndParent;
376 for (i = 0; list[i]; i++)
378 if (!WIN_GetRectangles( list[i], COORDS_PARENT, &rect, NULL )) continue;
379 if (!PtInRect( &rect, pt )) continue;
380 if (uFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
382 LONG style = GetWindowLongW( list[i], GWL_STYLE );
383 if ((uFlags & CWP_SKIPINVISIBLE) && !(style & WS_VISIBLE)) continue;
384 if ((uFlags & CWP_SKIPDISABLED) && (style & WS_DISABLED)) continue;
386 if (uFlags & CWP_SKIPTRANSPARENT)
388 if (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TRANSPARENT) continue;
390 break;
392 retvalue = list[i];
393 HeapFree( GetProcessHeap(), 0, list );
394 if (!retvalue) retvalue = hwndParent;
395 return retvalue;
399 /*******************************************************************
400 * WINPOS_GetWinOffset
402 * Calculate the offset between the origin of the two windows. Used
403 * to implement MapWindowPoints.
405 static BOOL WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, BOOL *mirrored, POINT *ret_offset )
407 WND * wndPtr;
408 POINT offset;
409 BOOL mirror_from, mirror_to, ret;
410 HWND hwnd;
412 offset.x = offset.y = 0;
413 *mirrored = mirror_from = mirror_to = FALSE;
415 /* Translate source window origin to screen coords */
416 if (hwndFrom)
418 if (!(wndPtr = WIN_GetPtr( hwndFrom )))
420 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
421 return FALSE;
423 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
424 if (wndPtr != WND_DESKTOP)
426 if (wndPtr->dwExStyle & WS_EX_LAYOUTRTL)
428 mirror_from = TRUE;
429 offset.x += wndPtr->client_rect.right - wndPtr->client_rect.left;
431 while (wndPtr->parent)
433 offset.x += wndPtr->client_rect.left;
434 offset.y += wndPtr->client_rect.top;
435 hwnd = wndPtr->parent;
436 WIN_ReleasePtr( wndPtr );
437 if (!(wndPtr = WIN_GetPtr( hwnd ))) break;
438 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
439 if (wndPtr == WND_DESKTOP) break;
440 if (wndPtr->flags & WIN_CHILDREN_MOVED)
442 WIN_ReleasePtr( wndPtr );
443 goto other_process;
446 if (wndPtr && wndPtr != WND_DESKTOP) WIN_ReleasePtr( wndPtr );
447 offset = point_win_to_thread_dpi( hwndFrom, offset );
451 /* Translate origin to destination window coords */
452 if (hwndTo)
454 if (!(wndPtr = WIN_GetPtr( hwndTo )))
456 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
457 return FALSE;
459 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
460 if (wndPtr != WND_DESKTOP)
462 POINT pt = { 0, 0 };
463 if (wndPtr->dwExStyle & WS_EX_LAYOUTRTL)
465 mirror_to = TRUE;
466 pt.x += wndPtr->client_rect.right - wndPtr->client_rect.left;
468 while (wndPtr->parent)
470 pt.x += wndPtr->client_rect.left;
471 pt.y += wndPtr->client_rect.top;
472 hwnd = wndPtr->parent;
473 WIN_ReleasePtr( wndPtr );
474 if (!(wndPtr = WIN_GetPtr( hwnd ))) break;
475 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
476 if (wndPtr == WND_DESKTOP) break;
477 if (wndPtr->flags & WIN_CHILDREN_MOVED)
479 WIN_ReleasePtr( wndPtr );
480 goto other_process;
483 if (wndPtr && wndPtr != WND_DESKTOP) WIN_ReleasePtr( wndPtr );
484 pt = point_win_to_thread_dpi( hwndTo, pt );
485 offset.x -= pt.x;
486 offset.y -= pt.y;
490 *mirrored = mirror_from ^ mirror_to;
491 if (mirror_from) offset.x = -offset.x;
492 *ret_offset = offset;
493 return TRUE;
495 other_process: /* one of the parents may belong to another process, do it the hard way */
496 SERVER_START_REQ( get_windows_offset )
498 req->from = wine_server_user_handle( hwndFrom );
499 req->to = wine_server_user_handle( hwndTo );
500 req->dpi = get_thread_dpi();
501 if ((ret = !wine_server_call_err( req )))
503 ret_offset->x = reply->x;
504 ret_offset->y = reply->y;
505 *mirrored = reply->mirror;
508 SERVER_END_REQ;
509 return ret;
512 /* map coordinates of a window region */
513 void map_window_region( HWND from, HWND to, HRGN hrgn )
515 BOOL mirrored;
516 POINT offset;
517 UINT i, size;
518 RGNDATA *data;
519 HRGN new_rgn;
520 RECT *rect;
522 if (!WINPOS_GetWinOffset( from, to, &mirrored, &offset )) return;
524 if (!mirrored)
526 OffsetRgn( hrgn, offset.x, offset.y );
527 return;
529 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
530 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
531 GetRegionData( hrgn, size, data );
532 rect = (RECT *)data->Buffer;
533 for (i = 0; i < data->rdh.nCount; i++)
535 int tmp = -(rect[i].left + offset.x);
536 rect[i].left = -(rect[i].right + offset.x);
537 rect[i].right = tmp;
538 rect[i].top += offset.y;
539 rect[i].bottom += offset.y;
541 if ((new_rgn = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data )))
543 CombineRgn( hrgn, new_rgn, 0, RGN_COPY );
544 DeleteObject( new_rgn );
546 HeapFree( GetProcessHeap(), 0, data );
550 /*******************************************************************
551 * MapWindowPoints (USER32.@)
553 INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT count )
555 BOOL mirrored;
556 POINT offset;
557 UINT i;
559 if (!WINPOS_GetWinOffset( hwndFrom, hwndTo, &mirrored, &offset )) return 0;
561 for (i = 0; i < count; i++)
563 lppt[i].x += offset.x;
564 lppt[i].y += offset.y;
565 if (mirrored) lppt[i].x = -lppt[i].x;
567 if (mirrored && count == 2) /* special case for rectangle */
569 int tmp = lppt[0].x;
570 lppt[0].x = lppt[1].x;
571 lppt[1].x = tmp;
573 return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) );
577 /*******************************************************************
578 * ClientToScreen (USER32.@)
580 BOOL WINAPI ClientToScreen( HWND hwnd, LPPOINT lppnt )
582 POINT offset;
583 BOOL mirrored;
585 if (!hwnd)
587 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
588 return FALSE;
590 if (!WINPOS_GetWinOffset( hwnd, 0, &mirrored, &offset )) return FALSE;
591 lppnt->x += offset.x;
592 lppnt->y += offset.y;
593 if (mirrored) lppnt->x = -lppnt->x;
594 return TRUE;
598 /*******************************************************************
599 * ScreenToClient (USER32.@)
601 BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
603 POINT offset;
604 BOOL mirrored;
606 if (!hwnd)
608 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
609 return FALSE;
611 if (!WINPOS_GetWinOffset( 0, hwnd, &mirrored, &offset )) return FALSE;
612 lppnt->x += offset.x;
613 lppnt->y += offset.y;
614 if (mirrored) lppnt->x = -lppnt->x;
615 return TRUE;
619 /***********************************************************************
620 * IsIconic (USER32.@)
622 BOOL WINAPI IsIconic(HWND hWnd)
624 return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MINIMIZE) != 0;
628 /***********************************************************************
629 * IsZoomed (USER32.@)
631 BOOL WINAPI IsZoomed(HWND hWnd)
633 return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MAXIMIZE) != 0;
637 /*******************************************************************
638 * AllowSetForegroundWindow (USER32.@)
640 BOOL WINAPI AllowSetForegroundWindow( DWORD procid )
642 /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
643 * implemented, then fix this function. */
644 return TRUE;
648 /*******************************************************************
649 * LockSetForegroundWindow (USER32.@)
651 BOOL WINAPI LockSetForegroundWindow( UINT lockcode )
653 /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
654 * implemented, then fix this function. */
655 return TRUE;
659 /***********************************************************************
660 * BringWindowToTop (USER32.@)
662 BOOL WINAPI BringWindowToTop( HWND hwnd )
664 return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
668 /***********************************************************************
669 * MoveWindow (USER32.@)
671 BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
672 BOOL repaint )
674 int flags = SWP_NOZORDER | SWP_NOACTIVATE;
675 if (!repaint) flags |= SWP_NOREDRAW;
676 TRACE("%p %d,%d %dx%d %d\n", hwnd, x, y, cx, cy, repaint );
677 return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
681 /*******************************************************************
682 * WINPOS_GetMinMaxInfo
684 * Get the minimized and maximized information for a window.
686 MINMAXINFO WINPOS_GetMinMaxInfo( HWND hwnd )
688 DPI_AWARENESS_CONTEXT context;
689 MINMAXINFO MinMax;
690 HMONITOR monitor;
691 INT xinc, yinc;
692 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
693 LONG adjustedStyle;
694 LONG exstyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
695 RECT rc;
696 WND *win;
698 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
700 /* Compute default values */
702 GetWindowRect(hwnd, &rc);
703 MinMax.ptReserved.x = rc.left;
704 MinMax.ptReserved.y = rc.top;
706 if ((style & WS_CAPTION) == WS_CAPTION)
707 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
708 else
709 adjustedStyle = style;
711 GetClientRect(GetAncestor(hwnd,GA_PARENT), &rc);
712 AdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
714 xinc = -rc.left;
715 yinc = -rc.top;
717 MinMax.ptMaxSize.x = rc.right - rc.left;
718 MinMax.ptMaxSize.y = rc.bottom - rc.top;
719 if (style & (WS_DLGFRAME | WS_BORDER))
721 MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
722 MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
724 else
726 MinMax.ptMinTrackSize.x = 2 * xinc;
727 MinMax.ptMinTrackSize.y = 2 * yinc;
729 MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
730 MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
731 MinMax.ptMaxPosition.x = -xinc;
732 MinMax.ptMaxPosition.y = -yinc;
734 if ((win = WIN_GetPtr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS)
736 if (!EMPTYPOINT(win->max_pos)) MinMax.ptMaxPosition = win->max_pos;
737 WIN_ReleasePtr( win );
740 SendMessageW( hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
742 /* if the app didn't change the values, adapt them for the current monitor */
744 if ((monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY )))
746 RECT rc_work;
747 MONITORINFO mon_info;
749 mon_info.cbSize = sizeof(mon_info);
750 GetMonitorInfoW( monitor, &mon_info );
752 rc_work = mon_info.rcMonitor;
754 if (style & WS_MAXIMIZEBOX)
756 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
757 rc_work = mon_info.rcWork;
760 if (MinMax.ptMaxSize.x == GetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
761 MinMax.ptMaxSize.y == GetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
763 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
764 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
766 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
768 MinMax.ptMaxPosition.x = rc_work.left - xinc;
769 MinMax.ptMaxPosition.y = rc_work.top - yinc;
773 /* Some sanity checks */
775 TRACE("%d %d / %d %d / %d %d / %d %d\n",
776 MinMax.ptMaxSize.x, MinMax.ptMaxSize.y,
777 MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y,
778 MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y,
779 MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y);
780 MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x,
781 MinMax.ptMinTrackSize.x );
782 MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y,
783 MinMax.ptMinTrackSize.y );
785 SetThreadDpiAwarenessContext( context );
786 return MinMax;
789 static POINT get_first_minimized_child_pos( const RECT *parent, const MINIMIZEDMETRICS *mm,
790 int width, int height )
792 POINT ret;
794 if (mm->iArrange & ARW_STARTRIGHT)
795 ret.x = parent->right - mm->iHorzGap - width;
796 else
797 ret.x = parent->left + mm->iHorzGap;
798 if (mm->iArrange & ARW_STARTTOP)
799 ret.y = parent->top + mm->iVertGap;
800 else
801 ret.y = parent->bottom - mm->iVertGap - height;
803 return ret;
806 static void get_next_minimized_child_pos( const RECT *parent, const MINIMIZEDMETRICS *mm,
807 int width, int height, POINT *pos )
809 BOOL next;
811 if (mm->iArrange & ARW_UP) /* == ARW_DOWN */
813 if (mm->iArrange & ARW_STARTTOP)
815 pos->y += height + mm->iVertGap;
816 if ((next = pos->y + height > parent->bottom))
817 pos->y = parent->top + mm->iVertGap;
819 else
821 pos->y -= height + mm->iVertGap;
822 if ((next = pos->y < parent->top))
823 pos->y = parent->bottom - mm->iVertGap - height;
826 if (next)
828 if (mm->iArrange & ARW_STARTRIGHT)
829 pos->x -= width + mm->iHorzGap;
830 else
831 pos->x += width + mm->iHorzGap;
834 else
836 if (mm->iArrange & ARW_STARTRIGHT)
838 pos->x -= width + mm->iHorzGap;
839 if ((next = pos->x < parent->left))
840 pos->x = parent->right - mm->iHorzGap - width;
842 else
844 pos->x += width + mm->iHorzGap;
845 if ((next = pos->x + width > parent->right))
846 pos->x = parent->left + mm->iHorzGap;
849 if (next)
851 if (mm->iArrange & ARW_STARTTOP)
852 pos->y += height + mm->iVertGap;
853 else
854 pos->y -= height + mm->iVertGap;
859 static POINT get_minimized_pos( HWND hwnd, POINT pt )
861 RECT rect, rectParent;
862 HWND parent, child;
863 HRGN hrgn, tmp;
864 MINIMIZEDMETRICS metrics;
865 int width, height;
867 parent = GetAncestor( hwnd, GA_PARENT );
868 if (parent == GetDesktopWindow())
870 MONITORINFO mon_info;
871 HMONITOR monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY );
873 mon_info.cbSize = sizeof( mon_info );
874 GetMonitorInfoW( monitor, &mon_info );
875 rectParent = mon_info.rcWork;
877 else GetClientRect( parent, &rectParent );
879 if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics( SM_CXMINIMIZED ) < rectParent.right) &&
880 (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics( SM_CYMINIMIZED ) < rectParent.bottom))
881 return pt; /* The icon already has a suitable position */
883 width = GetSystemMetrics( SM_CXMINIMIZED );
884 height = GetSystemMetrics( SM_CYMINIMIZED );
886 metrics.cbSize = sizeof(metrics);
887 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(metrics), &metrics, 0 );
889 /* Check if another icon already occupies this spot */
890 /* FIXME: this is completely inefficient */
892 hrgn = CreateRectRgn( 0, 0, 0, 0 );
893 tmp = CreateRectRgn( 0, 0, 0, 0 );
894 for (child = GetWindow( parent, GW_CHILD ); child; child = GetWindow( child, GW_HWNDNEXT ))
896 if (child == hwnd) continue;
897 if ((GetWindowLongW( child, GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE))
898 continue;
899 if (WIN_GetRectangles( child, COORDS_PARENT, &rect, NULL ))
901 SetRectRgn( tmp, rect.left, rect.top, rect.right, rect.bottom );
902 CombineRgn( hrgn, hrgn, tmp, RGN_OR );
905 DeleteObject( tmp );
907 pt = get_first_minimized_child_pos( &rectParent, &metrics, width, height );
908 for (;;)
910 SetRect( &rect, pt.x, pt.y, pt.x + width, pt.y + height );
911 if (!RectInRegion( hrgn, &rect ))
912 break;
914 get_next_minimized_child_pos( &rectParent, &metrics, width, height, &pt );
917 DeleteObject( hrgn );
918 return pt;
922 /***********************************************************************
923 * WINPOS_MinMaximize
925 UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
927 UINT swpFlags = 0;
928 LONG old_style;
929 MINMAXINFO minmax;
930 WINDOWPLACEMENT wpl;
932 TRACE("%p %u\n", hwnd, cmd );
934 wpl.length = sizeof(wpl);
935 GetWindowPlacement( hwnd, &wpl );
937 if (HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd, TRUE ))
938 return SWP_NOSIZE | SWP_NOMOVE;
940 if (IsIconic( hwnd ))
942 switch (cmd)
944 case SW_SHOWMINNOACTIVE:
945 case SW_SHOWMINIMIZED:
946 case SW_FORCEMINIMIZE:
947 case SW_MINIMIZE:
948 wpl.ptMinPosition = get_minimized_pos( hwnd, wpl.ptMinPosition );
950 SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
951 wpl.ptMinPosition.x + GetSystemMetrics(SM_CXMINIMIZED),
952 wpl.ptMinPosition.y + GetSystemMetrics(SM_CYMINIMIZED) );
953 return SWP_NOSIZE | SWP_NOMOVE;
955 if (!SendMessageW( hwnd, WM_QUERYOPEN, 0, 0 )) return SWP_NOSIZE | SWP_NOMOVE;
956 swpFlags |= SWP_NOCOPYBITS;
959 switch( cmd )
961 case SW_SHOWMINNOACTIVE:
962 case SW_SHOWMINIMIZED:
963 case SW_FORCEMINIMIZE:
964 case SW_MINIMIZE:
965 if (IsZoomed( hwnd )) win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
966 else win_set_flags( hwnd, 0, WIN_RESTORE_MAX );
968 if (GetFocus() == hwnd)
970 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_CHILD)
971 SetFocus(GetAncestor(hwnd, GA_PARENT));
972 else
973 SetFocus(0);
976 old_style = WIN_SetStyle( hwnd, WS_MINIMIZE, WS_MAXIMIZE );
978 wpl.ptMinPosition = get_minimized_pos( hwnd, wpl.ptMinPosition );
980 if (!(old_style & WS_MINIMIZE)) swpFlags |= SWP_STATECHANGED;
981 SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
982 wpl.ptMinPosition.x + GetSystemMetrics(SM_CXMINIMIZED),
983 wpl.ptMinPosition.y + GetSystemMetrics(SM_CYMINIMIZED) );
984 swpFlags |= SWP_NOCOPYBITS;
985 break;
987 case SW_MAXIMIZE:
988 old_style = GetWindowLongW( hwnd, GWL_STYLE );
989 if ((old_style & WS_MAXIMIZE) && (old_style & WS_VISIBLE)) return SWP_NOSIZE | SWP_NOMOVE;
991 minmax = WINPOS_GetMinMaxInfo( hwnd );
993 old_style = WIN_SetStyle( hwnd, WS_MAXIMIZE, WS_MINIMIZE );
994 if (old_style & WS_MINIMIZE)
995 win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
997 if (!(old_style & WS_MAXIMIZE)) swpFlags |= SWP_STATECHANGED;
998 SetRect( rect, minmax.ptMaxPosition.x, minmax.ptMaxPosition.y,
999 minmax.ptMaxPosition.x + minmax.ptMaxSize.x, minmax.ptMaxPosition.y + minmax.ptMaxSize.y );
1000 break;
1002 case SW_SHOWNOACTIVATE:
1003 win_set_flags( hwnd, 0, WIN_RESTORE_MAX );
1004 /* fall through */
1005 case SW_SHOWNORMAL:
1006 case SW_RESTORE:
1007 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1008 old_style = WIN_SetStyle( hwnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
1009 if (old_style & WS_MINIMIZE)
1011 if (win_get_flags( hwnd ) & WIN_RESTORE_MAX)
1013 /* Restore to maximized position */
1014 minmax = WINPOS_GetMinMaxInfo( hwnd );
1015 WIN_SetStyle( hwnd, WS_MAXIMIZE, 0 );
1016 swpFlags |= SWP_STATECHANGED;
1017 SetRect( rect, minmax.ptMaxPosition.x, minmax.ptMaxPosition.y,
1018 minmax.ptMaxPosition.x + minmax.ptMaxSize.x, minmax.ptMaxPosition.y + minmax.ptMaxSize.y );
1019 break;
1022 else if (!(old_style & WS_MAXIMIZE)) break;
1024 swpFlags |= SWP_STATECHANGED;
1026 /* Restore to normal position */
1028 *rect = wpl.rcNormalPosition;
1029 break;
1032 return swpFlags;
1036 /***********************************************************************
1037 * show_window
1039 * Implementation of ShowWindow and ShowWindowAsync.
1041 static BOOL show_window( HWND hwnd, INT cmd )
1043 WND *wndPtr;
1044 HWND parent;
1045 DPI_AWARENESS_CONTEXT context;
1046 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1047 BOOL wasVisible = (style & WS_VISIBLE) != 0;
1048 BOOL showFlag = TRUE;
1049 RECT newPos = {0, 0, 0, 0};
1050 UINT swp = 0;
1052 TRACE("hwnd=%p, cmd=%d, wasVisible %d\n", hwnd, cmd, wasVisible);
1054 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
1056 switch(cmd)
1058 case SW_HIDE:
1059 if (!wasVisible) goto done;
1060 showFlag = FALSE;
1061 swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1062 if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1063 break;
1065 case SW_SHOWMINNOACTIVE:
1066 case SW_MINIMIZE:
1067 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
1068 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1069 /* fall through */
1070 case SW_SHOWMINIMIZED:
1071 swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1072 swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
1073 if ((style & WS_MINIMIZE) && wasVisible) goto done;
1074 break;
1076 case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
1077 if (!wasVisible) swp |= SWP_SHOWWINDOW;
1078 swp |= SWP_FRAMECHANGED;
1079 swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
1080 if ((style & WS_MAXIMIZE) && wasVisible) goto done;
1081 break;
1083 case SW_SHOWNA:
1084 swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1085 if (style & WS_CHILD) swp |= SWP_NOZORDER;
1086 break;
1087 case SW_SHOW:
1088 if (wasVisible) goto done;
1089 swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1090 if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1091 break;
1093 case SW_SHOWNOACTIVATE:
1094 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1095 /* fall through */
1096 case SW_RESTORE:
1097 /* fall through */
1098 case SW_SHOWNORMAL: /* same as SW_NORMAL: */
1099 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1100 if (!wasVisible) swp |= SWP_SHOWWINDOW;
1101 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1103 swp |= SWP_FRAMECHANGED;
1104 swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
1106 else
1108 if (wasVisible) goto done;
1109 swp |= SWP_NOSIZE | SWP_NOMOVE;
1111 if (style & WS_CHILD && !(swp & SWP_STATECHANGED)) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1112 break;
1113 default:
1114 goto done;
1117 if ((showFlag != wasVisible || cmd == SW_SHOWNA) && cmd != SW_SHOWMAXIMIZED && !(swp & SWP_STATECHANGED))
1119 SendMessageW( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1120 if (!IsWindow( hwnd )) goto done;
1123 swp = USER_Driver->pShowWindow( hwnd, cmd, &newPos, swp );
1125 parent = GetAncestor( hwnd, GA_PARENT );
1126 if (parent && !IsWindowVisible( parent ) && !(swp & SWP_STATECHANGED))
1128 /* if parent is not visible simply toggle WS_VISIBLE and return */
1129 if (showFlag) WIN_SetStyle( hwnd, WS_VISIBLE, 0 );
1130 else WIN_SetStyle( hwnd, 0, WS_VISIBLE );
1132 else
1133 SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
1134 newPos.right - newPos.left, newPos.bottom - newPos.top, swp );
1136 if (cmd == SW_HIDE)
1138 HWND hFocus;
1140 /* FIXME: This will cause the window to be activated irrespective
1141 * of whether it is owned by the same thread. Has to be done
1142 * asynchronously.
1145 if (hwnd == GetActiveWindow())
1146 WINPOS_ActivateOtherWindow(hwnd);
1148 /* Revert focus to parent */
1149 hFocus = GetFocus();
1150 if (hwnd == hFocus)
1152 HWND parent = GetAncestor(hwnd, GA_PARENT);
1153 if (parent == GetDesktopWindow()) parent = 0;
1154 SetFocus(parent);
1156 goto done;
1159 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) goto done;
1161 if (wndPtr->flags & WIN_NEED_SIZE)
1163 /* should happen only in CreateWindowEx() */
1164 int wParam = SIZE_RESTORED;
1165 RECT client;
1166 LPARAM lparam;
1168 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &client );
1169 lparam = MAKELONG( client.right - client.left, client.bottom - client.top );
1170 wndPtr->flags &= ~WIN_NEED_SIZE;
1171 if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
1172 else if (wndPtr->dwStyle & WS_MINIMIZE)
1174 wParam = SIZE_MINIMIZED;
1175 lparam = 0;
1177 WIN_ReleasePtr( wndPtr );
1179 SendMessageW( hwnd, WM_SIZE, wParam, lparam );
1180 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( client.left, client.top ));
1182 else WIN_ReleasePtr( wndPtr );
1184 /* if previous state was minimized Windows sets focus to the window */
1185 if (style & WS_MINIMIZE) SetFocus( hwnd );
1187 done:
1188 SetThreadDpiAwarenessContext( context );
1189 return wasVisible;
1193 /***********************************************************************
1194 * ShowWindowAsync (USER32.@)
1196 * doesn't wait; returns immediately.
1197 * used by threads to toggle windows in other (possibly hanging) threads
1199 BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd )
1201 HWND full_handle;
1203 if (is_broadcast(hwnd))
1205 SetLastError( ERROR_INVALID_PARAMETER );
1206 return FALSE;
1209 if ((full_handle = WIN_IsCurrentThread( hwnd )))
1210 return show_window( full_handle, cmd );
1212 return SendNotifyMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
1216 /***********************************************************************
1217 * ShowWindow (USER32.@)
1219 BOOL WINAPI ShowWindow( HWND hwnd, INT cmd )
1221 HWND full_handle;
1223 if (is_broadcast(hwnd))
1225 SetLastError( ERROR_INVALID_PARAMETER );
1226 return FALSE;
1228 if ((full_handle = WIN_IsCurrentThread( hwnd )))
1229 return show_window( full_handle, cmd );
1231 if ((cmd == SW_HIDE) && !(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
1232 return FALSE;
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) 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)
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));