Changes in crossover-wine-src-6.1.0 except for configure
[wine/hacks.git] / dlls / user32 / winpos.c
blob554e232b358a2f61843188d206100b40a1db7635
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 "winerror.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winerror.h"
34 #include "wine/winuser16.h"
35 #include "wine/server.h"
36 #include "controls.h"
37 #include "user_private.h"
38 #include "win.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(win);
43 #define SWP_AGG_NOGEOMETRYCHANGE \
44 (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER)
45 #define SWP_AGG_NOPOSCHANGE \
46 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
47 #define SWP_AGG_STATUSFLAGS \
48 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
50 #define HAS_DLGFRAME(style,exStyle) \
51 (((exStyle) & WS_EX_DLGMODALFRAME) || \
52 (((style) & WS_DLGFRAME) && !((style) & WS_BORDER)))
54 #define HAS_THICKFRAME(style) \
55 (((style) & WS_THICKFRAME) && \
56 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
58 #define EMPTYPOINT(pt) ((*(LONG*)&(pt)) == -1)
60 #define PLACE_MIN 0x0001
61 #define PLACE_MAX 0x0002
62 #define PLACE_RECT 0x0004
65 #define DWP_MAGIC ((INT)('W' | ('P' << 8) | ('O' << 16) | ('S' << 24)))
67 typedef struct
69 INT actualCount;
70 INT suggestedCount;
71 BOOL valid;
72 INT wMagic;
73 HWND hwndParent;
74 WINDOWPOS winPos[1];
75 } DWP;
77 typedef struct
79 RECT16 rectNormal;
80 POINT16 ptIconPos;
81 POINT16 ptMaxPos;
82 HWND hwndIconTitle;
83 } INTERNALPOS, *LPINTERNALPOS;
85 /* ----- internal functions ----- */
87 static const WCHAR SysIP_W[] = { 'S','y','s','I','P',0 };
89 static inline INTERNALPOS *get_internal_pos( HWND hwnd )
91 return GetPropW( hwnd, SysIP_W );
94 static inline void set_internal_pos( HWND hwnd, INTERNALPOS *pos )
96 SetPropW( hwnd, SysIP_W, pos );
99 /***********************************************************************
100 * WINPOS_CheckInternalPos
102 * Called when a window is destroyed.
104 void WINPOS_CheckInternalPos( HWND hwnd )
106 LPINTERNALPOS lpPos = get_internal_pos( hwnd );
108 if ( lpPos )
110 if( IsWindow(lpPos->hwndIconTitle) )
111 DestroyWindow( lpPos->hwndIconTitle );
112 HeapFree( GetProcessHeap(), 0, lpPos );
116 /***********************************************************************
117 * ArrangeIconicWindows (USER32.@)
119 UINT WINAPI ArrangeIconicWindows( HWND parent )
121 RECT rectParent;
122 HWND hwndChild;
123 INT x, y, xspacing, yspacing;
125 GetClientRect( parent, &rectParent );
126 x = rectParent.left;
127 y = rectParent.bottom;
128 xspacing = GetSystemMetrics(SM_CXICONSPACING);
129 yspacing = GetSystemMetrics(SM_CYICONSPACING);
131 hwndChild = GetWindow( parent, GW_CHILD );
132 while (hwndChild)
134 if( IsIconic( hwndChild ) )
136 WINPOS_ShowIconTitle( hwndChild, FALSE );
138 SetWindowPos( hwndChild, 0, x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2,
139 y - yspacing - GetSystemMetrics(SM_CYICON)/2, 0, 0,
140 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
141 if( IsWindow(hwndChild) )
142 WINPOS_ShowIconTitle(hwndChild , TRUE );
144 if (x <= rectParent.right - xspacing) x += xspacing;
145 else
147 x = rectParent.left;
148 y -= yspacing;
151 hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
153 return yspacing;
157 /***********************************************************************
158 * SwitchToThisWindow (USER32.@)
160 void WINAPI SwitchToThisWindow( HWND hwnd, BOOL restore )
162 ShowWindow( hwnd, restore ? SW_RESTORE : SW_SHOWMINIMIZED );
166 /***********************************************************************
167 * GetWindowRect (USER32.@)
169 BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect )
171 BOOL ret = WIN_GetRectangles( hwnd, rect, NULL );
172 if (ret)
174 MapWindowPoints( GetAncestor( hwnd, GA_PARENT ), 0, (POINT *)rect, 2 );
175 TRACE( "hwnd %p (%d,%d)-(%d,%d)\n",
176 hwnd, rect->left, rect->top, rect->right, rect->bottom);
178 return ret;
182 /***********************************************************************
183 * GetWindowRgn (USER32.@)
185 int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn )
187 int nRet = ERROR;
188 NTSTATUS status;
189 HRGN win_rgn = 0;
190 RGNDATA *data;
191 size_t size = 256;
195 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 )))
197 SetLastError( ERROR_OUTOFMEMORY );
198 return ERROR;
200 SERVER_START_REQ( get_window_region )
202 req->window = hwnd;
203 wine_server_set_reply( req, data->Buffer, size );
204 if (!(status = wine_server_call( req )))
206 size_t reply_size = wine_server_reply_size( reply );
207 if (reply_size)
209 data->rdh.dwSize = sizeof(data->rdh);
210 data->rdh.iType = RDH_RECTANGLES;
211 data->rdh.nCount = reply_size / sizeof(RECT);
212 data->rdh.nRgnSize = reply_size;
213 win_rgn = ExtCreateRegion( NULL, size, data );
216 else size = reply->total_size;
218 SERVER_END_REQ;
219 HeapFree( GetProcessHeap(), 0, data );
220 } while (status == STATUS_BUFFER_OVERFLOW);
222 if (status) SetLastError( RtlNtStatusToDosError(status) );
223 else if (win_rgn)
225 nRet = CombineRgn( hrgn, win_rgn, 0, RGN_COPY );
226 DeleteObject( win_rgn );
228 return nRet;
232 /***********************************************************************
233 * SetWindowRgn (USER32.@)
235 int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw )
237 static const RECT empty_rect;
238 BOOL ret;
240 if (hrgn)
242 RGNDATA *data;
243 DWORD size;
245 if (!(size = GetRegionData( hrgn, 0, NULL ))) return FALSE;
246 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
247 if (!GetRegionData( hrgn, size, data ))
249 HeapFree( GetProcessHeap(), 0, data );
250 return FALSE;
252 SERVER_START_REQ( set_window_region )
254 req->window = hwnd;
255 req->redraw = (bRedraw != 0);
256 if (data->rdh.nCount)
257 wine_server_add_data( req, data->Buffer, data->rdh.nCount * sizeof(RECT) );
258 else
259 wine_server_add_data( req, &empty_rect, sizeof(empty_rect) );
260 ret = !wine_server_call_err( req );
262 SERVER_END_REQ;
264 else /* clear existing region */
266 SERVER_START_REQ( set_window_region )
268 req->window = hwnd;
269 req->redraw = (bRedraw != 0);
270 ret = !wine_server_call_err( req );
272 SERVER_END_REQ;
275 if (ret) ret = USER_Driver->pSetWindowRgn( hwnd, hrgn, bRedraw );
277 if (ret)
279 UINT swp_flags = SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED;
280 if (hrgn) swp_flags |= SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE;
281 if (!bRedraw) swp_flags |= SWP_NOREDRAW;
282 SetWindowPos( hwnd, 0, 0, 0, 0, 0, swp_flags );
284 return ret;
288 /***********************************************************************
289 * GetClientRect (USER32.@)
291 BOOL WINAPI GetClientRect( HWND hwnd, LPRECT rect )
293 BOOL ret;
295 if ((ret = WIN_GetRectangles( hwnd, NULL, rect )))
297 rect->right -= rect->left;
298 rect->bottom -= rect->top;
299 rect->left = rect->top = 0;
301 return ret;
305 /*******************************************************************
306 * ClientToScreen (USER32.@)
308 BOOL WINAPI ClientToScreen( HWND hwnd, LPPOINT lppnt )
310 MapWindowPoints( hwnd, 0, lppnt, 1 );
311 return TRUE;
315 /*******************************************************************
316 * ScreenToClient (USER32.@)
318 BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
320 MapWindowPoints( 0, hwnd, lppnt, 1 );
321 return TRUE;
325 /***********************************************************************
326 * list_children_from_point
328 * Get the list of children that can contain point from the server.
329 * Point is in screen coordinates.
330 * Returned list must be freed by caller.
332 static HWND *list_children_from_point( HWND hwnd, POINT pt )
334 HWND *list;
335 int size = 32;
337 for (;;)
339 int count = 0;
341 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
343 SERVER_START_REQ( get_window_children_from_point )
345 req->parent = hwnd;
346 req->x = pt.x;
347 req->y = pt.y;
348 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
349 if (!wine_server_call( req )) count = reply->count;
351 SERVER_END_REQ;
352 if (count && count < size)
354 list[count] = 0;
355 return list;
357 HeapFree( GetProcessHeap(), 0, list );
358 if (!count) break;
359 size = count + 1; /* restart with a large enough buffer */
361 return NULL;
365 /***********************************************************************
366 * WINPOS_WindowFromPoint
368 * Find the window and hittest for a given point.
370 HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
372 int i, res;
373 HWND ret, *list;
375 if (!hwndScope) hwndScope = GetDesktopWindow();
377 *hittest = HTNOWHERE;
379 if (!(list = list_children_from_point( hwndScope, pt ))) return 0;
381 /* now determine the hittest */
383 for (i = 0; list[i]; i++)
385 LONG style = GetWindowLongW( list[i], GWL_STYLE );
387 /* If window is minimized or disabled, return at once */
388 if (style & WS_MINIMIZE)
390 *hittest = HTCAPTION;
391 break;
393 if (style & WS_DISABLED)
395 *hittest = HTERROR;
396 break;
398 /* Send WM_NCCHITTEST (if same thread) */
399 if (!WIN_IsCurrentThread( list[i] ))
401 *hittest = HTCLIENT;
402 break;
404 res = SendMessageW( list[i], WM_NCHITTEST, 0, MAKELONG(pt.x,pt.y) );
405 if (res != HTTRANSPARENT)
407 *hittest = res; /* Found the window */
408 break;
410 /* continue search with next window in z-order */
412 ret = list[i];
413 HeapFree( GetProcessHeap(), 0, list );
414 TRACE( "scope %p (%d,%d) returning %p\n", hwndScope, pt.x, pt.y, ret );
415 return ret;
419 /*******************************************************************
420 * WindowFromPoint (USER32.@)
422 HWND WINAPI WindowFromPoint( POINT pt )
424 INT hittest;
425 return WINPOS_WindowFromPoint( 0, pt, &hittest );
429 /*******************************************************************
430 * ChildWindowFromPoint (USER32.@)
432 HWND WINAPI ChildWindowFromPoint( HWND hwndParent, POINT pt )
434 return ChildWindowFromPointEx( hwndParent, pt, CWP_ALL );
437 /*******************************************************************
438 * ChildWindowFromPointEx (USER32.@)
440 HWND WINAPI ChildWindowFromPointEx( HWND hwndParent, POINT pt, UINT uFlags)
442 /* pt is in the client coordinates */
443 HWND *list;
444 int i;
445 RECT rect;
446 HWND retvalue;
448 GetClientRect( hwndParent, &rect );
449 if (!PtInRect( &rect, pt )) return 0;
450 if (!(list = WIN_ListChildren( hwndParent ))) return hwndParent;
452 for (i = 0; list[i]; i++)
454 if (!WIN_GetRectangles( list[i], &rect, NULL )) continue;
455 if (!PtInRect( &rect, pt )) continue;
456 if (uFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
458 LONG style = GetWindowLongW( list[i], GWL_STYLE );
459 if ((uFlags & CWP_SKIPINVISIBLE) && !(style & WS_VISIBLE)) continue;
460 if ((uFlags & CWP_SKIPDISABLED) && (style & WS_DISABLED)) continue;
462 if (uFlags & CWP_SKIPTRANSPARENT)
464 if (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TRANSPARENT) continue;
466 break;
468 retvalue = list[i];
469 HeapFree( GetProcessHeap(), 0, list );
470 if (!retvalue) retvalue = hwndParent;
471 return retvalue;
475 /*******************************************************************
476 * WINPOS_GetWinOffset
478 * Calculate the offset between the origin of the two windows. Used
479 * to implement MapWindowPoints.
481 static void WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, POINT *offset )
483 WND * wndPtr;
485 offset->x = offset->y = 0;
487 /* Translate source window origin to screen coords */
488 if (hwndFrom)
490 HWND hwnd = hwndFrom;
492 while (hwnd)
494 if (hwnd == hwndTo) return;
495 if (!(wndPtr = WIN_GetPtr( hwnd )))
497 ERR( "bad hwndFrom = %p\n", hwnd );
498 return;
500 if (wndPtr == WND_DESKTOP) break;
501 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
502 offset->x += wndPtr->rectClient.left;
503 offset->y += wndPtr->rectClient.top;
504 hwnd = wndPtr->parent;
505 WIN_ReleasePtr( wndPtr );
509 /* Translate origin to destination window coords */
510 if (hwndTo)
512 HWND hwnd = hwndTo;
514 while (hwnd)
516 if (!(wndPtr = WIN_GetPtr( hwnd )))
518 ERR( "bad hwndTo = %p\n", hwnd );
519 return;
521 if (wndPtr == WND_DESKTOP) break;
522 if (wndPtr == WND_OTHER_PROCESS) goto other_process;
523 offset->x -= wndPtr->rectClient.left;
524 offset->y -= wndPtr->rectClient.top;
525 hwnd = wndPtr->parent;
526 WIN_ReleasePtr( wndPtr );
529 return;
531 other_process: /* one of the parents may belong to another process, do it the hard way */
532 offset->x = offset->y = 0;
533 SERVER_START_REQ( get_windows_offset )
535 req->from = hwndFrom;
536 req->to = hwndTo;
537 if (!wine_server_call( req ))
539 offset->x = reply->x;
540 offset->y = reply->y;
543 SERVER_END_REQ;
547 /*******************************************************************
548 * MapWindowPoints (USER.258)
550 void WINAPI MapWindowPoints16( HWND16 hwndFrom, HWND16 hwndTo,
551 LPPOINT16 lppt, UINT16 count )
553 POINT offset;
555 WINPOS_GetWinOffset( WIN_Handle32(hwndFrom), WIN_Handle32(hwndTo), &offset );
556 while (count--)
558 lppt->x += offset.x;
559 lppt->y += offset.y;
560 lppt++;
565 /*******************************************************************
566 * MapWindowPoints (USER32.@)
568 INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT count )
570 POINT offset;
572 WINPOS_GetWinOffset( hwndFrom, hwndTo, &offset );
573 while (count--)
575 lppt->x += offset.x;
576 lppt->y += offset.y;
577 lppt++;
579 return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) );
583 /***********************************************************************
584 * IsIconic (USER32.@)
586 BOOL WINAPI IsIconic(HWND hWnd)
588 return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MINIMIZE) != 0;
592 /***********************************************************************
593 * IsZoomed (USER32.@)
595 BOOL WINAPI IsZoomed(HWND hWnd)
597 return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MAXIMIZE) != 0;
601 /*******************************************************************
602 * AllowSetForegroundWindow (USER32.@)
604 BOOL WINAPI AllowSetForegroundWindow( DWORD procid )
606 /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
607 * implemented, then fix this function. */
608 return TRUE;
612 /*******************************************************************
613 * LockSetForegroundWindow (USER32.@)
615 BOOL WINAPI LockSetForegroundWindow( UINT lockcode )
617 /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
618 * implemented, then fix this function. */
619 return TRUE;
623 /***********************************************************************
624 * BringWindowToTop (USER32.@)
626 BOOL WINAPI BringWindowToTop( HWND hwnd )
628 return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
632 /***********************************************************************
633 * MoveWindow (USER32.@)
635 BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
636 BOOL repaint )
638 int flags = SWP_NOZORDER | SWP_NOACTIVATE;
639 if (!repaint) flags |= SWP_NOREDRAW;
640 TRACE("%p %d,%d %dx%d %d\n", hwnd, x, y, cx, cy, repaint );
641 return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
644 /***********************************************************************
645 * WINPOS_InitInternalPos
647 static LPINTERNALPOS WINPOS_InitInternalPos( WND* wnd )
649 LPINTERNALPOS lpPos = get_internal_pos( wnd->hwndSelf );
650 if( !lpPos )
652 /* this happens when the window is minimized/maximized
653 * for the first time (rectWindow is not adjusted yet) */
655 lpPos = HeapAlloc( GetProcessHeap(), 0, sizeof(INTERNALPOS) );
656 if( !lpPos ) return NULL;
658 set_internal_pos( wnd->hwndSelf, lpPos );
659 lpPos->hwndIconTitle = 0; /* defer until needs to be shown */
660 lpPos->rectNormal.left = wnd->rectWindow.left;
661 lpPos->rectNormal.top = wnd->rectWindow.top;
662 lpPos->rectNormal.right = wnd->rectWindow.right;
663 lpPos->rectNormal.bottom = wnd->rectWindow.bottom;
664 lpPos->ptIconPos.x = lpPos->ptIconPos.y = -1;
665 lpPos->ptMaxPos.x = lpPos->ptMaxPos.y = -1;
668 if( wnd->dwStyle & WS_MINIMIZE )
670 lpPos->ptIconPos.x = wnd->rectWindow.left;
671 lpPos->ptIconPos.y = wnd->rectWindow.top;
673 else if( wnd->dwStyle & WS_MAXIMIZE )
675 lpPos->ptMaxPos.x = wnd->rectWindow.left;
676 lpPos->ptMaxPos.y = wnd->rectWindow.top;
678 else
680 lpPos->rectNormal.left = wnd->rectWindow.left;
681 lpPos->rectNormal.top = wnd->rectWindow.top;
682 lpPos->rectNormal.right = wnd->rectWindow.right;
683 lpPos->rectNormal.bottom = wnd->rectWindow.bottom;
685 return lpPos;
688 /***********************************************************************
689 * WINPOS_RedrawIconTitle
691 BOOL WINPOS_RedrawIconTitle( HWND hWnd )
693 LPINTERNALPOS lpPos = get_internal_pos( hWnd );
694 if( lpPos )
696 if( lpPos->hwndIconTitle )
698 SendMessageW( lpPos->hwndIconTitle, WM_SHOWWINDOW, TRUE, 0);
699 InvalidateRect( lpPos->hwndIconTitle, NULL, TRUE );
700 return TRUE;
703 return FALSE;
706 /***********************************************************************
707 * WINPOS_ShowIconTitle
709 BOOL WINPOS_ShowIconTitle( HWND hwnd, BOOL bShow )
711 LPINTERNALPOS lpPos = get_internal_pos( hwnd );
713 if (lpPos && !GetPropA( hwnd, "__wine_x11_managed" ))
715 HWND title = lpPos->hwndIconTitle;
717 TRACE("%p %i\n", hwnd, (bShow != 0) );
719 if( !title )
720 lpPos->hwndIconTitle = title = ICONTITLE_Create( hwnd );
721 if( bShow )
723 if (!IsWindowVisible(title))
725 SendMessageW( title, WM_SHOWWINDOW, TRUE, 0 );
726 SetWindowPos( title, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
727 SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW );
730 else ShowWindow( title, SW_HIDE );
732 return FALSE;
735 /*******************************************************************
736 * WINPOS_GetMinMaxInfo
738 * Get the minimized and maximized information for a window.
740 void WINPOS_GetMinMaxInfo( HWND hwnd, POINT *maxSize, POINT *maxPos,
741 POINT *minTrack, POINT *maxTrack )
743 LPINTERNALPOS lpPos;
744 MINMAXINFO MinMax;
745 HMONITOR monitor;
746 INT xinc, yinc;
747 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
748 LONG exstyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
749 RECT rc;
751 /* Compute default values */
753 GetWindowRect(hwnd, &rc);
754 MinMax.ptReserved.x = rc.left;
755 MinMax.ptReserved.y = rc.top;
757 if (style & WS_CHILD)
759 if ((style & WS_CAPTION) == WS_CAPTION)
760 style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
762 GetClientRect(GetAncestor(hwnd,GA_PARENT), &rc);
763 AdjustWindowRectEx(&rc, style, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
765 /* avoid calculating this twice */
766 style &= ~(WS_DLGFRAME | WS_BORDER | WS_THICKFRAME);
768 MinMax.ptMaxSize.x = rc.right - rc.left;
769 MinMax.ptMaxSize.y = rc.bottom - rc.top;
771 else
773 MinMax.ptMaxSize.x = GetSystemMetrics(SM_CXSCREEN);
774 MinMax.ptMaxSize.y = GetSystemMetrics(SM_CYSCREEN);
776 MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
777 MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
778 MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
779 MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
781 if (HAS_DLGFRAME( style, exstyle ))
783 xinc = GetSystemMetrics(SM_CXDLGFRAME);
784 yinc = GetSystemMetrics(SM_CYDLGFRAME);
786 else
788 xinc = yinc = 0;
789 if (HAS_THICKFRAME(style))
791 xinc += GetSystemMetrics(SM_CXFRAME);
792 yinc += GetSystemMetrics(SM_CYFRAME);
794 if (style & WS_BORDER)
796 xinc += GetSystemMetrics(SM_CXBORDER);
797 yinc += GetSystemMetrics(SM_CYBORDER);
800 MinMax.ptMaxSize.x += 2 * xinc;
801 MinMax.ptMaxSize.y += 2 * yinc;
803 lpPos = get_internal_pos( hwnd );
804 if( lpPos && !EMPTYPOINT(lpPos->ptMaxPos) )
806 MinMax.ptMaxPosition.x = lpPos->ptMaxPos.x;
807 MinMax.ptMaxPosition.y = lpPos->ptMaxPos.y;
809 else
811 MinMax.ptMaxPosition.x = -xinc;
812 MinMax.ptMaxPosition.y = -yinc;
815 SendMessageW( hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
817 /* if the app didn't change the values, adapt them for the current monitor */
819 if ((monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY )))
821 MONITORINFO mon_info;
823 mon_info.cbSize = sizeof(mon_info);
824 GetMonitorInfoW( monitor, &mon_info );
826 if (MinMax.ptMaxSize.x == GetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
827 MinMax.ptMaxSize.y == GetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
829 MinMax.ptMaxSize.x = (mon_info.rcWork.right - mon_info.rcWork.left) + 2 * xinc;
830 MinMax.ptMaxSize.y = (mon_info.rcWork.bottom - mon_info.rcWork.top) + 2 * yinc;
832 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
834 MinMax.ptMaxPosition.x = mon_info.rcWork.left - xinc;
835 MinMax.ptMaxPosition.y = mon_info.rcWork.top - yinc;
839 /* Some sanity checks */
841 TRACE("%d %d / %d %d / %d %d / %d %d\n",
842 MinMax.ptMaxSize.x, MinMax.ptMaxSize.y,
843 MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y,
844 MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y,
845 MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y);
846 MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x,
847 MinMax.ptMinTrackSize.x );
848 MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y,
849 MinMax.ptMinTrackSize.y );
851 if (maxSize) *maxSize = MinMax.ptMaxSize;
852 if (maxPos) *maxPos = MinMax.ptMaxPosition;
853 if (minTrack) *minTrack = MinMax.ptMinTrackSize;
854 if (maxTrack) *maxTrack = MinMax.ptMaxTrackSize;
857 /***********************************************************************
858 * ShowWindowAsync (USER32.@)
860 * doesn't wait; returns immediately.
861 * used by threads to toggle windows in other (possibly hanging) threads
863 BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd )
865 HWND full_handle;
867 if (is_broadcast(hwnd))
869 SetLastError( ERROR_INVALID_PARAMETER );
870 return FALSE;
873 if ((full_handle = WIN_IsCurrentThread( hwnd )))
874 return USER_Driver->pShowWindow( full_handle, cmd );
876 return SendNotifyMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
880 /***********************************************************************
881 * ShowWindow (USER32.@)
883 BOOL WINAPI ShowWindow( HWND hwnd, INT cmd )
885 HWND full_handle;
887 if (is_broadcast(hwnd))
889 SetLastError( ERROR_INVALID_PARAMETER );
890 return FALSE;
892 if ((full_handle = WIN_IsCurrentThread( hwnd )))
893 return USER_Driver->pShowWindow( full_handle, cmd );
895 return SendMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 );
899 /***********************************************************************
900 * GetInternalWindowPos (USER32.@)
902 UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd,
903 LPPOINT ptIcon )
905 WINDOWPLACEMENT wndpl;
906 if (GetWindowPlacement( hwnd, &wndpl ))
908 if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
909 if (ptIcon) *ptIcon = wndpl.ptMinPosition;
910 return wndpl.showCmd;
912 return 0;
916 /***********************************************************************
917 * GetWindowPlacement (USER32.@)
919 * Win95:
920 * Fails if wndpl->length of Win95 (!) apps is invalid.
922 BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
924 WND *pWnd = WIN_GetPtr( hwnd );
925 LPINTERNALPOS lpPos;
927 if (!pWnd || pWnd == WND_DESKTOP) return FALSE;
928 if (pWnd == WND_OTHER_PROCESS)
930 if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
931 return FALSE;
934 lpPos = WINPOS_InitInternalPos( pWnd );
935 wndpl->length = sizeof(*wndpl);
936 if( pWnd->dwStyle & WS_MINIMIZE )
937 wndpl->showCmd = SW_SHOWMINIMIZED;
938 else
939 wndpl->showCmd = ( pWnd->dwStyle & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
940 if( pWnd->flags & WIN_RESTORE_MAX )
941 wndpl->flags = WPF_RESTORETOMAXIMIZED;
942 else
943 wndpl->flags = 0;
944 wndpl->ptMinPosition.x = lpPos->ptIconPos.x;
945 wndpl->ptMinPosition.y = lpPos->ptIconPos.y;
946 wndpl->ptMaxPosition.x = lpPos->ptMaxPos.x;
947 wndpl->ptMaxPosition.y = lpPos->ptMaxPos.y;
948 wndpl->rcNormalPosition.left = lpPos->rectNormal.left;
949 wndpl->rcNormalPosition.top = lpPos->rectNormal.top;
950 wndpl->rcNormalPosition.right = lpPos->rectNormal.right;
951 wndpl->rcNormalPosition.bottom = lpPos->rectNormal.bottom;
952 WIN_ReleasePtr( pWnd );
953 return TRUE;
957 /***********************************************************************
958 * WINPOS_SetPlacement
960 static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT flags )
962 LPINTERNALPOS lpPos;
963 DWORD style;
964 WND *pWnd = WIN_GetPtr( hwnd );
966 if (!pWnd || pWnd == WND_OTHER_PROCESS || pWnd == WND_DESKTOP) return FALSE;
967 lpPos = WINPOS_InitInternalPos( pWnd );
969 if( flags & PLACE_MIN )
971 lpPos->ptIconPos.x = wndpl->ptMinPosition.x;
972 lpPos->ptIconPos.y = wndpl->ptMinPosition.y;
974 if( flags & PLACE_MAX )
976 lpPos->ptMaxPos.x = wndpl->ptMaxPosition.x;
977 lpPos->ptMaxPos.y = wndpl->ptMaxPosition.y;
979 if( flags & PLACE_RECT)
981 lpPos->rectNormal.left = wndpl->rcNormalPosition.left;
982 lpPos->rectNormal.top = wndpl->rcNormalPosition.top;
983 lpPos->rectNormal.right = wndpl->rcNormalPosition.right;
984 lpPos->rectNormal.bottom = wndpl->rcNormalPosition.bottom;
987 style = pWnd->dwStyle;
988 WIN_ReleasePtr( pWnd );
990 if( style & WS_MINIMIZE )
992 WINPOS_ShowIconTitle( hwnd, FALSE );
993 if( wndpl->flags & WPF_SETMINPOSITION && !EMPTYPOINT(lpPos->ptIconPos))
994 SetWindowPos( hwnd, 0, lpPos->ptIconPos.x, lpPos->ptIconPos.y,
995 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
997 else if( style & WS_MAXIMIZE )
999 if( !EMPTYPOINT(lpPos->ptMaxPos) )
1000 SetWindowPos( hwnd, 0, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y,
1001 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1003 else if( flags & PLACE_RECT )
1004 SetWindowPos( hwnd, 0, lpPos->rectNormal.left, lpPos->rectNormal.top,
1005 lpPos->rectNormal.right - lpPos->rectNormal.left,
1006 lpPos->rectNormal.bottom - lpPos->rectNormal.top,
1007 SWP_NOZORDER | SWP_NOACTIVATE );
1009 ShowWindow( hwnd, wndpl->showCmd );
1011 if (IsIconic( hwnd ))
1013 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE) WINPOS_ShowIconTitle( hwnd, TRUE );
1015 /* SDK: ...valid only the next time... */
1016 if( wndpl->flags & WPF_RESTORETOMAXIMIZED )
1018 pWnd = WIN_GetPtr( hwnd );
1019 if (pWnd && pWnd != WND_OTHER_PROCESS)
1021 pWnd->flags |= WIN_RESTORE_MAX;
1022 WIN_ReleasePtr( pWnd );
1026 return TRUE;
1030 /***********************************************************************
1031 * SetWindowPlacement (USER32.@)
1033 * Win95:
1034 * Fails if wndpl->length of Win95 (!) apps is invalid.
1036 BOOL WINAPI SetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl )
1038 if (!wpl) return FALSE;
1039 return WINPOS_SetPlacement( hwnd, wpl, PLACE_MIN | PLACE_MAX | PLACE_RECT );
1043 /***********************************************************************
1044 * AnimateWindow (USER32.@)
1045 * Shows/Hides a window with an animation
1046 * NO ANIMATION YET
1048 BOOL WINAPI AnimateWindow(HWND hwnd, DWORD dwTime, DWORD dwFlags)
1050 FIXME("partial stub\n");
1052 /* If trying to show/hide and it's already *
1053 * shown/hidden or invalid window, fail with *
1054 * invalid parameter */
1055 if(!IsWindow(hwnd) ||
1056 (IsWindowVisible(hwnd) && !(dwFlags & AW_HIDE)) ||
1057 (!IsWindowVisible(hwnd) && (dwFlags & AW_HIDE)))
1059 SetLastError(ERROR_INVALID_PARAMETER);
1060 return FALSE;
1063 ShowWindow(hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA));
1065 return TRUE;
1068 /***********************************************************************
1069 * SetInternalWindowPos (USER32.@)
1071 void WINAPI SetInternalWindowPos( HWND hwnd, UINT showCmd,
1072 LPRECT rect, LPPOINT pt )
1074 if( IsWindow(hwnd) )
1076 WINDOWPLACEMENT wndpl;
1077 UINT flags;
1079 wndpl.length = sizeof(wndpl);
1080 wndpl.showCmd = showCmd;
1081 wndpl.flags = flags = 0;
1083 if( pt )
1085 flags |= PLACE_MIN;
1086 wndpl.flags |= WPF_SETMINPOSITION;
1087 wndpl.ptMinPosition = *pt;
1089 if( rect )
1091 flags |= PLACE_RECT;
1092 wndpl.rcNormalPosition = *rect;
1094 WINPOS_SetPlacement( hwnd, &wndpl, flags );
1099 /*******************************************************************
1100 * can_activate_window
1102 * Check if we can activate the specified window.
1104 static BOOL can_activate_window( HWND hwnd )
1106 LONG style;
1108 if (!hwnd) return FALSE;
1109 style = GetWindowLongW( hwnd, GWL_STYLE );
1110 if (!(style & WS_VISIBLE)) return FALSE;
1111 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
1112 return !(style & WS_DISABLED);
1116 /*******************************************************************
1117 * WINPOS_ActivateOtherWindow
1119 * Activates window other than pWnd.
1121 void WINPOS_ActivateOtherWindow(HWND hwnd)
1123 HWND hwndTo, fg;
1125 if ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) && (hwndTo = GetWindow( hwnd, GW_OWNER )))
1127 hwndTo = GetAncestor( hwndTo, GA_ROOT );
1128 if (can_activate_window( hwndTo )) goto done;
1131 hwndTo = hwnd;
1132 for (;;)
1134 if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break;
1135 if (can_activate_window( hwndTo )) break;
1138 done:
1139 fg = GetForegroundWindow();
1140 TRACE("win = %p fg = %p\n", hwndTo, fg);
1141 if (!fg || (hwnd == fg))
1143 if (SetForegroundWindow( hwndTo )) return;
1145 if (!SetActiveWindow( hwndTo )) SetActiveWindow(0);
1149 /***********************************************************************
1150 * WINPOS_HandleWindowPosChanging
1152 * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
1154 LONG WINPOS_HandleWindowPosChanging( HWND hwnd, WINDOWPOS *winpos )
1156 POINT minTrack, maxTrack;
1157 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1159 if (winpos->flags & SWP_NOSIZE) return 0;
1160 if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0))
1162 WINPOS_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack );
1163 if (winpos->cx > maxTrack.x) winpos->cx = maxTrack.x;
1164 if (winpos->cy > maxTrack.y) winpos->cy = maxTrack.y;
1165 if (!(style & WS_MINIMIZE))
1167 if (winpos->cx < minTrack.x ) winpos->cx = minTrack.x;
1168 if (winpos->cy < minTrack.y ) winpos->cy = minTrack.y;
1171 return 0;
1175 /***********************************************************************
1176 * dump_winpos_flags
1178 static void dump_winpos_flags(UINT flags)
1180 TRACE("flags:");
1181 if(flags & SWP_NOSIZE) TRACE(" SWP_NOSIZE");
1182 if(flags & SWP_NOMOVE) TRACE(" SWP_NOMOVE");
1183 if(flags & SWP_NOZORDER) TRACE(" SWP_NOZORDER");
1184 if(flags & SWP_NOREDRAW) TRACE(" SWP_NOREDRAW");
1185 if(flags & SWP_NOACTIVATE) TRACE(" SWP_NOACTIVATE");
1186 if(flags & SWP_FRAMECHANGED) TRACE(" SWP_FRAMECHANGED");
1187 if(flags & SWP_SHOWWINDOW) TRACE(" SWP_SHOWWINDOW");
1188 if(flags & SWP_HIDEWINDOW) TRACE(" SWP_HIDEWINDOW");
1189 if(flags & SWP_NOCOPYBITS) TRACE(" SWP_NOCOPYBITS");
1190 if(flags & SWP_NOOWNERZORDER) TRACE(" SWP_NOOWNERZORDER");
1191 if(flags & SWP_NOSENDCHANGING) TRACE(" SWP_NOSENDCHANGING");
1192 if(flags & SWP_DEFERERASE) TRACE(" SWP_DEFERERASE");
1193 if(flags & SWP_ASYNCWINDOWPOS) TRACE(" SWP_ASYNCWINDOWPOS");
1195 #define DUMPED_FLAGS \
1196 (SWP_NOSIZE | \
1197 SWP_NOMOVE | \
1198 SWP_NOZORDER | \
1199 SWP_NOREDRAW | \
1200 SWP_NOACTIVATE | \
1201 SWP_FRAMECHANGED | \
1202 SWP_SHOWWINDOW | \
1203 SWP_HIDEWINDOW | \
1204 SWP_NOCOPYBITS | \
1205 SWP_NOOWNERZORDER | \
1206 SWP_NOSENDCHANGING | \
1207 SWP_DEFERERASE | \
1208 SWP_ASYNCWINDOWPOS)
1210 if(flags & ~DUMPED_FLAGS) TRACE(" %08x", flags & ~DUMPED_FLAGS);
1211 TRACE("\n");
1212 #undef DUMPED_FLAGS
1215 /***********************************************************************
1216 * SWP_DoWinPosChanging
1218 static BOOL SWP_DoWinPosChanging( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT* pNewClientRect )
1220 WND *wndPtr;
1222 /* Send WM_WINDOWPOSCHANGING message */
1224 if (!(pWinpos->flags & SWP_NOSENDCHANGING))
1225 SendMessageW( pWinpos->hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
1227 if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) ||
1228 wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
1230 /* Calculate new position and size */
1232 *pNewWindowRect = wndPtr->rectWindow;
1233 *pNewClientRect = (wndPtr->dwStyle & WS_MINIMIZE) ? wndPtr->rectWindow
1234 : wndPtr->rectClient;
1236 if (!(pWinpos->flags & SWP_NOSIZE))
1238 pNewWindowRect->right = pNewWindowRect->left + pWinpos->cx;
1239 pNewWindowRect->bottom = pNewWindowRect->top + pWinpos->cy;
1241 if (!(pWinpos->flags & SWP_NOMOVE))
1243 pNewWindowRect->left = pWinpos->x;
1244 pNewWindowRect->top = pWinpos->y;
1245 pNewWindowRect->right += pWinpos->x - wndPtr->rectWindow.left;
1246 pNewWindowRect->bottom += pWinpos->y - wndPtr->rectWindow.top;
1248 OffsetRect( pNewClientRect, pWinpos->x - wndPtr->rectWindow.left,
1249 pWinpos->y - wndPtr->rectWindow.top );
1251 pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1253 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
1254 pWinpos->hwnd, pWinpos->hwndInsertAfter, pWinpos->x, pWinpos->y,
1255 pWinpos->cx, pWinpos->cy, pWinpos->flags );
1256 TRACE( "current %s style %08x new %s\n",
1257 wine_dbgstr_rect( &wndPtr->rectWindow ), wndPtr->dwStyle,
1258 wine_dbgstr_rect( pNewWindowRect ));
1260 WIN_ReleasePtr( wndPtr );
1261 return TRUE;
1264 /***********************************************************************
1265 * get_valid_rects
1267 * Compute the valid rects from the old and new client rect and WVR_* flags.
1268 * Helper for WM_NCCALCSIZE handling.
1270 static inline void get_valid_rects( const RECT *old_client, const RECT *new_client, UINT flags,
1271 RECT *valid )
1273 int cx, cy;
1275 if (flags & WVR_REDRAW)
1277 SetRectEmpty( &valid[0] );
1278 SetRectEmpty( &valid[1] );
1279 return;
1282 if (flags & WVR_VALIDRECTS)
1284 if (!IntersectRect( &valid[0], &valid[0], new_client ) ||
1285 !IntersectRect( &valid[1], &valid[1], old_client ))
1287 SetRectEmpty( &valid[0] );
1288 SetRectEmpty( &valid[1] );
1289 return;
1291 flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
1293 else
1295 valid[0] = *new_client;
1296 valid[1] = *old_client;
1299 /* make sure the rectangles have the same size */
1300 cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
1301 cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
1303 if (flags & WVR_ALIGNBOTTOM)
1305 valid[0].top = valid[0].bottom - cy;
1306 valid[1].top = valid[1].bottom - cy;
1308 else
1310 valid[0].bottom = valid[0].top + cy;
1311 valid[1].bottom = valid[1].top + cy;
1313 if (flags & WVR_ALIGNRIGHT)
1315 valid[0].left = valid[0].right - cx;
1316 valid[1].left = valid[1].right - cx;
1318 else
1320 valid[0].right = valid[0].left + cx;
1321 valid[1].right = valid[1].left + cx;
1325 struct move_owned_info
1327 HWND owner;
1328 HWND insert_after;
1331 static BOOL CALLBACK move_owned_popups( HWND hwnd, LPARAM lparam )
1333 struct move_owned_info *info = (struct move_owned_info *)lparam;
1335 if (hwnd == info->owner) return FALSE;
1336 if ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) &&
1337 GetWindow( hwnd, GW_OWNER ) == info->owner)
1339 SetWindowPos( hwnd, info->insert_after, 0, 0, 0, 0,
1340 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE |
1341 SWP_NOSENDCHANGING | SWP_DEFERERASE );
1342 info->insert_after = hwnd;
1344 return TRUE;
1347 /***********************************************************************
1348 * SWP_DoOwnedPopups
1350 * fix Z order taking into account owned popups -
1351 * basically we need to maintain them above the window that owns them
1353 * FIXME: hide/show owned popups when owner visibility changes.
1355 static HWND SWP_DoOwnedPopups(HWND hwnd, HWND hwndInsertAfter)
1357 HWND owner = GetWindow( hwnd, GW_OWNER );
1358 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1359 struct move_owned_info info;
1361 TRACE("(%p) hInsertAfter = %p\n", hwnd, hwndInsertAfter );
1363 if ((style & WS_POPUP) && owner)
1365 /* make sure this popup stays above the owner */
1367 if( hwndInsertAfter != HWND_TOP )
1369 HWND hwndLocalPrev = HWND_TOP;
1370 HWND prev = GetWindow( owner, GW_HWNDPREV );
1372 while (prev && prev != hwndInsertAfter)
1374 if (hwndLocalPrev == HWND_TOP && GetWindowLongW( prev, GWL_STYLE ) & WS_VISIBLE)
1375 hwndLocalPrev = prev;
1376 prev = GetWindow( prev, GW_HWNDPREV );
1378 if (!prev) hwndInsertAfter = hwndLocalPrev;
1381 else if (style & WS_CHILD) return hwndInsertAfter;
1383 info.owner = hwnd;
1384 info.insert_after = hwndInsertAfter;
1385 EnumWindows( move_owned_popups, (LPARAM)&info );
1386 return info.insert_after;
1389 /***********************************************************************
1390 * SWP_DoNCCalcSize
1392 static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, const RECT* pNewWindowRect, RECT* pNewClientRect,
1393 RECT *validRects )
1395 UINT wvrFlags = 0;
1396 WND *wndPtr;
1398 if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1400 /* Send WM_NCCALCSIZE message to get new client area */
1401 if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
1403 NCCALCSIZE_PARAMS params;
1404 WINDOWPOS winposCopy;
1406 params.rgrc[0] = *pNewWindowRect;
1407 params.rgrc[1] = wndPtr->rectWindow;
1408 params.rgrc[2] = wndPtr->rectClient;
1409 params.lppos = &winposCopy;
1410 winposCopy = *pWinpos;
1411 WIN_ReleasePtr( wndPtr );
1413 wvrFlags = SendMessageW( pWinpos->hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)&params );
1415 *pNewClientRect = params.rgrc[0];
1417 if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1419 TRACE( "hwnd %p old win %s old client %s new win %s new client %s\n", pWinpos->hwnd,
1420 wine_dbgstr_rect(&wndPtr->rectWindow), wine_dbgstr_rect(&wndPtr->rectClient),
1421 wine_dbgstr_rect(pNewWindowRect), wine_dbgstr_rect(pNewClientRect) );
1423 if( pNewClientRect->left != wndPtr->rectClient.left ||
1424 pNewClientRect->top != wndPtr->rectClient.top )
1425 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
1427 if( (pNewClientRect->right - pNewClientRect->left !=
1428 wndPtr->rectClient.right - wndPtr->rectClient.left))
1429 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
1430 else
1431 wvrFlags &= ~WVR_HREDRAW;
1433 if (pNewClientRect->bottom - pNewClientRect->top !=
1434 wndPtr->rectClient.bottom - wndPtr->rectClient.top)
1435 pWinpos->flags &= ~SWP_NOCLIENTSIZE;
1436 else
1437 wvrFlags &= ~WVR_VREDRAW;
1439 validRects[0] = params.rgrc[1];
1440 validRects[1] = params.rgrc[2];
1442 else
1444 if (!(pWinpos->flags & SWP_NOMOVE) &&
1445 (pNewClientRect->left != wndPtr->rectClient.left ||
1446 pNewClientRect->top != wndPtr->rectClient.top))
1447 pWinpos->flags &= ~SWP_NOCLIENTMOVE;
1450 if (pWinpos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
1452 SetRectEmpty( &validRects[0] );
1453 SetRectEmpty( &validRects[1] );
1455 else get_valid_rects( &wndPtr->rectClient, pNewClientRect, wvrFlags, validRects );
1457 WIN_ReleasePtr( wndPtr );
1458 return wvrFlags;
1461 /* fix redundant flags and values in the WINDOWPOS structure */
1462 static BOOL fixup_flags( WINDOWPOS *winpos )
1464 HWND parent;
1465 WND *wndPtr = WIN_GetPtr( winpos->hwnd );
1466 BOOL ret = TRUE;
1468 if (!wndPtr || wndPtr == WND_OTHER_PROCESS)
1470 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1471 return FALSE;
1473 winpos->hwnd = wndPtr->hwndSelf; /* make it a full handle */
1475 /* Finally make sure that all coordinates are valid */
1476 if (winpos->x < -32768) winpos->x = -32768;
1477 else if (winpos->x > 32767) winpos->x = 32767;
1478 if (winpos->y < -32768) winpos->y = -32768;
1479 else if (winpos->y > 32767) winpos->y = 32767;
1481 if (winpos->cx < 0) winpos->cx = 0;
1482 else if (winpos->cx > 32767) winpos->cx = 32767;
1483 if (winpos->cy < 0) winpos->cy = 0;
1484 else if (winpos->cy > 32767) winpos->cy = 32767;
1486 parent = GetAncestor( winpos->hwnd, GA_PARENT );
1487 if (!IsWindowVisible( parent )) winpos->flags |= SWP_NOREDRAW;
1489 if (wndPtr->dwStyle & WS_VISIBLE) winpos->flags &= ~SWP_SHOWWINDOW;
1490 else
1492 winpos->flags &= ~SWP_HIDEWINDOW;
1493 if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
1496 if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == winpos->cx) &&
1497 (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == winpos->cy))
1498 winpos->flags |= SWP_NOSIZE; /* Already the right size */
1500 if ((wndPtr->rectWindow.left == winpos->x) && (wndPtr->rectWindow.top == winpos->y))
1501 winpos->flags |= SWP_NOMOVE; /* Already the right position */
1503 if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1505 if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW))) /* Bring to the top when activating */
1507 winpos->flags &= ~SWP_NOZORDER;
1508 winpos->hwndInsertAfter = HWND_TOP;
1512 /* Check hwndInsertAfter */
1513 if (winpos->flags & SWP_NOZORDER) goto done;
1515 /* fix sign extension */
1516 if (winpos->hwndInsertAfter == (HWND)0xffff) winpos->hwndInsertAfter = HWND_TOPMOST;
1517 else if (winpos->hwndInsertAfter == (HWND)0xfffe) winpos->hwndInsertAfter = HWND_NOTOPMOST;
1519 /* FIXME: TOPMOST not supported yet */
1520 if ((winpos->hwndInsertAfter == HWND_TOPMOST) ||
1521 (winpos->hwndInsertAfter == HWND_NOTOPMOST)) winpos->hwndInsertAfter = HWND_TOP;
1523 /* hwndInsertAfter must be a sibling of the window */
1524 if (winpos->hwndInsertAfter == HWND_TOP)
1526 if (GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
1527 winpos->flags |= SWP_NOZORDER;
1529 else if (winpos->hwndInsertAfter == HWND_BOTTOM)
1531 if (GetWindow(winpos->hwnd, GW_HWNDLAST) == winpos->hwnd)
1532 winpos->flags |= SWP_NOZORDER;
1534 else
1536 if (GetAncestor( winpos->hwndInsertAfter, GA_PARENT ) != parent) ret = FALSE;
1537 else
1539 /* don't need to change the Zorder of hwnd if it's already inserted
1540 * after hwndInsertAfter or when inserting hwnd after itself.
1542 if ((winpos->hwnd == winpos->hwndInsertAfter) ||
1543 (winpos->hwnd == GetWindow( winpos->hwndInsertAfter, GW_HWNDNEXT )))
1544 winpos->flags |= SWP_NOZORDER;
1547 done:
1548 WIN_ReleasePtr( wndPtr );
1549 return ret;
1552 /***********************************************************************
1553 * USER_SetWindowPos
1555 * User32 internal function
1557 BOOL USER_SetWindowPos( WINDOWPOS * winpos )
1559 RECT newWindowRect, newClientRect, valid_rects[2];
1560 UINT orig_flags;
1562 orig_flags = winpos->flags;
1564 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
1565 if (!(winpos->flags & SWP_NOMOVE))
1567 if (winpos->x < -32768) winpos->x = -32768;
1568 else if (winpos->x > 32767) winpos->x = 32767;
1569 if (winpos->y < -32768) winpos->y = -32768;
1570 else if (winpos->y > 32767) winpos->y = 32767;
1572 if (!(winpos->flags & SWP_NOSIZE))
1574 if (winpos->cx < 0) winpos->cx = 0;
1575 else if (winpos->cx > 32767) winpos->cx = 32767;
1576 if (winpos->cy < 0) winpos->cy = 0;
1577 else if (winpos->cy > 32767) winpos->cy = 32767;
1580 if (!SWP_DoWinPosChanging( winpos, &newWindowRect, &newClientRect )) return FALSE;
1582 /* Fix redundant flags */
1583 if (!fixup_flags( winpos )) return FALSE;
1585 if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
1587 if (GetAncestor( winpos->hwnd, GA_PARENT ) == GetDesktopWindow())
1588 winpos->hwndInsertAfter = SWP_DoOwnedPopups( winpos->hwnd, winpos->hwndInsertAfter );
1591 /* Common operations */
1593 SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect, valid_rects );
1595 if(!USER_Driver->pSetWindowPos( winpos->hwnd, winpos->hwndInsertAfter,
1596 &newWindowRect, &newClientRect, orig_flags, valid_rects ))
1597 return FALSE;
1599 /* Windows doesn't redraw a window if it is being just moved */
1600 if (!(orig_flags & SWP_SHOWWINDOW) &&
1601 (winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE)
1603 UINT rdw_flags = RDW_FRAME | RDW_ERASE;
1604 if ( !(orig_flags & SWP_DEFERERASE) ) rdw_flags |= RDW_ERASENOW;
1605 RedrawWindow( winpos->hwnd, NULL, NULL, rdw_flags );
1608 if( winpos->flags & SWP_HIDEWINDOW )
1609 HideCaret(winpos->hwnd);
1610 else if (winpos->flags & SWP_SHOWWINDOW)
1611 ShowCaret(winpos->hwnd);
1613 if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
1615 /* child windows get WM_CHILDACTIVATE message */
1616 if ((GetWindowLongW( winpos->hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1617 SendMessageW( winpos->hwnd, WM_CHILDACTIVATE, 0, 0 );
1618 else
1619 SetForegroundWindow( winpos->hwnd );
1622 /* And last, send the WM_WINDOWPOSCHANGED message */
1624 TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
1626 if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE))
1628 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
1629 and always contains final window position.
1631 winpos->x = newWindowRect.left;
1632 winpos->y = newWindowRect.top;
1633 winpos->cx = newWindowRect.right - newWindowRect.left;
1634 winpos->cy = newWindowRect.bottom - newWindowRect.top;
1635 SendMessageW( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
1637 return TRUE;
1640 /***********************************************************************
1641 * SetWindowPos (USER32.@)
1643 BOOL WINAPI SetWindowPos( HWND hwnd, HWND hwndInsertAfter,
1644 INT x, INT y, INT cx, INT cy, UINT flags )
1646 WINDOWPOS winpos;
1648 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
1649 hwnd, hwndInsertAfter, x, y, cx, cy, flags);
1650 if(TRACE_ON(win)) dump_winpos_flags(flags);
1652 if (is_broadcast(hwnd))
1654 SetLastError( ERROR_INVALID_PARAMETER );
1655 return FALSE;
1658 winpos.hwnd = WIN_GetFullHandle(hwnd);
1659 winpos.hwndInsertAfter = WIN_GetFullHandle(hwndInsertAfter);
1660 winpos.x = x;
1661 winpos.y = y;
1662 winpos.cx = cx;
1663 winpos.cy = cy;
1664 winpos.flags = flags;
1666 if (WIN_IsCurrentThread( hwnd ))
1667 return USER_SetWindowPos(&winpos);
1669 return SendMessageW( winpos.hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)&winpos );
1673 /***********************************************************************
1674 * BeginDeferWindowPos (USER32.@)
1676 HDWP WINAPI BeginDeferWindowPos( INT count )
1678 HDWP handle;
1679 DWP *pDWP;
1681 TRACE("%d\n", count);
1683 if (count < 0)
1685 SetLastError(ERROR_INVALID_PARAMETER);
1686 return 0;
1688 /* Windows allows zero count, in which case it allocates context for 8 moves */
1689 if (count == 0) count = 8;
1691 handle = USER_HEAP_ALLOC( sizeof(DWP) + (count-1)*sizeof(WINDOWPOS) );
1692 if (!handle) return 0;
1693 pDWP = (DWP *) USER_HEAP_LIN_ADDR( handle );
1694 pDWP->actualCount = 0;
1695 pDWP->suggestedCount = count;
1696 pDWP->valid = TRUE;
1697 pDWP->wMagic = DWP_MAGIC;
1698 pDWP->hwndParent = 0;
1700 TRACE("returning hdwp %p\n", handle);
1701 return handle;
1705 /***********************************************************************
1706 * DeferWindowPos (USER32.@)
1708 HDWP WINAPI DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter,
1709 INT x, INT y, INT cx, INT cy,
1710 UINT flags )
1712 DWP *pDWP;
1713 int i;
1714 HDWP newhdwp = hdwp,retvalue;
1716 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
1717 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
1719 hwnd = WIN_GetFullHandle( hwnd );
1720 if (hwnd == GetDesktopWindow()) return 0;
1722 if (!(pDWP = USER_HEAP_LIN_ADDR( hdwp ))) return 0;
1724 USER_Lock();
1726 for (i = 0; i < pDWP->actualCount; i++)
1728 if (pDWP->winPos[i].hwnd == hwnd)
1730 /* Merge with the other changes */
1731 if (!(flags & SWP_NOZORDER))
1733 pDWP->winPos[i].hwndInsertAfter = WIN_GetFullHandle(hwndAfter);
1735 if (!(flags & SWP_NOMOVE))
1737 pDWP->winPos[i].x = x;
1738 pDWP->winPos[i].y = y;
1740 if (!(flags & SWP_NOSIZE))
1742 pDWP->winPos[i].cx = cx;
1743 pDWP->winPos[i].cy = cy;
1745 pDWP->winPos[i].flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
1746 SWP_NOZORDER | SWP_NOREDRAW |
1747 SWP_NOACTIVATE | SWP_NOCOPYBITS|
1748 SWP_NOOWNERZORDER);
1749 pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
1750 SWP_FRAMECHANGED);
1751 retvalue = hdwp;
1752 goto END;
1755 if (pDWP->actualCount >= pDWP->suggestedCount)
1757 newhdwp = USER_HEAP_REALLOC( hdwp,
1758 sizeof(DWP) + pDWP->suggestedCount*sizeof(WINDOWPOS) );
1759 if (!newhdwp)
1761 retvalue = 0;
1762 goto END;
1764 pDWP = (DWP *) USER_HEAP_LIN_ADDR( newhdwp );
1765 pDWP->suggestedCount++;
1767 pDWP->winPos[pDWP->actualCount].hwnd = hwnd;
1768 pDWP->winPos[pDWP->actualCount].hwndInsertAfter = hwndAfter;
1769 pDWP->winPos[pDWP->actualCount].x = x;
1770 pDWP->winPos[pDWP->actualCount].y = y;
1771 pDWP->winPos[pDWP->actualCount].cx = cx;
1772 pDWP->winPos[pDWP->actualCount].cy = cy;
1773 pDWP->winPos[pDWP->actualCount].flags = flags;
1774 pDWP->actualCount++;
1775 retvalue = newhdwp;
1776 END:
1777 USER_Unlock();
1778 return retvalue;
1782 /***********************************************************************
1783 * EndDeferWindowPos (USER32.@)
1785 BOOL WINAPI EndDeferWindowPos( HDWP hdwp )
1787 DWP *pDWP;
1788 WINDOWPOS *winpos;
1789 BOOL res = TRUE;
1790 int i;
1792 TRACE("%p\n", hdwp);
1794 pDWP = (DWP *) USER_HEAP_LIN_ADDR( hdwp );
1795 if (!pDWP) return FALSE;
1796 for (i = 0, winpos = pDWP->winPos; i < pDWP->actualCount; i++, winpos++)
1798 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
1799 winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
1800 winpos->cx, winpos->cy, winpos->flags);
1802 if (!(res = USER_SetWindowPos( winpos ))) break;
1804 USER_HEAP_FREE( hdwp );
1805 return res;
1809 /***********************************************************************
1810 * TileChildWindows (USER.199)
1812 void WINAPI TileChildWindows16( HWND16 parent, WORD action )
1814 FIXME("(%04x, %d): stub\n", parent, action);
1817 /***********************************************************************
1818 * CascadeChildWindows (USER.198)
1820 void WINAPI CascadeChildWindows16( HWND16 parent, WORD action )
1822 FIXME("(%04x, %d): stub\n", parent, action);