msdasql/tests: Test for ITransaction* interfaces on a session.
[wine.git] / dlls / user32 / winpos.c
blobff23206b39587d029da80451c6feb66791c0f984
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 <string.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "user_private.h"
26 #include "winerror.h"
27 #include "controls.h"
28 #include "win.h"
29 #include "wine/server.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(win);
34 #define SWP_AGG_NOGEOMETRYCHANGE \
35 (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER)
36 #define SWP_AGG_NOPOSCHANGE \
37 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
38 #define SWP_AGG_STATUSFLAGS \
39 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
40 #define SWP_AGG_NOCLIENTCHANGE \
41 (SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
43 #define HAS_DLGFRAME(style,exStyle) \
44 (((exStyle) & WS_EX_DLGMODALFRAME) || \
45 (((style) & WS_DLGFRAME) && !((style) & WS_BORDER)))
47 #define HAS_THICKFRAME(style) \
48 (((style) & WS_THICKFRAME) && \
49 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
51 #define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1)
53 #define ON_LEFT_BORDER(hit) \
54 (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
55 #define ON_RIGHT_BORDER(hit) \
56 (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
57 #define ON_TOP_BORDER(hit) \
58 (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
59 #define ON_BOTTOM_BORDER(hit) \
60 (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
62 #define PLACE_MIN 0x0001
63 #define PLACE_MAX 0x0002
64 #define PLACE_RECT 0x0004
66 typedef struct
68 struct user_object obj;
69 INT actualCount;
70 INT suggestedCount;
71 HWND hwndParent;
72 WINDOWPOS *winPos;
73 } DWP;
76 /***********************************************************************
77 * SwitchToThisWindow (USER32.@)
79 void WINAPI SwitchToThisWindow( HWND hwnd, BOOL alt_tab )
81 if (IsIconic( hwnd )) ShowWindow( hwnd, SW_RESTORE );
82 else BringWindowToTop( hwnd );
86 /***********************************************************************
87 * GetWindowRect (USER32.@)
89 BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect )
91 BOOL ret = WIN_GetRectangles( hwnd, COORDS_SCREEN, rect, NULL );
92 if (ret) TRACE( "hwnd %p %s\n", hwnd, wine_dbgstr_rect(rect) );
93 return ret;
97 /***********************************************************************
98 * GetWindowRgn (USER32.@)
100 int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn )
102 int nRet = ERROR;
103 NTSTATUS status;
104 HRGN win_rgn = 0;
105 RGNDATA *data;
106 size_t size = 256;
110 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 )))
112 SetLastError( ERROR_OUTOFMEMORY );
113 return ERROR;
115 SERVER_START_REQ( get_window_region )
117 req->window = wine_server_user_handle( hwnd );
118 wine_server_set_reply( req, data->Buffer, size );
119 if (!(status = wine_server_call( req )))
121 size_t reply_size = wine_server_reply_size( reply );
122 if (reply_size)
124 data->rdh.dwSize = sizeof(data->rdh);
125 data->rdh.iType = RDH_RECTANGLES;
126 data->rdh.nCount = reply_size / sizeof(RECT);
127 data->rdh.nRgnSize = reply_size;
128 win_rgn = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
131 else size = reply->total_size;
133 SERVER_END_REQ;
134 HeapFree( GetProcessHeap(), 0, data );
135 } while (status == STATUS_BUFFER_OVERFLOW);
137 if (status) SetLastError( RtlNtStatusToDosError(status) );
138 else if (win_rgn)
140 nRet = CombineRgn( hrgn, win_rgn, 0, RGN_COPY );
141 DeleteObject( win_rgn );
143 return nRet;
146 /***********************************************************************
147 * GetWindowRgnBox (USER32.@)
149 int WINAPI GetWindowRgnBox( HWND hwnd, LPRECT prect )
151 int ret = ERROR;
152 HRGN hrgn;
154 if (!prect)
155 return ERROR;
157 if ((hrgn = CreateRectRgn(0, 0, 0, 0)))
159 if ((ret = GetWindowRgn( hwnd, hrgn )) != ERROR )
160 ret = GetRgnBox( hrgn, prect );
161 DeleteObject(hrgn);
164 return ret;
167 /***********************************************************************
168 * SetWindowRgn (USER32.@)
170 int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw )
172 static const RECT empty_rect;
173 BOOL ret;
175 if (hrgn)
177 RGNDATA *data;
178 DWORD size;
180 if (!(size = GetRegionData( hrgn, 0, NULL ))) return FALSE;
181 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
182 if (!GetRegionData( hrgn, size, data ))
184 HeapFree( GetProcessHeap(), 0, data );
185 return FALSE;
187 SERVER_START_REQ( set_window_region )
189 req->window = wine_server_user_handle( hwnd );
190 req->redraw = (bRedraw != 0);
191 if (data->rdh.nCount)
192 wine_server_add_data( req, data->Buffer, data->rdh.nCount * sizeof(RECT) );
193 else
194 wine_server_add_data( req, &empty_rect, sizeof(empty_rect) );
195 ret = !wine_server_call_err( req );
197 SERVER_END_REQ;
198 HeapFree( GetProcessHeap(), 0, data );
200 else /* clear existing region */
202 SERVER_START_REQ( set_window_region )
204 req->window = wine_server_user_handle( hwnd );
205 req->redraw = (bRedraw != 0);
206 ret = !wine_server_call_err( req );
208 SERVER_END_REQ;
211 if (ret)
213 UINT swp_flags = SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE;
214 if (!bRedraw) swp_flags |= SWP_NOREDRAW;
215 USER_Driver->pSetWindowRgn( hwnd, hrgn, bRedraw );
216 SetWindowPos( hwnd, 0, 0, 0, 0, 0, swp_flags );
217 if (hrgn) DeleteObject( hrgn );
219 return ret;
223 /***********************************************************************
224 * GetClientRect (USER32.@)
226 BOOL WINAPI GetClientRect( HWND hwnd, LPRECT rect )
228 return WIN_GetRectangles( hwnd, COORDS_CLIENT, NULL, rect );
232 /***********************************************************************
233 * list_children_from_point
235 * Get the list of children that can contain point from the server.
236 * Point is in screen coordinates.
237 * Returned list must be freed by caller.
239 static HWND *list_children_from_point( HWND hwnd, POINT pt )
241 HWND *list;
242 int i, size = 128;
244 for (;;)
246 int count = 0;
248 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
250 SERVER_START_REQ( get_window_children_from_point )
252 req->parent = wine_server_user_handle( hwnd );
253 req->x = pt.x;
254 req->y = pt.y;
255 req->dpi = get_thread_dpi();
256 wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) );
257 if (!wine_server_call( req )) count = reply->count;
259 SERVER_END_REQ;
260 if (count && count < size)
262 /* start from the end since HWND is potentially larger than user_handle_t */
263 for (i = count - 1; i >= 0; i--)
264 list[i] = wine_server_ptr_handle( ((user_handle_t *)list)[i] );
265 list[count] = 0;
266 return list;
268 HeapFree( GetProcessHeap(), 0, list );
269 if (!count) break;
270 size = count + 1; /* restart with a large enough buffer */
272 return NULL;
276 /***********************************************************************
277 * WINPOS_WindowFromPoint
279 * Find the window and hittest for a given point.
281 HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
283 int i, res;
284 HWND ret, *list;
285 POINT win_pt;
287 if (!hwndScope) hwndScope = GetDesktopWindow();
289 *hittest = HTNOWHERE;
291 if (!(list = list_children_from_point( hwndScope, pt ))) return 0;
293 /* now determine the hittest */
295 for (i = 0; list[i]; i++)
297 LONG style = GetWindowLongW( list[i], GWL_STYLE );
299 /* If window is minimized or disabled, return at once */
300 if (style & WS_DISABLED)
302 *hittest = HTERROR;
303 break;
305 /* Send WM_NCCHITTEST (if same thread) */
306 if (!WIN_IsCurrentThread( list[i] ))
308 *hittest = HTCLIENT;
309 break;
311 win_pt = point_thread_to_win_dpi( list[i], pt );
312 res = SendMessageW( list[i], WM_NCHITTEST, 0, MAKELPARAM( win_pt.x, win_pt.y ));
313 if (res != HTTRANSPARENT)
315 *hittest = res; /* Found the window */
316 break;
318 /* continue search with next window in z-order */
320 ret = list[i];
321 HeapFree( GetProcessHeap(), 0, list );
322 TRACE( "scope %p (%d,%d) returning %p\n", hwndScope, pt.x, pt.y, ret );
323 return ret;
327 /*******************************************************************
328 * WindowFromPoint (USER32.@)
330 HWND WINAPI WindowFromPoint( POINT pt )
332 INT hittest;
333 return WINPOS_WindowFromPoint( 0, pt, &hittest );
337 /*******************************************************************
338 * ChildWindowFromPoint (USER32.@)
340 HWND WINAPI ChildWindowFromPoint( HWND hwndParent, POINT pt )
342 return ChildWindowFromPointEx( hwndParent, pt, CWP_ALL );
345 /*******************************************************************
346 * RealChildWindowFromPoint (USER32.@)
348 HWND WINAPI RealChildWindowFromPoint( HWND hwndParent, POINT pt )
350 return ChildWindowFromPointEx( hwndParent, pt, CWP_SKIPTRANSPARENT | CWP_SKIPINVISIBLE );
353 /*******************************************************************
354 * ChildWindowFromPointEx (USER32.@)
356 HWND WINAPI ChildWindowFromPointEx( HWND hwndParent, POINT pt, UINT uFlags)
358 /* pt is in the client coordinates */
359 HWND *list;
360 int i;
361 RECT rect;
362 HWND retvalue;
364 GetClientRect( hwndParent, &rect );
365 if (!PtInRect( &rect, pt )) return 0;
366 if (!(list = WIN_ListChildren( hwndParent ))) return hwndParent;
368 for (i = 0; list[i]; i++)
370 if (!WIN_GetRectangles( list[i], COORDS_PARENT, &rect, NULL )) continue;
371 if (!PtInRect( &rect, pt )) continue;
372 if (uFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
374 LONG style = GetWindowLongW( list[i], GWL_STYLE );
375 if ((uFlags & CWP_SKIPINVISIBLE) && !(style & WS_VISIBLE)) continue;
376 if ((uFlags & CWP_SKIPDISABLED) && (style & WS_DISABLED)) continue;
378 if (uFlags & CWP_SKIPTRANSPARENT)
380 if (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TRANSPARENT) continue;
382 break;
384 retvalue = list[i];
385 HeapFree( GetProcessHeap(), 0, list );
386 if (!retvalue) retvalue = hwndParent;
387 return retvalue;
391 /*******************************************************************
392 * WINPOS_GetWinOffset
394 * Calculate the offset between the origin of the two windows. Used
395 * to implement MapWindowPoints.
397 static BOOL WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, BOOL *mirrored, POINT *ret_offset )
399 WND * wndPtr;
400 POINT offset;
401 BOOL mirror_from, mirror_to, ret;
402 HWND hwnd;
404 offset.x = offset.y = 0;
405 *mirrored = mirror_from = mirror_to = FALSE;
407 /* Translate source window origin to screen coords */
408 if (hwndFrom)
410 if (!(wndPtr = WIN_GetPtr( hwndFrom )))
412 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
413 return FALSE;
415 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
416 if (wndPtr != WND_DESKTOP)
418 if (wndPtr->dwExStyle & WS_EX_LAYOUTRTL)
420 mirror_from = TRUE;
421 offset.x += wndPtr->client_rect.right - wndPtr->client_rect.left;
423 while (wndPtr->parent)
425 offset.x += wndPtr->client_rect.left;
426 offset.y += wndPtr->client_rect.top;
427 hwnd = wndPtr->parent;
428 WIN_ReleasePtr( wndPtr );
429 if (!(wndPtr = WIN_GetPtr( hwnd ))) break;
430 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
431 if (wndPtr == WND_DESKTOP) break;
432 if (wndPtr->flags & WIN_CHILDREN_MOVED)
434 WIN_ReleasePtr( wndPtr );
435 goto other_process;
438 if (wndPtr && wndPtr != WND_DESKTOP) WIN_ReleasePtr( wndPtr );
439 offset = point_win_to_thread_dpi( hwndFrom, offset );
443 /* Translate origin to destination window coords */
444 if (hwndTo)
446 if (!(wndPtr = WIN_GetPtr( hwndTo )))
448 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
449 return FALSE;
451 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
452 if (wndPtr != WND_DESKTOP)
454 POINT pt = { 0, 0 };
455 if (wndPtr->dwExStyle & WS_EX_LAYOUTRTL)
457 mirror_to = TRUE;
458 pt.x += wndPtr->client_rect.right - wndPtr->client_rect.left;
460 while (wndPtr->parent)
462 pt.x += wndPtr->client_rect.left;
463 pt.y += wndPtr->client_rect.top;
464 hwnd = wndPtr->parent;
465 WIN_ReleasePtr( wndPtr );
466 if (!(wndPtr = WIN_GetPtr( hwnd ))) break;
467 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
468 if (wndPtr == WND_DESKTOP) break;
469 if (wndPtr->flags & WIN_CHILDREN_MOVED)
471 WIN_ReleasePtr( wndPtr );
472 goto other_process;
475 if (wndPtr && wndPtr != WND_DESKTOP) WIN_ReleasePtr( wndPtr );
476 pt = point_win_to_thread_dpi( hwndTo, pt );
477 offset.x -= pt.x;
478 offset.y -= pt.y;
482 *mirrored = mirror_from ^ mirror_to;
483 if (mirror_from) offset.x = -offset.x;
484 *ret_offset = offset;
485 return TRUE;
487 other_process: /* one of the parents may belong to another process, do it the hard way */
488 SERVER_START_REQ( get_windows_offset )
490 req->from = wine_server_user_handle( hwndFrom );
491 req->to = wine_server_user_handle( hwndTo );
492 req->dpi = get_thread_dpi();
493 if ((ret = !wine_server_call_err( req )))
495 ret_offset->x = reply->x;
496 ret_offset->y = reply->y;
497 *mirrored = reply->mirror;
500 SERVER_END_REQ;
501 return ret;
504 /* map coordinates of a window region */
505 void map_window_region( HWND from, HWND to, HRGN hrgn )
507 BOOL mirrored;
508 POINT offset;
509 UINT i, size;
510 RGNDATA *data;
511 HRGN new_rgn;
512 RECT *rect;
514 if (!WINPOS_GetWinOffset( from, to, &mirrored, &offset )) return;
516 if (!mirrored)
518 OffsetRgn( hrgn, offset.x, offset.y );
519 return;
521 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
522 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
523 GetRegionData( hrgn, size, data );
524 rect = (RECT *)data->Buffer;
525 for (i = 0; i < data->rdh.nCount; i++)
527 int tmp = -(rect[i].left + offset.x);
528 rect[i].left = -(rect[i].right + offset.x);
529 rect[i].right = tmp;
530 rect[i].top += offset.y;
531 rect[i].bottom += offset.y;
533 if ((new_rgn = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data )))
535 CombineRgn( hrgn, new_rgn, 0, RGN_COPY );
536 DeleteObject( new_rgn );
538 HeapFree( GetProcessHeap(), 0, data );
542 /*******************************************************************
543 * MapWindowPoints (USER32.@)
545 INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT count )
547 BOOL mirrored;
548 POINT offset;
549 UINT i;
551 if (!WINPOS_GetWinOffset( hwndFrom, hwndTo, &mirrored, &offset )) return 0;
553 for (i = 0; i < count; i++)
555 lppt[i].x += offset.x;
556 lppt[i].y += offset.y;
557 if (mirrored) lppt[i].x = -lppt[i].x;
559 if (mirrored && count == 2) /* special case for rectangle */
561 int tmp = lppt[0].x;
562 lppt[0].x = lppt[1].x;
563 lppt[1].x = tmp;
565 return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) );
569 /*******************************************************************
570 * ClientToScreen (USER32.@)
572 BOOL WINAPI ClientToScreen( HWND hwnd, LPPOINT lppnt )
574 POINT offset;
575 BOOL mirrored;
577 if (!hwnd)
579 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
580 return FALSE;
582 if (!WINPOS_GetWinOffset( hwnd, 0, &mirrored, &offset )) return FALSE;
583 lppnt->x += offset.x;
584 lppnt->y += offset.y;
585 if (mirrored) lppnt->x = -lppnt->x;
586 return TRUE;
590 /*******************************************************************
591 * ScreenToClient (USER32.@)
593 BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
595 POINT offset;
596 BOOL mirrored;
598 if (!hwnd)
600 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
601 return FALSE;
603 if (!WINPOS_GetWinOffset( 0, hwnd, &mirrored, &offset )) return FALSE;
604 lppnt->x += offset.x;
605 lppnt->y += offset.y;
606 if (mirrored) lppnt->x = -lppnt->x;
607 return TRUE;
611 /***********************************************************************
612 * IsIconic (USER32.@)
614 BOOL WINAPI IsIconic(HWND hWnd)
616 return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MINIMIZE) != 0;
620 /***********************************************************************
621 * IsZoomed (USER32.@)
623 BOOL WINAPI IsZoomed(HWND hWnd)
625 return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MAXIMIZE) != 0;
629 /*******************************************************************
630 * AllowSetForegroundWindow (USER32.@)
632 BOOL WINAPI AllowSetForegroundWindow( DWORD procid )
634 /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
635 * implemented, then fix this function. */
636 return TRUE;
640 /*******************************************************************
641 * LockSetForegroundWindow (USER32.@)
643 BOOL WINAPI LockSetForegroundWindow( UINT lockcode )
645 /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
646 * implemented, then fix this function. */
647 return TRUE;
651 /***********************************************************************
652 * BringWindowToTop (USER32.@)
654 BOOL WINAPI BringWindowToTop( HWND hwnd )
656 return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
660 /***********************************************************************
661 * MoveWindow (USER32.@)
663 BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
664 BOOL repaint )
666 int flags = SWP_NOZORDER | SWP_NOACTIVATE;
667 if (!repaint) flags |= SWP_NOREDRAW;
668 TRACE("%p %d,%d %dx%d %d\n", hwnd, x, y, cx, cy, repaint );
669 return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
673 /*******************************************************************
674 * get_work_rect
676 * Get the work area that a maximized window can cover, depending on style.
678 static BOOL get_work_rect( HWND hwnd, RECT *rect )
680 HMONITOR monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY );
681 MONITORINFO mon_info;
682 DWORD style;
684 if (!monitor) return FALSE;
686 mon_info.cbSize = sizeof(mon_info);
687 GetMonitorInfoW( monitor, &mon_info );
688 *rect = mon_info.rcMonitor;
690 style = GetWindowLongW( hwnd, GWL_STYLE );
691 if (style & WS_MAXIMIZEBOX)
693 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
694 *rect = mon_info.rcWork;
696 return TRUE;
700 /*******************************************************************
701 * WINPOS_GetMinMaxInfo
703 * Get the minimized and maximized information for a window.
705 MINMAXINFO WINPOS_GetMinMaxInfo( HWND hwnd )
707 DPI_AWARENESS_CONTEXT context;
708 RECT rc_work, rc_primary;
709 MINMAXINFO MinMax;
710 INT xinc, yinc;
711 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
712 LONG adjustedStyle;
713 LONG exstyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
714 RECT rc;
715 WND *win;
717 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
719 /* Compute default values */
721 GetWindowRect(hwnd, &rc);
722 MinMax.ptReserved.x = rc.left;
723 MinMax.ptReserved.y = rc.top;
725 if ((style & WS_CAPTION) == WS_CAPTION)
726 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
727 else
728 adjustedStyle = style;
730 GetClientRect(GetAncestor(hwnd,GA_PARENT), &rc);
731 AdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
733 xinc = -rc.left;
734 yinc = -rc.top;
736 MinMax.ptMaxSize.x = rc.right - rc.left;
737 MinMax.ptMaxSize.y = rc.bottom - rc.top;
738 if (style & (WS_DLGFRAME | WS_BORDER))
740 MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
741 MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
743 else
745 MinMax.ptMinTrackSize.x = 2 * xinc;
746 MinMax.ptMinTrackSize.y = 2 * yinc;
748 MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
749 MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
750 MinMax.ptMaxPosition.x = -xinc;
751 MinMax.ptMaxPosition.y = -yinc;
753 if ((win = WIN_GetPtr( hwnd )) && win != WND_DESKTOP && win != WND_OTHER_PROCESS)
755 if (!EMPTYPOINT(win->max_pos)) MinMax.ptMaxPosition = win->max_pos;
756 WIN_ReleasePtr( win );
759 SendMessageW( hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
761 /* if the app didn't change the values, adapt them for the current monitor */
763 if (get_work_rect( hwnd, &rc_work ))
765 rc_primary = get_primary_monitor_rect();
766 if (MinMax.ptMaxSize.x == (rc_primary.right - rc_primary.left) + 2 * xinc &&
767 MinMax.ptMaxSize.y == (rc_primary.bottom - rc_primary.top) + 2 * yinc)
769 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
770 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
772 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
774 MinMax.ptMaxPosition.x = rc_work.left - xinc;
775 MinMax.ptMaxPosition.y = rc_work.top - yinc;
779 /* Some sanity checks */
781 TRACE("%d %d / %d %d / %d %d / %d %d\n",
782 MinMax.ptMaxSize.x, MinMax.ptMaxSize.y,
783 MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y,
784 MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y,
785 MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y);
786 MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x,
787 MinMax.ptMinTrackSize.x );
788 MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y,
789 MinMax.ptMinTrackSize.y );
791 SetThreadDpiAwarenessContext( context );
792 return MinMax;
795 static POINT get_first_minimized_child_pos( const RECT *parent, const MINIMIZEDMETRICS *mm,
796 int width, int height )
798 POINT ret;
800 if (mm->iArrange & ARW_STARTRIGHT)
801 ret.x = parent->right - mm->iHorzGap - width;
802 else
803 ret.x = parent->left + mm->iHorzGap;
804 if (mm->iArrange & ARW_STARTTOP)
805 ret.y = parent->top + mm->iVertGap;
806 else
807 ret.y = parent->bottom - mm->iVertGap - height;
809 return ret;
812 static void get_next_minimized_child_pos( const RECT *parent, const MINIMIZEDMETRICS *mm,
813 int width, int height, POINT *pos )
815 BOOL next;
817 if (mm->iArrange & ARW_UP) /* == ARW_DOWN */
819 if (mm->iArrange & ARW_STARTTOP)
821 pos->y += height + mm->iVertGap;
822 if ((next = pos->y + height > parent->bottom))
823 pos->y = parent->top + mm->iVertGap;
825 else
827 pos->y -= height + mm->iVertGap;
828 if ((next = pos->y < parent->top))
829 pos->y = parent->bottom - mm->iVertGap - height;
832 if (next)
834 if (mm->iArrange & ARW_STARTRIGHT)
835 pos->x -= width + mm->iHorzGap;
836 else
837 pos->x += width + mm->iHorzGap;
840 else
842 if (mm->iArrange & ARW_STARTRIGHT)
844 pos->x -= width + mm->iHorzGap;
845 if ((next = pos->x < parent->left))
846 pos->x = parent->right - mm->iHorzGap - width;
848 else
850 pos->x += width + mm->iHorzGap;
851 if ((next = pos->x + width > parent->right))
852 pos->x = parent->left + mm->iHorzGap;
855 if (next)
857 if (mm->iArrange & ARW_STARTTOP)
858 pos->y += height + mm->iVertGap;
859 else
860 pos->y -= height + mm->iVertGap;
865 static POINT get_minimized_pos( HWND hwnd, POINT pt )
867 RECT rect, rectParent;
868 HWND parent, child;
869 HRGN hrgn, tmp;
870 MINIMIZEDMETRICS metrics;
871 int width, height;
873 parent = GetAncestor( hwnd, GA_PARENT );
874 if (parent == GetDesktopWindow())
876 MONITORINFO mon_info;
877 HMONITOR monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY );
879 mon_info.cbSize = sizeof( mon_info );
880 GetMonitorInfoW( monitor, &mon_info );
881 rectParent = mon_info.rcWork;
883 else GetClientRect( parent, &rectParent );
885 if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics( SM_CXMINIMIZED ) < rectParent.right) &&
886 (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics( SM_CYMINIMIZED ) < rectParent.bottom))
887 return pt; /* The icon already has a suitable position */
889 width = GetSystemMetrics( SM_CXMINIMIZED );
890 height = GetSystemMetrics( SM_CYMINIMIZED );
892 metrics.cbSize = sizeof(metrics);
893 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(metrics), &metrics, 0 );
895 /* Check if another icon already occupies this spot */
896 /* FIXME: this is completely inefficient */
898 hrgn = CreateRectRgn( 0, 0, 0, 0 );
899 tmp = CreateRectRgn( 0, 0, 0, 0 );
900 for (child = GetWindow( parent, GW_CHILD ); child; child = GetWindow( child, GW_HWNDNEXT ))
902 if (child == hwnd) continue;
903 if ((GetWindowLongW( child, GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE))
904 continue;
905 if (WIN_GetRectangles( child, COORDS_PARENT, &rect, NULL ))
907 SetRectRgn( tmp, rect.left, rect.top, rect.right, rect.bottom );
908 CombineRgn( hrgn, hrgn, tmp, RGN_OR );
911 DeleteObject( tmp );
913 pt = get_first_minimized_child_pos( &rectParent, &metrics, width, height );
914 for (;;)
916 SetRect( &rect, pt.x, pt.y, pt.x + width, pt.y + height );
917 if (!RectInRegion( hrgn, &rect ))
918 break;
920 get_next_minimized_child_pos( &rectParent, &metrics, width, height, &pt );
923 DeleteObject( hrgn );
924 return pt;
928 /***********************************************************************
929 * WINPOS_MinMaximize
931 UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
933 UINT swpFlags = 0;
934 LONG old_style;
935 MINMAXINFO minmax;
936 WINDOWPLACEMENT wpl;
938 TRACE("%p %u\n", hwnd, cmd );
940 wpl.length = sizeof(wpl);
941 GetWindowPlacement( hwnd, &wpl );
943 if (HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd, TRUE ))
944 return SWP_NOSIZE | SWP_NOMOVE;
946 if (IsIconic( hwnd ))
948 switch (cmd)
950 case SW_SHOWMINNOACTIVE:
951 case SW_SHOWMINIMIZED:
952 case SW_FORCEMINIMIZE:
953 case SW_MINIMIZE:
954 wpl.ptMinPosition = get_minimized_pos( hwnd, wpl.ptMinPosition );
956 SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
957 wpl.ptMinPosition.x + GetSystemMetrics(SM_CXMINIMIZED),
958 wpl.ptMinPosition.y + GetSystemMetrics(SM_CYMINIMIZED) );
959 return SWP_NOSIZE | SWP_NOMOVE;
961 if (!SendMessageW( hwnd, WM_QUERYOPEN, 0, 0 )) return SWP_NOSIZE | SWP_NOMOVE;
962 swpFlags |= SWP_NOCOPYBITS;
965 switch( cmd )
967 case SW_SHOWMINNOACTIVE:
968 case SW_SHOWMINIMIZED:
969 case SW_FORCEMINIMIZE:
970 case SW_MINIMIZE:
971 if (IsZoomed( hwnd )) win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
972 else win_set_flags( hwnd, 0, WIN_RESTORE_MAX );
974 if (GetFocus() == hwnd)
976 if (GetWindowLongW(hwnd, GWL_STYLE) & WS_CHILD)
977 SetFocus(GetAncestor(hwnd, GA_PARENT));
978 else
979 SetFocus(0);
982 old_style = WIN_SetStyle( hwnd, WS_MINIMIZE, WS_MAXIMIZE );
984 wpl.ptMinPosition = get_minimized_pos( hwnd, wpl.ptMinPosition );
986 if (!(old_style & WS_MINIMIZE)) swpFlags |= SWP_STATECHANGED;
987 SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
988 wpl.ptMinPosition.x + GetSystemMetrics(SM_CXMINIMIZED),
989 wpl.ptMinPosition.y + GetSystemMetrics(SM_CYMINIMIZED) );
990 swpFlags |= SWP_NOCOPYBITS;
991 break;
993 case SW_MAXIMIZE:
994 old_style = GetWindowLongW( hwnd, GWL_STYLE );
995 if ((old_style & WS_MAXIMIZE) && (old_style & WS_VISIBLE)) return SWP_NOSIZE | SWP_NOMOVE;
997 minmax = WINPOS_GetMinMaxInfo( hwnd );
999 old_style = WIN_SetStyle( hwnd, WS_MAXIMIZE, WS_MINIMIZE );
1000 if (old_style & WS_MINIMIZE)
1001 win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
1003 if (!(old_style & WS_MAXIMIZE)) swpFlags |= SWP_STATECHANGED;
1004 SetRect( rect, minmax.ptMaxPosition.x, minmax.ptMaxPosition.y,
1005 minmax.ptMaxPosition.x + minmax.ptMaxSize.x, minmax.ptMaxPosition.y + minmax.ptMaxSize.y );
1006 break;
1008 case SW_SHOWNOACTIVATE:
1009 win_set_flags( hwnd, 0, WIN_RESTORE_MAX );
1010 /* fall through */
1011 case SW_SHOWNORMAL:
1012 case SW_RESTORE:
1013 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1014 old_style = WIN_SetStyle( hwnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
1015 if (old_style & WS_MINIMIZE)
1017 if (win_get_flags( hwnd ) & WIN_RESTORE_MAX)
1019 /* Restore to maximized position */
1020 minmax = WINPOS_GetMinMaxInfo( hwnd );
1021 WIN_SetStyle( hwnd, WS_MAXIMIZE, 0 );
1022 swpFlags |= SWP_STATECHANGED;
1023 SetRect( rect, minmax.ptMaxPosition.x, minmax.ptMaxPosition.y,
1024 minmax.ptMaxPosition.x + minmax.ptMaxSize.x, minmax.ptMaxPosition.y + minmax.ptMaxSize.y );
1025 break;
1028 else if (!(old_style & WS_MAXIMIZE)) break;
1030 swpFlags |= SWP_STATECHANGED;
1032 /* Restore to normal position */
1034 *rect = wpl.rcNormalPosition;
1035 break;
1038 return swpFlags;
1042 /***********************************************************************
1043 * show_window
1045 * Implementation of ShowWindow and ShowWindowAsync.
1047 static BOOL show_window( HWND hwnd, INT cmd )
1049 WND *wndPtr;
1050 HWND parent;
1051 DPI_AWARENESS_CONTEXT context;
1052 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1053 BOOL wasVisible = (style & WS_VISIBLE) != 0;
1054 BOOL showFlag = TRUE;
1055 RECT newPos = {0, 0, 0, 0};
1056 UINT new_swp, swp = 0;
1058 TRACE("hwnd=%p, cmd=%d, wasVisible %d\n", hwnd, cmd, wasVisible);
1060 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( hwnd ));
1062 switch(cmd)
1064 case SW_HIDE:
1065 if (!wasVisible) goto done;
1066 showFlag = FALSE;
1067 swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1068 if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1069 break;
1071 case SW_SHOWMINNOACTIVE:
1072 case SW_MINIMIZE:
1073 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
1074 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1075 /* fall through */
1076 case SW_SHOWMINIMIZED:
1077 swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1078 swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
1079 if ((style & WS_MINIMIZE) && wasVisible) goto done;
1080 break;
1082 case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
1083 if (!wasVisible) swp |= SWP_SHOWWINDOW;
1084 swp |= SWP_FRAMECHANGED;
1085 swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
1086 if ((style & WS_MAXIMIZE) && wasVisible) goto done;
1087 break;
1089 case SW_SHOWNA:
1090 swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1091 if (style & WS_CHILD) swp |= SWP_NOZORDER;
1092 break;
1093 case SW_SHOW:
1094 if (wasVisible) goto done;
1095 swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1096 if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1097 break;
1099 case SW_SHOWNOACTIVATE:
1100 swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1101 /* fall through */
1102 case SW_RESTORE:
1103 /* fall through */
1104 case SW_SHOWNORMAL: /* same as SW_NORMAL: */
1105 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1106 if (!wasVisible) swp |= SWP_SHOWWINDOW;
1107 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1109 swp |= SWP_FRAMECHANGED;
1110 swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
1112 else
1114 if (wasVisible) goto done;
1115 swp |= SWP_NOSIZE | SWP_NOMOVE;
1117 if (style & WS_CHILD && !(swp & SWP_STATECHANGED)) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1118 break;
1119 default:
1120 goto done;
1123 if ((showFlag != wasVisible || cmd == SW_SHOWNA) && cmd != SW_SHOWMAXIMIZED && !(swp & SWP_STATECHANGED))
1125 SendMessageW( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1126 if (!IsWindow( hwnd )) goto done;
1129 if (IsRectEmpty( &newPos )) new_swp = swp;
1130 else if ((new_swp = USER_Driver->pShowWindow( hwnd, cmd, &newPos, swp )) == ~0)
1132 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) new_swp = swp;
1133 else if (IsIconic( hwnd ) && (newPos.left != -32000 || newPos.top != -32000))
1135 OffsetRect( &newPos, -32000 - newPos.left, -32000 - newPos.top );
1136 new_swp = swp & ~(SWP_NOMOVE | SWP_NOCLIENTMOVE);
1138 else new_swp = swp;
1140 swp = new_swp;
1142 parent = GetAncestor( hwnd, GA_PARENT );
1143 if (parent && !IsWindowVisible( parent ) && !(swp & SWP_STATECHANGED))
1145 /* if parent is not visible simply toggle WS_VISIBLE and return */
1146 if (showFlag) WIN_SetStyle( hwnd, WS_VISIBLE, 0 );
1147 else WIN_SetStyle( hwnd, 0, WS_VISIBLE );
1149 else
1150 SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
1151 newPos.right - newPos.left, newPos.bottom - newPos.top, swp );
1153 if (cmd == SW_HIDE)
1155 HWND hFocus;
1157 /* FIXME: This will cause the window to be activated irrespective
1158 * of whether it is owned by the same thread. Has to be done
1159 * asynchronously.
1162 if (hwnd == GetActiveWindow())
1163 WINPOS_ActivateOtherWindow(hwnd);
1165 /* Revert focus to parent */
1166 hFocus = GetFocus();
1167 if (hwnd == hFocus)
1169 HWND parent = GetAncestor(hwnd, GA_PARENT);
1170 if (parent == GetDesktopWindow()) parent = 0;
1171 SetFocus(parent);
1173 goto done;
1176 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) goto done;
1178 if (wndPtr->flags & WIN_NEED_SIZE)
1180 /* should happen only in CreateWindowEx() */
1181 int wParam = SIZE_RESTORED;
1182 RECT client;
1183 LPARAM lparam;
1185 WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &client );
1186 lparam = MAKELONG( client.right - client.left, client.bottom - client.top );
1187 wndPtr->flags &= ~WIN_NEED_SIZE;
1188 if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
1189 else if (wndPtr->dwStyle & WS_MINIMIZE)
1191 wParam = SIZE_MINIMIZED;
1192 lparam = 0;
1194 WIN_ReleasePtr( wndPtr );
1196 SendMessageW( hwnd, WM_SIZE, wParam, lparam );
1197 SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( client.left, client.top ));
1199 else WIN_ReleasePtr( wndPtr );
1201 /* if previous state was minimized Windows sets focus to the window */
1202 if (style & WS_MINIMIZE)
1204 SetFocus( hwnd );
1205 /* Send a WM_ACTIVATE message for a top level window, even if the window is already active */
1206 if (GetAncestor( hwnd, GA_ROOT ) == hwnd && !(swp & SWP_NOACTIVATE))
1207 SendMessageW( hwnd, WM_ACTIVATE, WA_ACTIVE, 0 );
1210 done:
1211 SetThreadDpiAwarenessContext( context );
1212 return wasVisible;
1216 /***********************************************************************
1217 * ShowWindowAsync (USER32.@)
1219 * doesn't wait; returns immediately.
1220 * used by threads to toggle windows in other (possibly hanging) threads
1222 BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd )
1224 HWND full_handle;
1226 if (is_broadcast(hwnd))
1228 SetLastError( ERROR_INVALID_PARAMETER );
1229 return FALSE;
1232 if ((full_handle = WIN_IsCurrentThread( hwnd )))
1233 return show_window( full_handle, cmd );
1235 return SendNotifyMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
1239 /***********************************************************************
1240 * ShowWindow (USER32.@)
1242 BOOL WINAPI ShowWindow( HWND hwnd, INT cmd )
1244 HWND full_handle;
1246 if (is_broadcast(hwnd))
1248 SetLastError( ERROR_INVALID_PARAMETER );
1249 return FALSE;
1251 if ((full_handle = WIN_IsCurrentThread( hwnd )))
1252 return show_window( full_handle, cmd );
1254 if ((cmd == SW_HIDE) && !(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
1255 return FALSE;
1257 if ((cmd == SW_SHOW) && (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE))
1258 return TRUE;
1260 return SendMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
1264 /***********************************************************************
1265 * GetInternalWindowPos (USER32.@)
1267 UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd,
1268 LPPOINT ptIcon )
1270 WINDOWPLACEMENT wndpl;
1272 wndpl.length = sizeof(wndpl);
1273 if (GetWindowPlacement( hwnd, &wndpl ))
1275 if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
1276 if (ptIcon) *ptIcon = wndpl.ptMinPosition;
1277 return wndpl.showCmd;
1279 return 0;
1283 static RECT get_maximized_work_rect( HWND hwnd )
1285 RECT work_rect = { 0 };
1287 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_MINIMIZE | WS_MAXIMIZE)) == WS_MAXIMIZE)
1289 if (!get_work_rect( hwnd, &work_rect ))
1290 work_rect = get_primary_monitor_rect();
1292 return work_rect;
1296 /*******************************************************************
1297 * update_maximized_pos
1299 * For top level windows covering the work area, we might have to
1300 * "forget" the maximized position. Windows presumably does this
1301 * to avoid situations where the border style changes, which would
1302 * lead the window to be outside the screen, or the window gets
1303 * reloaded on a different screen, and the "saved" position no
1304 * longer applies to it (despite being maximized).
1306 * Some applications (e.g. Imperiums: Greek Wars) depend on this.
1308 static void update_maximized_pos( WND *wnd, RECT *work_rect )
1310 if (wnd->parent && wnd->parent != GetDesktopWindow())
1311 return;
1313 if (wnd->dwStyle & WS_MAXIMIZE)
1315 if (wnd->window_rect.left <= work_rect->left && wnd->window_rect.top <= work_rect->top &&
1316 wnd->window_rect.right >= work_rect->right && wnd->window_rect.bottom >= work_rect->bottom)
1317 wnd->max_pos.x = wnd->max_pos.y = -1;
1319 else
1320 wnd->max_pos.x = wnd->max_pos.y = -1;
1324 /***********************************************************************
1325 * GetWindowPlacement (USER32.@)
1327 * Win95:
1328 * Fails if wndpl->length of Win95 (!) apps is invalid.
1330 BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
1332 RECT work_rect = get_maximized_work_rect( hwnd );
1333 WND *pWnd = WIN_GetPtr( hwnd );
1335 if (!pWnd) return FALSE;
1337 if (pWnd == WND_DESKTOP)
1339 wndpl->length = sizeof(*wndpl);
1340 wndpl->showCmd = SW_SHOWNORMAL;
1341 wndpl->flags = 0;
1342 wndpl->ptMinPosition.x = -1;
1343 wndpl->ptMinPosition.y = -1;
1344 wndpl->ptMaxPosition.x = -1;
1345 wndpl->ptMaxPosition.y = -1;
1346 GetWindowRect( hwnd, &wndpl->rcNormalPosition );
1347 return TRUE;
1349 if (pWnd == WND_OTHER_PROCESS)
1351 RECT normal_position;
1352 DWORD style;
1354 if (!GetWindowRect(hwnd, &normal_position))
1355 return FALSE;
1357 FIXME("not fully supported on other process window %p.\n", hwnd);
1359 wndpl->length = sizeof(*wndpl);
1360 style = GetWindowLongW(hwnd, GWL_STYLE);
1361 if (style & WS_MINIMIZE)
1362 wndpl->showCmd = SW_SHOWMINIMIZED;
1363 else
1364 wndpl->showCmd = (style & WS_MAXIMIZE) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL;
1365 /* provide some dummy information */
1366 wndpl->flags = 0;
1367 wndpl->ptMinPosition.x = -1;
1368 wndpl->ptMinPosition.y = -1;
1369 wndpl->ptMaxPosition.x = -1;
1370 wndpl->ptMaxPosition.y = -1;
1371 wndpl->rcNormalPosition = normal_position;
1372 return TRUE;
1375 /* update the placement according to the current style */
1376 if (pWnd->dwStyle & WS_MINIMIZE)
1378 pWnd->min_pos.x = pWnd->window_rect.left;
1379 pWnd->min_pos.y = pWnd->window_rect.top;
1381 else if (pWnd->dwStyle & WS_MAXIMIZE)
1383 pWnd->max_pos.x = pWnd->window_rect.left;
1384 pWnd->max_pos.y = pWnd->window_rect.top;
1386 else
1388 pWnd->normal_rect = pWnd->window_rect;
1390 update_maximized_pos( pWnd, &work_rect );
1392 wndpl->length = sizeof(*wndpl);
1393 if( pWnd->dwStyle & WS_MINIMIZE )
1394 wndpl->showCmd = SW_SHOWMINIMIZED;
1395 else
1396 wndpl->showCmd = ( pWnd->dwStyle & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
1397 if( pWnd->flags & WIN_RESTORE_MAX )
1398 wndpl->flags = WPF_RESTORETOMAXIMIZED;
1399 else
1400 wndpl->flags = 0;
1401 wndpl->ptMinPosition = EMPTYPOINT(pWnd->min_pos) ? pWnd->min_pos : point_win_to_thread_dpi( hwnd, pWnd->min_pos );
1402 wndpl->ptMaxPosition = EMPTYPOINT(pWnd->max_pos) ? pWnd->max_pos : point_win_to_thread_dpi( hwnd, pWnd->max_pos );
1403 wndpl->rcNormalPosition = rect_win_to_thread_dpi( hwnd, pWnd->normal_rect );
1404 WIN_ReleasePtr( pWnd );
1406 TRACE( "%p: returning min %d,%d max %d,%d normal %s\n",
1407 hwnd, wndpl->ptMinPosition.x, wndpl->ptMinPosition.y,
1408 wndpl->ptMaxPosition.x, wndpl->ptMaxPosition.y,
1409 wine_dbgstr_rect(&wndpl->rcNormalPosition) );
1410 return TRUE;
1413 /* make sure the specified rect is visible on screen */
1414 static void make_rect_onscreen( RECT *rect )
1416 MONITORINFO info;
1417 HMONITOR monitor = MonitorFromRect( rect, MONITOR_DEFAULTTONEAREST );
1419 info.cbSize = sizeof(info);
1420 if (!monitor || !GetMonitorInfoW( monitor, &info )) return;
1421 /* FIXME: map coordinates from rcWork to rcMonitor */
1422 if (rect->right <= info.rcWork.left)
1424 rect->right += info.rcWork.left - rect->left;
1425 rect->left = info.rcWork.left;
1427 else if (rect->left >= info.rcWork.right)
1429 rect->left += info.rcWork.right - rect->right;
1430 rect->right = info.rcWork.right;
1432 if (rect->bottom <= info.rcWork.top)
1434 rect->bottom += info.rcWork.top - rect->top;
1435 rect->top = info.rcWork.top;
1437 else if (rect->top >= info.rcWork.bottom)
1439 rect->top += info.rcWork.bottom - rect->bottom;
1440 rect->bottom = info.rcWork.bottom;
1444 /* make sure the specified point is visible on screen */
1445 static void make_point_onscreen( POINT *pt )
1447 RECT rect;
1449 SetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 );
1450 make_rect_onscreen( &rect );
1451 pt->x = rect.left;
1452 pt->y = rect.top;
1456 /***********************************************************************
1457 * WINPOS_SetPlacement
1459 static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT flags )
1461 DWORD style;
1462 RECT work_rect = get_maximized_work_rect( hwnd );
1463 WND *pWnd = WIN_GetPtr( hwnd );
1464 WINDOWPLACEMENT wp = *wndpl;
1466 if (flags & PLACE_MIN) make_point_onscreen( &wp.ptMinPosition );
1467 if (flags & PLACE_MAX) make_point_onscreen( &wp.ptMaxPosition );
1468 if (flags & PLACE_RECT) make_rect_onscreen( &wp.rcNormalPosition );
1470 TRACE( "%p: setting min %d,%d max %d,%d normal %s flags %x adjusted to min %d,%d max %d,%d normal %s\n",
1471 hwnd, wndpl->ptMinPosition.x, wndpl->ptMinPosition.y,
1472 wndpl->ptMaxPosition.x, wndpl->ptMaxPosition.y,
1473 wine_dbgstr_rect(&wndpl->rcNormalPosition), flags,
1474 wp.ptMinPosition.x, wp.ptMinPosition.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y,
1475 wine_dbgstr_rect(&wp.rcNormalPosition) );
1477 if (!pWnd || pWnd == WND_OTHER_PROCESS || pWnd == WND_DESKTOP) return FALSE;
1479 if (flags & PLACE_MIN) pWnd->min_pos = point_thread_to_win_dpi( hwnd, wp.ptMinPosition );
1480 if (flags & PLACE_MAX)
1482 pWnd->max_pos = point_thread_to_win_dpi( hwnd, wp.ptMaxPosition );
1483 update_maximized_pos( pWnd, &work_rect );
1485 if (flags & PLACE_RECT) pWnd->normal_rect = rect_thread_to_win_dpi( hwnd, wp.rcNormalPosition );
1487 style = pWnd->dwStyle;
1489 WIN_ReleasePtr( pWnd );
1491 if( style & WS_MINIMIZE )
1493 if (flags & PLACE_MIN)
1495 SetWindowPos( hwnd, 0, wp.ptMinPosition.x, wp.ptMinPosition.y, 0, 0,
1496 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1499 else if( style & WS_MAXIMIZE )
1501 if (flags & PLACE_MAX)
1502 SetWindowPos( hwnd, 0, wp.ptMaxPosition.x, wp.ptMaxPosition.y, 0, 0,
1503 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1505 else if( flags & PLACE_RECT )
1506 SetWindowPos( hwnd, 0, wp.rcNormalPosition.left, wp.rcNormalPosition.top,
1507 wp.rcNormalPosition.right - wp.rcNormalPosition.left,
1508 wp.rcNormalPosition.bottom - wp.rcNormalPosition.top,
1509 SWP_NOZORDER | SWP_NOACTIVATE );
1511 ShowWindow( hwnd, wndpl->showCmd );
1513 if (IsIconic( hwnd ))
1515 /* SDK: ...valid only the next time... */
1516 if( wndpl->flags & WPF_RESTORETOMAXIMIZED )
1517 win_set_flags( hwnd, WIN_RESTORE_MAX, 0 );
1519 return TRUE;
1523 /***********************************************************************
1524 * SetWindowPlacement (USER32.@)
1526 * Win95:
1527 * Fails if wndpl->length of Win95 (!) apps is invalid.
1529 BOOL WINAPI SetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl )
1531 UINT flags = PLACE_MAX | PLACE_RECT;
1532 if (!wpl) return FALSE;
1533 if (wpl->flags & WPF_SETMINPOSITION) flags |= PLACE_MIN;
1534 return WINPOS_SetPlacement( hwnd, wpl, flags );
1538 /***********************************************************************
1539 * AnimateWindow (USER32.@)
1540 * Shows/Hides a window with an animation
1541 * NO ANIMATION YET
1543 BOOL WINAPI AnimateWindow(HWND hwnd, DWORD dwTime, DWORD dwFlags)
1545 FIXME("partial stub\n");
1547 /* If trying to show/hide and it's already *
1548 * shown/hidden or invalid window, fail with *
1549 * invalid parameter */
1550 if(!IsWindow(hwnd) ||
1551 (IsWindowVisible(hwnd) && !(dwFlags & AW_HIDE)) ||
1552 (!IsWindowVisible(hwnd) && (dwFlags & AW_HIDE)))
1554 SetLastError(ERROR_INVALID_PARAMETER);
1555 return FALSE;
1558 ShowWindow(hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA));
1560 return TRUE;
1563 /***********************************************************************
1564 * SetInternalWindowPos (USER32.@)
1566 void WINAPI SetInternalWindowPos( HWND hwnd, UINT showCmd,
1567 LPRECT rect, LPPOINT pt )
1569 WINDOWPLACEMENT wndpl;
1570 UINT flags;
1572 wndpl.length = sizeof(wndpl);
1573 wndpl.showCmd = showCmd;
1574 wndpl.flags = flags = 0;
1576 if( pt )
1578 flags |= PLACE_MIN;
1579 wndpl.flags |= WPF_SETMINPOSITION;
1580 wndpl.ptMinPosition = *pt;
1582 if( rect )
1584 flags |= PLACE_RECT;
1585 wndpl.rcNormalPosition = *rect;
1587 WINPOS_SetPlacement( hwnd, &wndpl, flags );
1591 /*******************************************************************
1592 * can_activate_window
1594 * Check if we can activate the specified window.
1596 static BOOL can_activate_window( HWND hwnd )
1598 LONG style;
1600 if (!hwnd) return FALSE;
1601 style = GetWindowLongW( hwnd, GWL_STYLE );
1602 if (!(style & WS_VISIBLE)) return FALSE;
1603 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
1604 return !(style & WS_DISABLED);
1608 /*******************************************************************
1609 * WINPOS_ActivateOtherWindow
1611 * Activates window other than pWnd.
1613 void WINPOS_ActivateOtherWindow(HWND hwnd)
1615 HWND hwndTo, fg;
1617 if ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) && (hwndTo = GetWindow( hwnd, GW_OWNER )))
1619 hwndTo = GetAncestor( hwndTo, GA_ROOT );
1620 if (can_activate_window( hwndTo )) goto done;
1623 hwndTo = hwnd;
1624 for (;;)
1626 if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break;
1627 if (can_activate_window( hwndTo )) goto done;
1630 hwndTo = GetTopWindow( 0 );
1631 for (;;)
1633 if (hwndTo == hwnd)
1635 hwndTo = 0;
1636 break;
1638 if (can_activate_window( hwndTo )) goto done;
1639 if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break;
1642 done:
1643 fg = GetForegroundWindow();
1644 TRACE("win = %p fg = %p\n", hwndTo, fg);
1645 if (!fg || (hwnd == fg))
1647 if (SetForegroundWindow( hwndTo )) return;
1649 if (!SetActiveWindow( hwndTo )) SetActiveWindow(0);
1653 /***********************************************************************
1654 * WINPOS_HandleWindowPosChanging
1656 * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
1658 LONG WINPOS_HandleWindowPosChanging( HWND hwnd, WINDOWPOS *winpos )
1660 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1662 if (winpos->flags & SWP_NOSIZE) return 0;
1663 if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0))
1665 MINMAXINFO info = WINPOS_GetMinMaxInfo( hwnd );
1666 winpos->cx = min( winpos->cx, info.ptMaxTrackSize.x );
1667 winpos->cy = min( winpos->cy, info.ptMaxTrackSize.y );
1668 if (!(style & WS_MINIMIZE))
1670 winpos->cx = max( winpos->cx, info.ptMinTrackSize.x );
1671 winpos->cy = max( winpos->cy, info.ptMinTrackSize.y );
1674 return 0;
1678 /***********************************************************************
1679 * dump_winpos_flags
1681 static void dump_winpos_flags(UINT flags)
1683 static const DWORD dumped_flags = (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW |
1684 SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW |
1685 SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOOWNERZORDER |
1686 SWP_NOSENDCHANGING | SWP_DEFERERASE | SWP_ASYNCWINDOWPOS |
1687 SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_STATECHANGED);
1688 TRACE("flags:");
1689 if(flags & SWP_NOSIZE) TRACE(" SWP_NOSIZE");
1690 if(flags & SWP_NOMOVE) TRACE(" SWP_NOMOVE");
1691 if(flags & SWP_NOZORDER) TRACE(" SWP_NOZORDER");
1692 if(flags & SWP_NOREDRAW) TRACE(" SWP_NOREDRAW");
1693 if(flags & SWP_NOACTIVATE) TRACE(" SWP_NOACTIVATE");
1694 if(flags & SWP_FRAMECHANGED) TRACE(" SWP_FRAMECHANGED");
1695 if(flags & SWP_SHOWWINDOW) TRACE(" SWP_SHOWWINDOW");
1696 if(flags & SWP_HIDEWINDOW) TRACE(" SWP_HIDEWINDOW");
1697 if(flags & SWP_NOCOPYBITS) TRACE(" SWP_NOCOPYBITS");
1698 if(flags & SWP_NOOWNERZORDER) TRACE(" SWP_NOOWNERZORDER");
1699 if(flags & SWP_NOSENDCHANGING) TRACE(" SWP_NOSENDCHANGING");
1700 if(flags & SWP_DEFERERASE) TRACE(" SWP_DEFERERASE");
1701 if(flags & SWP_ASYNCWINDOWPOS) TRACE(" SWP_ASYNCWINDOWPOS");
1702 if(flags & SWP_NOCLIENTSIZE) TRACE(" SWP_NOCLIENTSIZE");
1703 if(flags & SWP_NOCLIENTMOVE) TRACE(" SWP_NOCLIENTMOVE");
1704 if(flags & SWP_STATECHANGED) TRACE(" SWP_STATECHANGED");
1706 if(flags & ~dumped_flags) TRACE(" %08x", flags & ~dumped_flags);
1707 TRACE("\n");
1711 /***********************************************************************
1712 * map_dpi_winpos
1714 static void map_dpi_winpos( WINDOWPOS *winpos )
1716 UINT dpi_from = get_thread_dpi();
1717 UINT dpi_to = GetDpiForWindow( winpos->hwnd );
1719 if (!dpi_from) dpi_from = get_win_monitor_dpi( winpos->hwnd );
1720 if (dpi_from == dpi_to) return;
1721 winpos->x = MulDiv( winpos->x, dpi_to, dpi_from );
1722 winpos->y = MulDiv( winpos->y, dpi_to, dpi_from );
1723 winpos->cx = MulDiv( winpos->cx, dpi_to, dpi_from );
1724 winpos->cy = MulDiv( winpos->cy, dpi_to, dpi_from );
1727 /***********************************************************************
1728 * SWP_DoWinPosChanging
1730 static BOOL SWP_DoWinPosChanging( WINDOWPOS *pWinpos, RECT *old_window_rect, RECT *old_client_rect,
1731 RECT *new_window_rect, RECT *new_client_rect )
1733 WND *wndPtr;
1735 /* Send WM_WINDOWPOSCHANGING message */
1737 if (!(pWinpos->flags & SWP_NOSENDCHANGING)
1738 && !((pWinpos->flags & SWP_AGG_NOCLIENTCHANGE) && (pWinpos->flags & SWP_SHOWWINDOW)))
1739 SendMessageW( pWinpos->hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
1741 if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) ||
1742 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
1744 /* Calculate new position and size */
1746 WIN_GetRectangles( pWinpos->hwnd, COORDS_PARENT, old_window_rect, old_client_rect );
1747 *new_window_rect = *old_window_rect;
1748 *new_client_rect = *old_client_rect;
1750 if (!(pWinpos->flags & SWP_NOSIZE))
1752 if (wndPtr->dwStyle & WS_MINIMIZE)
1754 new_window_rect->right = new_window_rect->left + GetSystemMetrics(SM_CXMINIMIZED);
1755 new_window_rect->bottom = new_window_rect->top + GetSystemMetrics(SM_CYMINIMIZED);
1757 else
1759 new_window_rect->right = new_window_rect->left + pWinpos->cx;
1760 new_window_rect->bottom = new_window_rect->top + pWinpos->cy;
1763 if (!(pWinpos->flags & SWP_NOMOVE))
1765 /* If the window is toplevel minimized off-screen, force keep it there */
1766 if ((wndPtr->dwStyle & WS_MINIMIZE) &&
1767 wndPtr->window_rect.left <= -32000 && wndPtr->window_rect.top <= -32000 &&
1768 (!wndPtr->parent || wndPtr->parent == GetDesktopWindow()))
1770 pWinpos->x = -32000;
1771 pWinpos->y = -32000;
1773 new_window_rect->left = pWinpos->x;
1774 new_window_rect->top = pWinpos->y;
1775 new_window_rect->right += pWinpos->x - old_window_rect->left;
1776 new_window_rect->bottom += pWinpos->y - old_window_rect->top;
1778 OffsetRect( new_client_rect, pWinpos->x - old_window_rect->left,
1779 pWinpos->y - old_window_rect->top );
1781 pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1783 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x current %s style %08x new %s\n",
1784 pWinpos->hwnd, pWinpos->hwndInsertAfter, pWinpos->x, pWinpos->y,
1785 pWinpos->cx, pWinpos->cy, pWinpos->flags,
1786 wine_dbgstr_rect( old_window_rect ), wndPtr->dwStyle,
1787 wine_dbgstr_rect( new_window_rect ));
1789 WIN_ReleasePtr( wndPtr );
1790 return TRUE;
1793 /***********************************************************************
1794 * get_valid_rects
1796 * Compute the valid rects from the old and new client rect and WVR_* flags.
1797 * Helper for WM_NCCALCSIZE handling.
1799 static inline void get_valid_rects( const RECT *old_client, const RECT *new_client, UINT flags,
1800 RECT *valid )
1802 int cx, cy;
1804 if (flags & WVR_REDRAW)
1806 SetRectEmpty( &valid[0] );
1807 SetRectEmpty( &valid[1] );
1808 return;
1811 if (flags & WVR_VALIDRECTS)
1813 if (!IntersectRect( &valid[0], &valid[0], new_client ) ||
1814 !IntersectRect( &valid[1], &valid[1], old_client ))
1816 SetRectEmpty( &valid[0] );
1817 SetRectEmpty( &valid[1] );
1818 return;
1820 flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
1822 else
1824 valid[0] = *new_client;
1825 valid[1] = *old_client;
1828 /* make sure the rectangles have the same size */
1829 cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
1830 cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
1832 if (flags & WVR_ALIGNBOTTOM)
1834 valid[0].top = valid[0].bottom - cy;
1835 valid[1].top = valid[1].bottom - cy;
1837 else
1839 valid[0].bottom = valid[0].top + cy;
1840 valid[1].bottom = valid[1].top + cy;
1842 if (flags & WVR_ALIGNRIGHT)
1844 valid[0].left = valid[0].right - cx;
1845 valid[1].left = valid[1].right - cx;
1847 else
1849 valid[0].right = valid[0].left + cx;
1850 valid[1].right = valid[1].left + cx;
1855 /***********************************************************************
1856 * SWP_DoOwnedPopups
1858 * fix Z order taking into account owned popups -
1859 * basically we need to maintain them above the window that owns them
1861 * FIXME: hide/show owned popups when owner visibility changes.
1863 static HWND SWP_DoOwnedPopups(HWND hwnd, HWND hwndInsertAfter)
1865 HWND owner, *list = NULL;
1866 unsigned int i;
1868 TRACE("(%p) hInsertAfter = %p\n", hwnd, hwndInsertAfter );
1870 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return hwndInsertAfter;
1872 if ((owner = GetWindow( hwnd, GW_OWNER )))
1874 /* make sure this popup stays above the owner */
1876 if (hwndInsertAfter != HWND_TOPMOST)
1878 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return hwndInsertAfter;
1880 for (i = 0; list[i]; i++)
1882 BOOL topmost = (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TOPMOST) != 0;
1884 if (list[i] == owner)
1886 if (i > 0) hwndInsertAfter = list[i-1];
1887 else hwndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP;
1888 break;
1891 if (hwndInsertAfter == HWND_TOP || hwndInsertAfter == HWND_NOTOPMOST)
1893 if (!topmost) break;
1895 else if (list[i] == hwndInsertAfter) break;
1900 if (hwndInsertAfter == HWND_BOTTOM) goto done;
1901 if (!list && !(list = WIN_ListChildren( GetDesktopWindow() ))) goto done;
1903 i = 0;
1904 if (hwndInsertAfter == HWND_TOP || hwndInsertAfter == HWND_NOTOPMOST)
1906 if (hwndInsertAfter == HWND_NOTOPMOST || !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST))
1908 /* skip all the topmost windows */
1909 while (list[i] && (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TOPMOST)) i++;
1912 else if (hwndInsertAfter != HWND_TOPMOST)
1914 /* skip windows that are already placed correctly */
1915 for (i = 0; list[i]; i++)
1917 if (list[i] == hwndInsertAfter) break;
1918 if (list[i] == hwnd) goto done; /* nothing to do if window is moving backwards in z-order */
1922 for ( ; list[i]; i++)
1924 if (list[i] == hwnd) break;
1925 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1926 TRACE( "moving %p owned by %p after %p\n", list[i], hwnd, hwndInsertAfter );
1927 SetWindowPos( list[i], hwndInsertAfter, 0, 0, 0, 0,
1928 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE );
1929 hwndInsertAfter = list[i];
1932 done:
1933 HeapFree( GetProcessHeap(), 0, list );
1934 return hwndInsertAfter;
1937 /***********************************************************************
1938 * SWP_DoNCCalcSize
1940 static UINT SWP_DoNCCalcSize( WINDOWPOS *pWinpos, const RECT *old_window_rect, const RECT *old_client_rect,
1941 const RECT *new_window_rect, RECT *new_client_rect, RECT *validRects,
1942 int parent_x, int parent_y )
1944 UINT wvrFlags = 0;
1946 /* Send WM_NCCALCSIZE message to get new client area */
1947 if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
1949 NCCALCSIZE_PARAMS params;
1950 WINDOWPOS winposCopy;
1952 params.rgrc[0] = *new_window_rect;
1953 params.rgrc[1] = *old_window_rect;
1954 params.rgrc[2] = *old_client_rect;
1955 params.lppos = &winposCopy;
1956 winposCopy = *pWinpos;
1958 if (pWinpos->flags & SWP_NOMOVE)
1960 winposCopy.x = old_window_rect->left;
1961 winposCopy.y = old_window_rect->top;
1964 if (pWinpos->flags & SWP_NOSIZE)
1966 winposCopy.cx = old_window_rect->right - old_window_rect->left;
1967 winposCopy.cy = old_window_rect->bottom - old_window_rect->top;
1970 wvrFlags = SendMessageW( pWinpos->hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)&params );
1972 *new_client_rect = params.rgrc[0];
1974 TRACE( "hwnd %p old win %s old client %s new win %s new client %s\n", pWinpos->hwnd,
1975 wine_dbgstr_rect(old_window_rect), wine_dbgstr_rect(old_client_rect),
1976 wine_dbgstr_rect(new_window_rect), wine_dbgstr_rect(new_client_rect) );
1978 if (new_client_rect->left != old_client_rect->left - parent_x ||
1979 new_client_rect->top != old_client_rect->top - parent_y)
1980 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
1982 if( (new_client_rect->right - new_client_rect->left !=
1983 old_client_rect->right - old_client_rect->left))
1984 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
1985 else
1986 wvrFlags &= ~WVR_HREDRAW;
1988 if (new_client_rect->bottom - new_client_rect->top !=
1989 old_client_rect->bottom - old_client_rect->top)
1990 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
1991 else
1992 wvrFlags &= ~WVR_VREDRAW;
1994 validRects[0] = params.rgrc[1];
1995 validRects[1] = params.rgrc[2];
1997 else
1999 if (!(pWinpos->flags & SWP_NOMOVE) &&
2000 (new_client_rect->left != old_client_rect->left - parent_x ||
2001 new_client_rect->top != old_client_rect->top - parent_y))
2002 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
2005 if (pWinpos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
2007 SetRectEmpty( &validRects[0] );
2008 SetRectEmpty( &validRects[1] );
2010 else get_valid_rects( old_client_rect, new_client_rect, wvrFlags, validRects );
2012 return wvrFlags;
2015 /* fix redundant flags and values in the WINDOWPOS structure */
2016 static BOOL fixup_flags( WINDOWPOS *winpos, const RECT *old_window_rect, int parent_x, int parent_y )
2018 HWND parent;
2019 WND *wndPtr = WIN_GetPtr( winpos->hwnd );
2020 BOOL ret = TRUE;
2022 if (!wndPtr || wndPtr == WND_OTHER_PROCESS)
2024 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2025 return FALSE;
2027 winpos->hwnd = wndPtr->obj.handle; /* make it a full handle */
2029 /* Finally make sure that all coordinates are valid */
2030 if (winpos->x < -32768) winpos->x = -32768;
2031 else if (winpos->x > 32767) winpos->x = 32767;
2032 if (winpos->y < -32768) winpos->y = -32768;
2033 else if (winpos->y > 32767) winpos->y = 32767;
2035 if (winpos->cx < 0) winpos->cx = 0;
2036 else if (winpos->cx > 32767) winpos->cx = 32767;
2037 if (winpos->cy < 0) winpos->cy = 0;
2038 else if (winpos->cy > 32767) winpos->cy = 32767;
2040 parent = GetAncestor( winpos->hwnd, GA_PARENT );
2041 if (!IsWindowVisible( parent )) winpos->flags |= SWP_NOREDRAW;
2043 if (wndPtr->dwStyle & WS_VISIBLE) winpos->flags &= ~SWP_SHOWWINDOW;
2044 else
2046 winpos->flags &= ~SWP_HIDEWINDOW;
2047 if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
2050 if ((old_window_rect->right - old_window_rect->left == winpos->cx) &&
2051 (old_window_rect->bottom - old_window_rect->top == winpos->cy))
2052 winpos->flags |= SWP_NOSIZE; /* Already the right size */
2054 if ((old_window_rect->left - parent_x == winpos->x) && (old_window_rect->top - parent_y == winpos->y))
2055 winpos->flags |= SWP_NOMOVE; /* Already the right position */
2057 if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
2059 if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) && /* Bring to the top when activating */
2060 (winpos->flags & SWP_NOZORDER ||
2061 (winpos->hwndInsertAfter != HWND_TOPMOST && winpos->hwndInsertAfter != HWND_NOTOPMOST)))
2063 winpos->flags &= ~SWP_NOZORDER;
2064 winpos->hwndInsertAfter = HWND_TOP;
2068 /* Check hwndInsertAfter */
2069 if (winpos->flags & SWP_NOZORDER) goto done;
2071 if (winpos->hwndInsertAfter == HWND_TOP)
2073 if (GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
2074 winpos->flags |= SWP_NOZORDER;
2076 else if (winpos->hwndInsertAfter == HWND_BOTTOM)
2078 if (!(wndPtr->dwExStyle & WS_EX_TOPMOST) && GetWindow(winpos->hwnd, GW_HWNDLAST) == winpos->hwnd)
2079 winpos->flags |= SWP_NOZORDER;
2081 else if (winpos->hwndInsertAfter == HWND_TOPMOST)
2083 if ((wndPtr->dwExStyle & WS_EX_TOPMOST) && GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
2084 winpos->flags |= SWP_NOZORDER;
2086 else if (winpos->hwndInsertAfter == HWND_NOTOPMOST)
2088 if (!(wndPtr->dwExStyle & WS_EX_TOPMOST))
2089 winpos->flags |= SWP_NOZORDER;
2091 else
2093 if ((winpos->hwnd == winpos->hwndInsertAfter) ||
2094 (winpos->hwnd == GetWindow( winpos->hwndInsertAfter, GW_HWNDNEXT )))
2095 winpos->flags |= SWP_NOZORDER;
2097 done:
2098 WIN_ReleasePtr( wndPtr );
2099 return ret;
2103 /***********************************************************************
2104 * update_surface_region
2106 static void update_surface_region( HWND hwnd )
2108 NTSTATUS status;
2109 HRGN region = 0;
2110 RGNDATA *data;
2111 size_t size = 256;
2112 WND *win = WIN_GetPtr( hwnd );
2114 if (!win || win == WND_DESKTOP || win == WND_OTHER_PROCESS) return;
2115 if (!win->surface) goto done;
2119 if (!(data = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( RGNDATA, Buffer[size] )))) goto done;
2121 SERVER_START_REQ( get_surface_region )
2123 req->window = wine_server_user_handle( hwnd );
2124 wine_server_set_reply( req, data->Buffer, size );
2125 if (!(status = wine_server_call( req )))
2127 size_t reply_size = wine_server_reply_size( reply );
2128 if (reply_size)
2130 data->rdh.dwSize = sizeof(data->rdh);
2131 data->rdh.iType = RDH_RECTANGLES;
2132 data->rdh.nCount = reply_size / sizeof(RECT);
2133 data->rdh.nRgnSize = reply_size;
2134 region = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
2135 OffsetRgn( region, -reply->visible_rect.left, -reply->visible_rect.top );
2138 else size = reply->total_size;
2140 SERVER_END_REQ;
2141 HeapFree( GetProcessHeap(), 0, data );
2142 } while (status == STATUS_BUFFER_OVERFLOW);
2144 if (status) goto done;
2146 win->surface->funcs->set_region( win->surface, region );
2147 if (region) DeleteObject( region );
2149 done:
2150 WIN_ReleasePtr( win );
2154 /***********************************************************************
2155 * set_window_pos
2157 * Backend implementation of SetWindowPos.
2159 BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags,
2160 const RECT *window_rect, const RECT *client_rect, const RECT *valid_rects )
2162 WND *win;
2163 HWND surface_win = 0, parent = GetAncestor( hwnd, GA_PARENT );
2164 BOOL ret, needs_update = FALSE;
2165 RECT visible_rect, old_visible_rect, old_window_rect, old_client_rect, extra_rects[3];
2166 struct window_surface *old_surface, *new_surface = NULL;
2168 if (!parent || parent == GetDesktopWindow())
2170 new_surface = &dummy_surface; /* provide a default surface for top-level windows */
2171 window_surface_add_ref( new_surface );
2173 visible_rect = *window_rect;
2174 if (!(ret = USER_Driver->pWindowPosChanging( hwnd, insert_after, swp_flags,
2175 window_rect, client_rect, &visible_rect, &new_surface )))
2177 if (IsRectEmpty( window_rect )) visible_rect = *window_rect;
2178 else
2180 visible_rect = get_virtual_screen_rect();
2181 IntersectRect( &visible_rect, &visible_rect, window_rect );
2185 WIN_GetRectangles( hwnd, COORDS_SCREEN, &old_window_rect, NULL );
2186 if (IsRectEmpty( &valid_rects[0] )) valid_rects = NULL;
2188 if (!(win = WIN_GetPtr( hwnd )) || win == WND_DESKTOP || win == WND_OTHER_PROCESS)
2190 if (new_surface) window_surface_release( new_surface );
2191 return FALSE;
2194 /* create or update window surface for top-level windows if the driver doesn't implement WindowPosChanging */
2195 if (!ret && new_surface && !IsRectEmpty( &visible_rect ) &&
2196 (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
2197 NtUserGetLayeredWindowAttributes( hwnd, NULL, NULL, NULL )))
2199 window_surface_release( new_surface );
2200 if ((new_surface = win->surface)) window_surface_add_ref( new_surface );
2201 create_offscreen_window_surface( &visible_rect, &new_surface );
2204 old_visible_rect = win->visible_rect;
2205 old_client_rect = win->client_rect;
2206 old_surface = win->surface;
2207 if (old_surface != new_surface) swp_flags |= SWP_FRAMECHANGED; /* force refreshing non-client area */
2208 if (new_surface == &dummy_surface) swp_flags |= SWP_NOREDRAW;
2209 else if (old_surface == &dummy_surface)
2211 swp_flags |= SWP_NOCOPYBITS;
2212 valid_rects = NULL;
2215 SERVER_START_REQ( set_window_pos )
2217 req->handle = wine_server_user_handle( hwnd );
2218 req->previous = wine_server_user_handle( insert_after );
2219 req->swp_flags = swp_flags;
2220 req->window.left = window_rect->left;
2221 req->window.top = window_rect->top;
2222 req->window.right = window_rect->right;
2223 req->window.bottom = window_rect->bottom;
2224 req->client.left = client_rect->left;
2225 req->client.top = client_rect->top;
2226 req->client.right = client_rect->right;
2227 req->client.bottom = client_rect->bottom;
2228 if (!EqualRect( window_rect, &visible_rect ) || new_surface || valid_rects)
2230 extra_rects[0] = extra_rects[1] = visible_rect;
2231 if (new_surface)
2233 extra_rects[1] = new_surface->rect;
2234 OffsetRect( &extra_rects[1], visible_rect.left, visible_rect.top );
2236 if (valid_rects) extra_rects[2] = valid_rects[0];
2237 else SetRectEmpty( &extra_rects[2] );
2238 wine_server_add_data( req, extra_rects, sizeof(extra_rects) );
2240 if (new_surface) req->paint_flags |= SET_WINPOS_PAINT_SURFACE;
2241 if (win->pixel_format) req->paint_flags |= SET_WINPOS_PIXEL_FORMAT;
2243 if ((ret = !wine_server_call( req )))
2245 win->dwStyle = reply->new_style;
2246 win->dwExStyle = reply->new_ex_style;
2247 win->window_rect = *window_rect;
2248 win->client_rect = *client_rect;
2249 win->visible_rect = visible_rect;
2250 win->surface = new_surface;
2251 surface_win = wine_server_ptr_handle( reply->surface_win );
2252 needs_update = reply->needs_update;
2253 if (GetWindowLongW( win->parent, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL)
2255 RECT client;
2256 GetClientRect( win->parent, &client );
2257 mirror_rect( &client, &win->window_rect );
2258 mirror_rect( &client, &win->client_rect );
2259 mirror_rect( &client, &win->visible_rect );
2261 /* if an RTL window is resized the children have moved */
2262 if (win->dwExStyle & WS_EX_LAYOUTRTL &&
2263 client_rect->right - client_rect->left != old_client_rect.right - old_client_rect.left)
2264 win->flags |= WIN_CHILDREN_MOVED;
2267 SERVER_END_REQ;
2269 if (ret)
2271 if (needs_update) update_surface_region( surface_win );
2272 if (((swp_flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) ||
2273 (swp_flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW | SWP_STATECHANGED | SWP_FRAMECHANGED)))
2274 invalidate_dce( win, &old_window_rect );
2277 WIN_ReleasePtr( win );
2279 if (ret)
2281 TRACE( "win %p surface %p -> %p\n", hwnd, old_surface, new_surface );
2282 register_window_surface( old_surface, new_surface );
2283 if (old_surface)
2285 if (valid_rects)
2287 move_window_bits( hwnd, old_surface, new_surface, &visible_rect,
2288 &old_visible_rect, window_rect, valid_rects );
2289 valid_rects = NULL; /* prevent the driver from trying to also move the bits */
2291 window_surface_release( old_surface );
2293 else if (surface_win && surface_win != hwnd)
2295 if (valid_rects)
2297 RECT rects[2];
2298 int x_offset = old_visible_rect.left - visible_rect.left;
2299 int y_offset = old_visible_rect.top - visible_rect.top;
2301 /* if all that happened is that the whole window moved, copy everything */
2302 if (!(swp_flags & SWP_FRAMECHANGED) &&
2303 old_visible_rect.right - visible_rect.right == x_offset &&
2304 old_visible_rect.bottom - visible_rect.bottom == y_offset &&
2305 old_client_rect.left - client_rect->left == x_offset &&
2306 old_client_rect.right - client_rect->right == x_offset &&
2307 old_client_rect.top - client_rect->top == y_offset &&
2308 old_client_rect.bottom - client_rect->bottom == y_offset &&
2309 EqualRect( &valid_rects[0], client_rect ))
2311 rects[0] = visible_rect;
2312 rects[1] = old_visible_rect;
2313 valid_rects = rects;
2315 move_window_bits_parent( hwnd, surface_win, window_rect, valid_rects );
2316 valid_rects = NULL; /* prevent the driver from trying to also move the bits */
2320 USER_Driver->pWindowPosChanged( hwnd, insert_after, swp_flags, window_rect,
2321 client_rect, &visible_rect, valid_rects, new_surface );
2323 else if (new_surface) window_surface_release( new_surface );
2325 return ret;
2329 /***********************************************************************
2330 * USER_SetWindowPos
2332 * User32 internal function
2334 BOOL USER_SetWindowPos( WINDOWPOS * winpos, int parent_x, int parent_y )
2336 RECT old_window_rect, old_client_rect, new_window_rect, new_client_rect, valid_rects[2];
2337 UINT orig_flags;
2338 BOOL ret = FALSE;
2339 DPI_AWARENESS_CONTEXT context;
2341 orig_flags = winpos->flags;
2343 /* First, check z-order arguments. */
2344 if (!(winpos->flags & SWP_NOZORDER))
2346 /* fix sign extension */
2347 if (winpos->hwndInsertAfter == (HWND)0xffff) winpos->hwndInsertAfter = HWND_TOPMOST;
2348 else if (winpos->hwndInsertAfter == (HWND)0xfffe) winpos->hwndInsertAfter = HWND_NOTOPMOST;
2350 if (!(winpos->hwndInsertAfter == HWND_TOP ||
2351 winpos->hwndInsertAfter == HWND_BOTTOM ||
2352 winpos->hwndInsertAfter == HWND_TOPMOST ||
2353 winpos->hwndInsertAfter == HWND_NOTOPMOST))
2355 HWND parent = GetAncestor( winpos->hwnd, GA_PARENT );
2356 HWND insertafter_parent = GetAncestor( winpos->hwndInsertAfter, GA_PARENT );
2358 /* hwndInsertAfter must be a sibling of the window */
2359 if (!insertafter_parent) return FALSE;
2360 if (insertafter_parent != parent) return TRUE;
2364 /* Make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
2365 if (!(winpos->flags & SWP_NOMOVE))
2367 if (winpos->x < -32768) winpos->x = -32768;
2368 else if (winpos->x > 32767) winpos->x = 32767;
2369 if (winpos->y < -32768) winpos->y = -32768;
2370 else if (winpos->y > 32767) winpos->y = 32767;
2372 if (!(winpos->flags & SWP_NOSIZE))
2374 if (winpos->cx < 0) winpos->cx = 0;
2375 else if (winpos->cx > 32767) winpos->cx = 32767;
2376 if (winpos->cy < 0) winpos->cy = 0;
2377 else if (winpos->cy > 32767) winpos->cy = 32767;
2380 context = SetThreadDpiAwarenessContext( GetWindowDpiAwarenessContext( winpos->hwnd ));
2382 if (!SWP_DoWinPosChanging( winpos, &old_window_rect, &old_client_rect,
2383 &new_window_rect, &new_client_rect )) goto done;
2385 /* Fix redundant flags */
2386 if (!fixup_flags( winpos, &old_window_rect, parent_x, parent_y )) goto done;
2388 if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
2390 if (GetAncestor( winpos->hwnd, GA_PARENT ) == GetDesktopWindow())
2391 winpos->hwndInsertAfter = SWP_DoOwnedPopups( winpos->hwnd, winpos->hwndInsertAfter );
2394 /* Common operations */
2396 SWP_DoNCCalcSize( winpos, &old_window_rect, &old_client_rect,
2397 &new_window_rect, &new_client_rect, valid_rects, parent_x, parent_y );
2399 if (!set_window_pos( winpos->hwnd, winpos->hwndInsertAfter, winpos->flags,
2400 &new_window_rect, &new_client_rect, valid_rects ))
2401 goto done;
2404 if( winpos->flags & SWP_HIDEWINDOW )
2405 HideCaret(winpos->hwnd);
2406 else if (winpos->flags & SWP_SHOWWINDOW)
2407 ShowCaret(winpos->hwnd);
2409 if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
2411 /* child windows get WM_CHILDACTIVATE message */
2412 if ((GetWindowLongW( winpos->hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2413 SendMessageW( winpos->hwnd, WM_CHILDACTIVATE, 0, 0 );
2414 else
2415 SetForegroundWindow( winpos->hwnd );
2418 if(!(orig_flags & SWP_DEFERERASE))
2420 /* erase parent when hiding or resizing child */
2421 if ((orig_flags & SWP_HIDEWINDOW) ||
2422 (!(orig_flags & SWP_SHOWWINDOW) &&
2423 (winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE))
2425 HWND parent = GetAncestor( winpos->hwnd, GA_PARENT );
2426 if (!parent || parent == GetDesktopWindow()) parent = winpos->hwnd;
2427 erase_now( parent, 0 );
2430 /* Give newly shown windows a chance to redraw */
2431 if(((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2432 && !(orig_flags & SWP_AGG_NOCLIENTCHANGE) && (orig_flags & SWP_SHOWWINDOW))
2434 erase_now(winpos->hwnd, 0);
2438 /* And last, send the WM_WINDOWPOSCHANGED message */
2440 TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
2442 if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
2443 && !((orig_flags & SWP_AGG_NOCLIENTCHANGE) && (orig_flags & SWP_SHOWWINDOW)))
2445 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
2446 and always contains final window position.
2448 winpos->x = new_window_rect.left;
2449 winpos->y = new_window_rect.top;
2450 winpos->cx = new_window_rect.right - new_window_rect.left;
2451 winpos->cy = new_window_rect.bottom - new_window_rect.top;
2452 SendMessageW( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
2454 ret = TRUE;
2455 done:
2456 SetThreadDpiAwarenessContext( context );
2457 return ret;
2460 /***********************************************************************
2461 * SetWindowPos (USER32.@)
2463 BOOL WINAPI SetWindowPos( HWND hwnd, HWND hwndInsertAfter,
2464 INT x, INT y, INT cx, INT cy, UINT flags )
2466 WINDOWPOS winpos;
2468 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2469 hwnd, hwndInsertAfter, x, y, cx, cy, flags);
2470 if(TRACE_ON(win)) dump_winpos_flags(flags);
2472 if (is_broadcast(hwnd))
2474 SetLastError( ERROR_INVALID_PARAMETER );
2475 return FALSE;
2478 winpos.hwnd = WIN_GetFullHandle(hwnd);
2479 winpos.hwndInsertAfter = WIN_GetFullHandle(hwndInsertAfter);
2480 winpos.x = x;
2481 winpos.y = y;
2482 winpos.cx = cx;
2483 winpos.cy = cy;
2484 winpos.flags = flags;
2486 map_dpi_winpos( &winpos );
2488 if (WIN_IsCurrentThread( hwnd ))
2489 return USER_SetWindowPos( &winpos, 0, 0 );
2491 if (flags & SWP_ASYNCWINDOWPOS)
2492 return SendNotifyMessageW( winpos.hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)&winpos );
2493 else
2494 return SendMessageW( winpos.hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)&winpos );
2498 /***********************************************************************
2499 * BeginDeferWindowPos (USER32.@)
2501 HDWP WINAPI BeginDeferWindowPos( INT count )
2503 HDWP handle = 0;
2504 DWP *pDWP;
2506 TRACE("%d\n", count);
2508 if (count < 0)
2510 SetLastError(ERROR_INVALID_PARAMETER);
2511 return 0;
2513 /* Windows allows zero count, in which case it allocates context for 8 moves */
2514 if (count == 0) count = 8;
2516 if (!(pDWP = HeapAlloc( GetProcessHeap(), 0, sizeof(DWP)))) return 0;
2518 pDWP->actualCount = 0;
2519 pDWP->suggestedCount = count;
2520 pDWP->hwndParent = 0;
2522 if (!(pDWP->winPos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WINDOWPOS) )) ||
2523 !(handle = alloc_user_handle( &pDWP->obj, USER_DWP )))
2525 HeapFree( GetProcessHeap(), 0, pDWP->winPos );
2526 HeapFree( GetProcessHeap(), 0, pDWP );
2529 TRACE("returning hdwp %p\n", handle);
2530 return handle;
2534 /***********************************************************************
2535 * DeferWindowPos (USER32.@)
2537 HDWP WINAPI DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter,
2538 INT x, INT y, INT cx, INT cy,
2539 UINT flags )
2541 DWP *pDWP;
2542 int i;
2543 HDWP retvalue = hdwp;
2544 WINDOWPOS winpos;
2546 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2547 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2549 winpos.hwnd = WIN_GetFullHandle( hwnd );
2550 if (is_desktop_window( winpos.hwnd ) || !IsWindow( winpos.hwnd ))
2552 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2553 return 0;
2556 winpos.hwndInsertAfter = WIN_GetFullHandle(hwndAfter);
2557 winpos.flags = flags;
2558 winpos.x = x;
2559 winpos.y = y;
2560 winpos.cx = cx;
2561 winpos.cy = cy;
2562 map_dpi_winpos( &winpos );
2564 if (!(pDWP = get_user_handle_ptr( hdwp, USER_DWP ))) return 0;
2565 if (pDWP == OBJ_OTHER_PROCESS)
2567 FIXME( "other process handle %p?\n", hdwp );
2568 return 0;
2571 for (i = 0; i < pDWP->actualCount; i++)
2573 if (pDWP->winPos[i].hwnd == winpos.hwnd)
2575 /* Merge with the other changes */
2576 if (!(flags & SWP_NOZORDER))
2578 pDWP->winPos[i].hwndInsertAfter = winpos.hwndInsertAfter;
2580 if (!(flags & SWP_NOMOVE))
2582 pDWP->winPos[i].x = winpos.x;
2583 pDWP->winPos[i].y = winpos.y;
2585 if (!(flags & SWP_NOSIZE))
2587 pDWP->winPos[i].cx = winpos.cx;
2588 pDWP->winPos[i].cy = winpos.cy;
2590 pDWP->winPos[i].flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2591 SWP_NOZORDER | SWP_NOREDRAW |
2592 SWP_NOACTIVATE | SWP_NOCOPYBITS|
2593 SWP_NOOWNERZORDER);
2594 pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2595 SWP_FRAMECHANGED);
2596 goto END;
2599 if (pDWP->actualCount >= pDWP->suggestedCount)
2601 WINDOWPOS *newpos = HeapReAlloc( GetProcessHeap(), 0, pDWP->winPos,
2602 pDWP->suggestedCount * 2 * sizeof(WINDOWPOS) );
2603 if (!newpos)
2605 retvalue = 0;
2606 goto END;
2608 pDWP->suggestedCount *= 2;
2609 pDWP->winPos = newpos;
2611 pDWP->winPos[pDWP->actualCount++] = winpos;
2612 END:
2613 release_user_handle_ptr( pDWP );
2614 return retvalue;
2618 /***********************************************************************
2619 * EndDeferWindowPos (USER32.@)
2621 BOOL WINAPI EndDeferWindowPos( HDWP hdwp )
2623 DWP *pDWP;
2624 WINDOWPOS *winpos;
2625 int i;
2627 TRACE("%p\n", hdwp);
2629 if (!(pDWP = free_user_handle( hdwp, USER_DWP ))) return FALSE;
2630 if (pDWP == OBJ_OTHER_PROCESS)
2632 FIXME( "other process handle %p?\n", hdwp );
2633 return FALSE;
2636 for (i = 0, winpos = pDWP->winPos; i < pDWP->actualCount; i++, winpos++)
2638 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2639 winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
2640 winpos->cx, winpos->cy, winpos->flags);
2642 if (WIN_IsCurrentThread( winpos->hwnd ))
2643 USER_SetWindowPos( winpos, 0, 0 );
2644 else
2645 SendMessageW( winpos->hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)winpos );
2647 HeapFree( GetProcessHeap(), 0, pDWP->winPos );
2648 HeapFree( GetProcessHeap(), 0, pDWP );
2649 return TRUE;
2653 /***********************************************************************
2654 * ArrangeIconicWindows (USER32.@)
2656 UINT WINAPI ArrangeIconicWindows( HWND parent )
2658 int width, height, count = 0;
2659 RECT rectParent;
2660 HWND hwndChild;
2661 POINT pt;
2662 MINIMIZEDMETRICS metrics;
2664 metrics.cbSize = sizeof(metrics);
2665 SystemParametersInfoW( SPI_GETMINIMIZEDMETRICS, sizeof(metrics), &metrics, 0 );
2666 width = GetSystemMetrics( SM_CXMINIMIZED );
2667 height = GetSystemMetrics( SM_CYMINIMIZED );
2669 if (parent == GetDesktopWindow())
2671 MONITORINFO mon_info;
2672 HMONITOR monitor = MonitorFromWindow( 0, MONITOR_DEFAULTTOPRIMARY );
2674 mon_info.cbSize = sizeof( mon_info );
2675 GetMonitorInfoW( monitor, &mon_info );
2676 rectParent = mon_info.rcWork;
2678 else GetClientRect( parent, &rectParent );
2680 pt = get_first_minimized_child_pos( &rectParent, &metrics, width, height );
2682 hwndChild = GetWindow( parent, GW_CHILD );
2683 while (hwndChild)
2685 if( IsIconic( hwndChild ) )
2687 SetWindowPos( hwndChild, 0, pt.x, pt.y, 0, 0,
2688 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
2689 get_next_minimized_child_pos( &rectParent, &metrics, width, height, &pt );
2690 count++;
2692 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
2694 return count;
2698 /***********************************************************************
2699 * draw_moving_frame
2701 * Draw the frame used when moving or resizing window.
2703 static void draw_moving_frame( HWND parent, HDC hdc, RECT *screen_rect, BOOL thickframe )
2705 RECT rect = *screen_rect;
2707 if (parent) MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
2708 if (thickframe)
2710 const int width = GetSystemMetrics(SM_CXFRAME);
2711 const int height = GetSystemMetrics(SM_CYFRAME);
2713 HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
2714 PatBlt( hdc, rect.left, rect.top,
2715 rect.right - rect.left - width, height, PATINVERT );
2716 PatBlt( hdc, rect.left, rect.top + height, width,
2717 rect.bottom - rect.top - height, PATINVERT );
2718 PatBlt( hdc, rect.left + width, rect.bottom - 1,
2719 rect.right - rect.left - width, -height, PATINVERT );
2720 PatBlt( hdc, rect.right - 1, rect.top, -width,
2721 rect.bottom - rect.top - height, PATINVERT );
2722 SelectObject( hdc, hbrush );
2724 else DrawFocusRect( hdc, &rect );
2728 /***********************************************************************
2729 * start_size_move
2731 * Initialization of a move or resize, when initiated from a menu choice.
2732 * Return hit test code for caption or sizing border.
2734 static LONG start_size_move( HWND hwnd, WPARAM wParam, POINT *capturePoint, LONG style )
2736 LONG hittest = 0;
2737 POINT pt;
2738 MSG msg;
2739 RECT rectWindow;
2741 GetWindowRect( hwnd, &rectWindow );
2743 if ((wParam & 0xfff0) == SC_MOVE)
2745 /* Move pointer at the center of the caption */
2746 RECT rect = rectWindow;
2747 /* Note: to be exactly centered we should take the different types
2748 * of border into account, but it shouldn't make more than a few pixels
2749 * of difference so let's not bother with that */
2750 rect.top += GetSystemMetrics(SM_CYBORDER);
2751 if (style & WS_SYSMENU)
2752 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
2753 if (style & WS_MINIMIZEBOX)
2754 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
2755 if (style & WS_MAXIMIZEBOX)
2756 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
2757 pt.x = (rect.right + rect.left) / 2;
2758 pt.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
2759 hittest = HTCAPTION;
2760 *capturePoint = pt;
2762 else /* SC_SIZE */
2764 SetCursor( LoadCursorW( 0, (LPWSTR)IDC_SIZEALL ) );
2765 pt.x = pt.y = 0;
2766 while(!hittest)
2768 if (!GetMessageW( &msg, 0, 0, 0 )) return 0;
2769 if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
2771 switch(msg.message)
2773 case WM_MOUSEMOVE:
2774 pt.x = min( max( msg.pt.x, rectWindow.left ), rectWindow.right - 1 );
2775 pt.y = min( max( msg.pt.y, rectWindow.top ), rectWindow.bottom - 1 );
2776 hittest = SendMessageW( hwnd, WM_NCHITTEST, 0, MAKELONG( pt.x, pt.y ) );
2777 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) hittest = 0;
2778 break;
2780 case WM_LBUTTONUP:
2781 return 0;
2783 case WM_KEYDOWN:
2784 switch(msg.wParam)
2786 case VK_UP:
2787 hittest = HTTOP;
2788 pt.x =(rectWindow.left+rectWindow.right)/2;
2789 pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
2790 break;
2791 case VK_DOWN:
2792 hittest = HTBOTTOM;
2793 pt.x =(rectWindow.left+rectWindow.right)/2;
2794 pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
2795 break;
2796 case VK_LEFT:
2797 hittest = HTLEFT;
2798 pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
2799 pt.y =(rectWindow.top+rectWindow.bottom)/2;
2800 break;
2801 case VK_RIGHT:
2802 hittest = HTRIGHT;
2803 pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
2804 pt.y =(rectWindow.top+rectWindow.bottom)/2;
2805 break;
2806 case VK_RETURN:
2807 case VK_ESCAPE:
2808 return 0;
2810 break;
2811 default:
2812 TranslateMessage( &msg );
2813 DispatchMessageW( &msg );
2814 break;
2817 *capturePoint = pt;
2819 SetCursorPos( pt.x, pt.y );
2820 SendMessageW( hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
2821 return hittest;
2825 /***********************************************************************
2826 * WINPOS_SysCommandSizeMove
2828 * Perform SC_MOVE and SC_SIZE commands.
2830 void WINPOS_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
2832 MSG msg;
2833 RECT sizingRect, mouseRect, origRect;
2834 HDC hdc;
2835 HWND parent;
2836 LONG hittest = (LONG)(wParam & 0x0f);
2837 WPARAM syscommand = wParam & 0xfff0;
2838 MINMAXINFO minmax;
2839 POINT capturePoint, pt;
2840 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2841 BOOL thickframe = HAS_THICKFRAME( style );
2842 BOOL moved = FALSE;
2843 DWORD dwPoint = GetMessagePos ();
2844 BOOL DragFullWindows = TRUE;
2845 HMONITOR mon = 0;
2847 if (IsZoomed(hwnd) || !IsWindowVisible(hwnd)) return;
2849 pt.x = (short)LOWORD(dwPoint);
2850 pt.y = (short)HIWORD(dwPoint);
2851 capturePoint = pt;
2852 ClipCursor( NULL );
2854 TRACE("hwnd %p command %04lx, hittest %d, pos %d,%d\n",
2855 hwnd, syscommand, hittest, pt.x, pt.y);
2857 if (syscommand == SC_MOVE)
2859 if (!hittest) hittest = start_size_move( hwnd, wParam, &capturePoint, style );
2860 if (!hittest) return;
2862 else /* SC_SIZE */
2864 if ( hittest && (syscommand != SC_MOUSEMENU) )
2865 hittest += (HTLEFT - WMSZ_LEFT);
2866 else
2868 set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
2869 hittest = start_size_move( hwnd, wParam, &capturePoint, style );
2870 if (!hittest)
2872 set_capture_window( 0, GUI_INMOVESIZE, NULL );
2873 return;
2878 /* Get min/max info */
2880 minmax = WINPOS_GetMinMaxInfo( hwnd );
2881 WIN_GetRectangles( hwnd, COORDS_PARENT, &sizingRect, NULL );
2882 origRect = sizingRect;
2883 if (style & WS_CHILD)
2885 parent = GetParent(hwnd);
2886 GetClientRect( parent, &mouseRect );
2887 MapWindowPoints( parent, 0, (LPPOINT)&mouseRect, 2 );
2888 MapWindowPoints( parent, 0, (LPPOINT)&sizingRect, 2 );
2890 else
2892 parent = 0;
2893 mouseRect = get_virtual_screen_rect();
2894 mon = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
2897 if (ON_LEFT_BORDER(hittest))
2899 mouseRect.left = max( mouseRect.left, sizingRect.right-minmax.ptMaxTrackSize.x+capturePoint.x-sizingRect.left );
2900 mouseRect.right = min( mouseRect.right, sizingRect.right-minmax.ptMinTrackSize.x+capturePoint.x-sizingRect.left );
2902 else if (ON_RIGHT_BORDER(hittest))
2904 mouseRect.left = max( mouseRect.left, sizingRect.left+minmax.ptMinTrackSize.x+capturePoint.x-sizingRect.right );
2905 mouseRect.right = min( mouseRect.right, sizingRect.left+minmax.ptMaxTrackSize.x+capturePoint.x-sizingRect.right );
2907 if (ON_TOP_BORDER(hittest))
2909 mouseRect.top = max( mouseRect.top, sizingRect.bottom-minmax.ptMaxTrackSize.y+capturePoint.y-sizingRect.top );
2910 mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minmax.ptMinTrackSize.y+capturePoint.y-sizingRect.top);
2912 else if (ON_BOTTOM_BORDER(hittest))
2914 mouseRect.top = max( mouseRect.top, sizingRect.top+minmax.ptMinTrackSize.y+capturePoint.y-sizingRect.bottom );
2915 mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+minmax.ptMaxTrackSize.y+capturePoint.y-sizingRect.bottom );
2918 /* Retrieve a default cache DC (without using the window style) */
2919 hdc = GetDCEx( parent, 0, DCX_CACHE );
2921 /* we only allow disabling the full window drag for child windows */
2922 if (parent) SystemParametersInfoW( SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0 );
2924 /* repaint the window before moving it around */
2925 RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
2927 SendMessageW( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
2928 set_capture_window( hwnd, GUI_INMOVESIZE, NULL );
2930 while(1)
2932 int dx = 0, dy = 0;
2934 if (!GetMessageW( &msg, 0, 0, 0 )) break;
2935 if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
2937 /* Exit on button-up, Return, or Esc */
2938 if ((msg.message == WM_LBUTTONUP) ||
2939 ((msg.message == WM_KEYDOWN) &&
2940 ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
2942 if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
2944 TranslateMessage( &msg );
2945 DispatchMessageW( &msg );
2946 continue; /* We are not interested in other messages */
2949 pt = msg.pt;
2951 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
2953 case VK_UP: pt.y -= 8; break;
2954 case VK_DOWN: pt.y += 8; break;
2955 case VK_LEFT: pt.x -= 8; break;
2956 case VK_RIGHT: pt.x += 8; break;
2959 pt.x = max( pt.x, mouseRect.left );
2960 pt.x = min( pt.x, mouseRect.right - 1 );
2961 pt.y = max( pt.y, mouseRect.top );
2962 pt.y = min( pt.y, mouseRect.bottom - 1 );
2964 if (!parent)
2966 HMONITOR newmon;
2967 MONITORINFO info;
2969 if ((newmon = MonitorFromPoint( pt, MONITOR_DEFAULTTONULL )))
2970 mon = newmon;
2972 info.cbSize = sizeof(info);
2973 if (mon && GetMonitorInfoW( mon, &info ))
2975 pt.x = max( pt.x, info.rcWork.left );
2976 pt.x = min( pt.x, info.rcWork.right - 1 );
2977 pt.y = max( pt.y, info.rcWork.top );
2978 pt.y = min( pt.y, info.rcWork.bottom - 1 );
2982 dx = pt.x - capturePoint.x;
2983 dy = pt.y - capturePoint.y;
2985 if (dx || dy)
2987 if( !moved )
2989 moved = TRUE;
2990 if (!DragFullWindows)
2991 draw_moving_frame( parent, hdc, &sizingRect, thickframe );
2994 if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
2995 else
2997 if (!DragFullWindows) draw_moving_frame( parent, hdc, &sizingRect, thickframe );
2998 if (hittest == HTCAPTION || hittest == HTBORDER) OffsetRect( &sizingRect, dx, dy );
2999 if (ON_LEFT_BORDER(hittest)) sizingRect.left += dx;
3000 else if (ON_RIGHT_BORDER(hittest)) sizingRect.right += dx;
3001 if (ON_TOP_BORDER(hittest)) sizingRect.top += dy;
3002 else if (ON_BOTTOM_BORDER(hittest)) sizingRect.bottom += dy;
3003 capturePoint = pt;
3005 /* determine the hit location */
3006 if (syscommand == SC_SIZE && hittest != HTBORDER)
3008 WPARAM wpSizingHit = 0;
3010 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
3011 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
3012 SendMessageW( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&sizingRect );
3014 else
3015 SendMessageW( hwnd, WM_MOVING, 0, (LPARAM)&sizingRect );
3017 if (!DragFullWindows)
3018 draw_moving_frame( parent, hdc, &sizingRect, thickframe );
3019 else
3021 RECT rect = sizingRect;
3022 MapWindowPoints( 0, parent, (POINT *)&rect, 2 );
3023 SetWindowPos( hwnd, 0, rect.left, rect.top,
3024 rect.right - rect.left, rect.bottom - rect.top,
3025 (hittest == HTCAPTION) ? SWP_NOSIZE : 0 );
3031 if (moved && !DragFullWindows)
3033 draw_moving_frame( parent, hdc, &sizingRect, thickframe );
3036 set_capture_window( 0, GUI_INMOVESIZE, NULL );
3037 ReleaseDC( parent, hdc );
3038 if (parent) MapWindowPoints( 0, parent, (POINT *)&sizingRect, 2 );
3040 if (HOOK_CallHooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect, TRUE ))
3041 moved = FALSE;
3043 SendMessageW( hwnd, WM_EXITSIZEMOVE, 0, 0 );
3044 SendMessageW( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
3046 /* window moved or resized */
3047 if (moved)
3049 /* if the moving/resizing isn't canceled call SetWindowPos
3050 * with the new position or the new size of the window
3052 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
3054 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
3055 if (!DragFullWindows)
3056 SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
3057 sizingRect.right - sizingRect.left,
3058 sizingRect.bottom - sizingRect.top,
3059 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
3061 else
3062 { /* restore previous size/position */
3063 if(DragFullWindows)
3064 SetWindowPos( hwnd, 0, origRect.left, origRect.top,
3065 origRect.right - origRect.left,
3066 origRect.bottom - origRect.top,
3067 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
3071 if (IsIconic(hwnd))
3073 /* Single click brings up the system menu when iconized */
3075 if( !moved )
3077 if(style & WS_SYSMENU )
3078 SendMessageW( hwnd, WM_SYSCOMMAND,
3079 SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));