/* * Window position related functions. * * Copyright 1993, 1994, 1995 Alexandre Julliard * 1995, 1996, 1999 Alex Korobka * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "wine/port.h" #include #include #include "winerror.h" #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "winerror.h" #include "wine/winuser16.h" #include "wine/server.h" #include "controls.h" #include "user.h" #include "win.h" #include "message.h" #include "winpos.h" #include "nonclient.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(win); #define HAS_DLGFRAME(style,exStyle) \ (((exStyle) & WS_EX_DLGMODALFRAME) || \ (((style) & WS_DLGFRAME) && !((style) & WS_BORDER))) #define HAS_THICKFRAME(style) \ (((style) & WS_THICKFRAME) && \ !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME)) #define EMPTYPOINT(pt) ((*(LONG*)&(pt)) == -1) #define PLACE_MIN 0x0001 #define PLACE_MAX 0x0002 #define PLACE_RECT 0x0004 #define DWP_MAGIC ((INT)('W' | ('P' << 8) | ('O' << 16) | ('S' << 24))) typedef struct { INT actualCount; INT suggestedCount; BOOL valid; INT wMagic; HWND hwndParent; WINDOWPOS winPos[1]; } DWP; /* ----- internal variables ----- */ static LPCSTR atomInternalPos; /*********************************************************************** * WINPOS_CreateInternalPosAtom */ BOOL WINPOS_CreateInternalPosAtom() { LPCSTR str = "SysIP"; atomInternalPos = (LPCSTR)(DWORD)GlobalAddAtomA(str); return (atomInternalPos) ? TRUE : FALSE; } /*********************************************************************** * WINPOS_CheckInternalPos * * Called when a window is destroyed. */ void WINPOS_CheckInternalPos( HWND hwnd ) { LPINTERNALPOS lpPos = (LPINTERNALPOS) GetPropA( hwnd, atomInternalPos ); if( lpPos ) { if( IsWindow(lpPos->hwndIconTitle) ) DestroyWindow( lpPos->hwndIconTitle ); HeapFree( GetProcessHeap(), 0, lpPos ); } } /*********************************************************************** * ArrangeIconicWindows (USER32.@) */ UINT WINAPI ArrangeIconicWindows( HWND parent ) { RECT rectParent; HWND hwndChild; INT x, y, xspacing, yspacing; GetClientRect( parent, &rectParent ); x = rectParent.left; y = rectParent.bottom; xspacing = GetSystemMetrics(SM_CXICONSPACING); yspacing = GetSystemMetrics(SM_CYICONSPACING); hwndChild = GetWindow( parent, GW_CHILD ); while (hwndChild) { if( IsIconic( hwndChild ) ) { WINPOS_ShowIconTitle( hwndChild, FALSE ); SetWindowPos( hwndChild, 0, x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2, y - yspacing - GetSystemMetrics(SM_CYICON)/2, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); if( IsWindow(hwndChild) ) WINPOS_ShowIconTitle(hwndChild , TRUE ); if (x <= rectParent.right - xspacing) x += xspacing; else { x = rectParent.left; y -= yspacing; } } hwndChild = GetWindow( hwndChild, GW_HWNDNEXT ); } return yspacing; } /*********************************************************************** * SwitchToThisWindow (USER32.@) */ void WINAPI SwitchToThisWindow( HWND hwnd, BOOL restore ) { ShowWindow( hwnd, restore ? SW_RESTORE : SW_SHOWMINIMIZED ); } /*********************************************************************** * GetWindowRect (USER32.@) */ BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect ) { BOOL ret = WIN_GetRectangles( hwnd, rect, NULL ); if (ret) { MapWindowPoints( GetAncestor( hwnd, GA_PARENT ), 0, (POINT *)rect, 2 ); TRACE( "hwnd %p (%ld,%ld)-(%ld,%ld)\n", hwnd, rect->left, rect->top, rect->right, rect->bottom); } return ret; } /*********************************************************************** * GetWindowRgn (USER32.@) */ int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn ) { int nRet = ERROR; HRGN win_rgn = 0; RGNDATA *data; size_t size = 256; BOOL retry = FALSE; do { if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 ))) { SetLastError( ERROR_OUTOFMEMORY ); return ERROR; } SERVER_START_REQ( get_window_region ) { req->window = hwnd; wine_server_set_reply( req, data->Buffer, size ); if (!wine_server_call_err( req )) { if (!reply->total_size) retry = FALSE; /* no region at all */ else if (reply->total_size <= size) { size_t reply_size = wine_server_reply_size( reply ); data->rdh.dwSize = sizeof(data->rdh); data->rdh.iType = RDH_RECTANGLES; data->rdh.nCount = reply_size / sizeof(RECT); data->rdh.nRgnSize = reply_size; win_rgn = ExtCreateRegion( NULL, size, data ); retry = FALSE; } else { size = reply->total_size; retry = TRUE; } } } SERVER_END_REQ; HeapFree( GetProcessHeap(), 0, data ); } while (retry); if (win_rgn) { nRet = CombineRgn( hrgn, win_rgn, 0, RGN_COPY ); DeleteObject( win_rgn ); } return nRet; } /*********************************************************************** * SetWindowRgn (USER32.@) */ int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw ) { static const RECT empty_rect; BOOL ret; if (hrgn) { RGNDATA *data; DWORD size; if (!(size = GetRegionData( hrgn, 0, NULL ))) return FALSE; if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE; if (!GetRegionData( hrgn, size, data )) { HeapFree( GetProcessHeap(), 0, data ); return FALSE; } SERVER_START_REQ( set_window_region ) { req->window = hwnd; if (data->rdh.nCount) wine_server_add_data( req, data->Buffer, data->rdh.nCount * sizeof(RECT) ); else wine_server_add_data( req, &empty_rect, sizeof(empty_rect) ); ret = !wine_server_call_err( req ); } SERVER_END_REQ; } else /* clear existing region */ { SERVER_START_REQ( set_window_region ) { req->window = hwnd; ret = !wine_server_call_err( req ); } SERVER_END_REQ; } if (ret && USER_Driver.pSetWindowRgn) ret = USER_Driver.pSetWindowRgn( hwnd, hrgn, bRedraw ); if (ret && bRedraw) RedrawWindow( hwnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ERASE ); return ret; } /*********************************************************************** * GetClientRect (USER32.@) */ BOOL WINAPI GetClientRect( HWND hwnd, LPRECT rect ) { BOOL ret; rect->right = rect->bottom = 0; if ((ret = WIN_GetRectangles( hwnd, NULL, rect ))) { rect->right -= rect->left; rect->bottom -= rect->top; } rect->left = rect->top = 0; return ret; } /******************************************************************* * ClientToScreen (USER32.@) */ BOOL WINAPI ClientToScreen( HWND hwnd, LPPOINT lppnt ) { MapWindowPoints( hwnd, 0, lppnt, 1 ); return TRUE; } /******************************************************************* * ScreenToClient (USER32.@) */ BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt ) { MapWindowPoints( 0, hwnd, lppnt, 1 ); return TRUE; } /*********************************************************************** * list_children_from_point * * Get the list of children that can contain point from the server. * Point is in screen coordinates. * Returned list must be freed by caller. */ static HWND *list_children_from_point( HWND hwnd, POINT pt ) { HWND *list; int size = 32; for (;;) { int count = 0; if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break; SERVER_START_REQ( get_window_children_from_point ) { req->parent = hwnd; req->x = pt.x; req->y = pt.y; wine_server_set_reply( req, list, (size-1) * sizeof(HWND) ); if (!wine_server_call( req )) count = reply->count; } SERVER_END_REQ; if (count && count < size) { list[count] = 0; return list; } HeapFree( GetProcessHeap(), 0, list ); if (!count) break; size = count + 1; /* restart with a large enough buffer */ } return NULL; } /*********************************************************************** * WINPOS_WindowFromPoint * * Find the window and hittest for a given point. */ HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest ) { int i, res; HWND ret, *list; if (!hwndScope) hwndScope = GetDesktopWindow(); *hittest = HTNOWHERE; if (!(list = list_children_from_point( hwndScope, pt ))) return 0; /* now determine the hittest */ for (i = 0; list[i]; i++) { LONG style = GetWindowLongW( list[i], GWL_STYLE ); /* If window is minimized or disabled, return at once */ if (style & WS_MINIMIZE) { *hittest = HTCAPTION; break; } if (style & WS_DISABLED) { *hittest = HTERROR; break; } /* Send WM_NCCHITTEST (if same thread) */ if (!WIN_IsCurrentThread( list[i] )) { *hittest = HTCLIENT; break; } res = SendMessageA( list[i], WM_NCHITTEST, 0, MAKELONG(pt.x,pt.y) ); if (res != HTTRANSPARENT) { *hittest = res; /* Found the window */ break; } /* continue search with next window in z-order */ } ret = list[i]; HeapFree( GetProcessHeap(), 0, list ); TRACE( "scope %p (%ld,%ld) returning %p\n", hwndScope, pt.x, pt.y, ret ); return ret; } /******************************************************************* * WindowFromPoint (USER32.@) */ HWND WINAPI WindowFromPoint( POINT pt ) { INT hittest; return WINPOS_WindowFromPoint( 0, pt, &hittest ); } /******************************************************************* * ChildWindowFromPoint (USER32.@) */ HWND WINAPI ChildWindowFromPoint( HWND hwndParent, POINT pt ) { return ChildWindowFromPointEx( hwndParent, pt, CWP_ALL ); } /******************************************************************* * ChildWindowFromPointEx (USER32.@) */ HWND WINAPI ChildWindowFromPointEx( HWND hwndParent, POINT pt, UINT uFlags) { /* pt is in the client coordinates */ HWND *list; int i; RECT rect; HWND retvalue; GetClientRect( hwndParent, &rect ); if (!PtInRect( &rect, pt )) return 0; if (!(list = WIN_ListChildren( hwndParent ))) return 0; for (i = 0; list[i]; i++) { if (!WIN_GetRectangles( list[i], &rect, NULL )) continue; if (!PtInRect( &rect, pt )) continue; if (uFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED)) { LONG style = GetWindowLongW( list[i], GWL_STYLE ); if ((uFlags & CWP_SKIPINVISIBLE) && !(style & WS_VISIBLE)) continue; if ((uFlags & CWP_SKIPDISABLED) && (style & WS_DISABLED)) continue; } if (uFlags & CWP_SKIPTRANSPARENT) { if (GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_TRANSPARENT) continue; } break; } retvalue = list[i]; HeapFree( GetProcessHeap(), 0, list ); if (!retvalue) retvalue = hwndParent; return retvalue; } /******************************************************************* * WINPOS_GetWinOffset * * Calculate the offset between the origin of the two windows. Used * to implement MapWindowPoints. */ static void WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, POINT *offset ) { WND * wndPtr; offset->x = offset->y = 0; /* Translate source window origin to screen coords */ if (hwndFrom) { HWND hwnd = hwndFrom; while (hwnd) { if (hwnd == hwndTo) return; if (!(wndPtr = WIN_GetPtr( hwnd ))) { ERR( "bad hwndFrom = %p\n", hwnd ); return; } if (wndPtr == WND_OTHER_PROCESS) goto other_process; offset->x += wndPtr->rectClient.left; offset->y += wndPtr->rectClient.top; hwnd = wndPtr->parent; WIN_ReleasePtr( wndPtr ); } } /* Translate origin to destination window coords */ if (hwndTo) { HWND hwnd = hwndTo; while (hwnd) { if (!(wndPtr = WIN_GetPtr( hwnd ))) { ERR( "bad hwndTo = %p\n", hwnd ); return; } if (wndPtr == WND_OTHER_PROCESS) goto other_process; offset->x -= wndPtr->rectClient.left; offset->y -= wndPtr->rectClient.top; hwnd = wndPtr->parent; WIN_ReleasePtr( wndPtr ); } } return; other_process: /* one of the parents may belong to another process, do it the hard way */ offset->x = offset->y = 0; SERVER_START_REQ( get_windows_offset ) { req->from = hwndFrom; req->to = hwndTo; if (!wine_server_call( req )) { offset->x = reply->x; offset->y = reply->y; } } SERVER_END_REQ; } /******************************************************************* * MapWindowPoints (USER.258) */ void WINAPI MapWindowPoints16( HWND16 hwndFrom, HWND16 hwndTo, LPPOINT16 lppt, UINT16 count ) { POINT offset; WINPOS_GetWinOffset( WIN_Handle32(hwndFrom), WIN_Handle32(hwndTo), &offset ); while (count--) { lppt->x += offset.x; lppt->y += offset.y; lppt++; } } /******************************************************************* * MapWindowPoints (USER32.@) */ INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT count ) { POINT offset; WINPOS_GetWinOffset( hwndFrom, hwndTo, &offset ); while (count--) { lppt->x += offset.x; lppt->y += offset.y; lppt++; } return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) ); } /*********************************************************************** * IsIconic (USER32.@) */ BOOL WINAPI IsIconic(HWND hWnd) { return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MINIMIZE) != 0; } /*********************************************************************** * IsZoomed (USER32.@) */ BOOL WINAPI IsZoomed(HWND hWnd) { return (GetWindowLongW( hWnd, GWL_STYLE ) & WS_MAXIMIZE) != 0; } /******************************************************************* * AllowSetForegroundWindow (USER32.@) */ BOOL WINAPI AllowSetForegroundWindow( DWORD procid ) { /* FIXME: If Win98/2000 style SetForegroundWindow behavior is * implemented, then fix this function. */ return TRUE; } /******************************************************************* * LockSetForegroundWindow (USER32.@) */ BOOL WINAPI LockSetForegroundWindow( UINT lockcode ) { /* FIXME: If Win98/2000 style SetForegroundWindow behavior is * implemented, then fix this function. */ return TRUE; } /*********************************************************************** * BringWindowToTop (USER32.@) */ BOOL WINAPI BringWindowToTop( HWND hwnd ) { return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE ); } /*********************************************************************** * MoveWindow (USER32.@) */ BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy, BOOL repaint ) { int flags = SWP_NOZORDER | SWP_NOACTIVATE; if (!repaint) flags |= SWP_NOREDRAW; TRACE("%p %d,%d %dx%d %d\n", hwnd, x, y, cx, cy, repaint ); return SetWindowPos( hwnd, 0, x, y, cx, cy, flags ); } /*********************************************************************** * WINPOS_InitInternalPos */ static LPINTERNALPOS WINPOS_InitInternalPos( WND* wnd, POINT pt, const RECT *restoreRect ) { LPINTERNALPOS lpPos = (LPINTERNALPOS) GetPropA( wnd->hwndSelf, atomInternalPos ); if( !lpPos ) { /* this happens when the window is minimized/maximized * for the first time (rectWindow is not adjusted yet) */ lpPos = HeapAlloc( GetProcessHeap(), 0, sizeof(INTERNALPOS) ); if( !lpPos ) return NULL; SetPropA( wnd->hwndSelf, atomInternalPos, (HANDLE)lpPos ); lpPos->hwndIconTitle = 0; /* defer until needs to be shown */ lpPos->rectNormal.left = wnd->rectWindow.left; lpPos->rectNormal.top = wnd->rectWindow.top; lpPos->rectNormal.right = wnd->rectWindow.right; lpPos->rectNormal.bottom = wnd->rectWindow.bottom; lpPos->ptIconPos.x = lpPos->ptIconPos.y = -1; lpPos->ptMaxPos.x = lpPos->ptMaxPos.y = -1; } if( wnd->dwStyle & WS_MINIMIZE ) { lpPos->ptIconPos.x = pt.x; lpPos->ptIconPos.y = pt.y; } else if( wnd->dwStyle & WS_MAXIMIZE ) { lpPos->ptMaxPos.x = pt.x; lpPos->ptMaxPos.y = pt.y; } else if( restoreRect ) { lpPos->rectNormal.left = restoreRect->left; lpPos->rectNormal.top = restoreRect->top; lpPos->rectNormal.right = restoreRect->right; lpPos->rectNormal.bottom = restoreRect->bottom; } return lpPos; } /*********************************************************************** * WINPOS_RedrawIconTitle */ BOOL WINPOS_RedrawIconTitle( HWND hWnd ) { LPINTERNALPOS lpPos = (LPINTERNALPOS)GetPropA( hWnd, atomInternalPos ); if( lpPos ) { if( lpPos->hwndIconTitle ) { SendMessageA( lpPos->hwndIconTitle, WM_SHOWWINDOW, TRUE, 0); InvalidateRect( lpPos->hwndIconTitle, NULL, TRUE ); return TRUE; } } return FALSE; } /*********************************************************************** * WINPOS_ShowIconTitle */ BOOL WINPOS_ShowIconTitle( HWND hwnd, BOOL bShow ) { LPINTERNALPOS lpPos = (LPINTERNALPOS)GetPropA( hwnd, atomInternalPos ); if( lpPos && !(GetWindowLongA( hwnd, GWL_EXSTYLE) & WS_EX_MANAGED)) { HWND title = lpPos->hwndIconTitle; TRACE("%p %i\n", hwnd, (bShow != 0) ); if( !title ) lpPos->hwndIconTitle = title = ICONTITLE_Create( hwnd ); if( bShow ) { if (!IsWindowVisible(title)) { SendMessageA( title, WM_SHOWWINDOW, TRUE, 0 ); SetWindowPos( title, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW ); } } else ShowWindow( title, SW_HIDE ); } return FALSE; } /******************************************************************* * WINPOS_GetMinMaxInfo * * Get the minimized and maximized information for a window. */ void WINPOS_GetMinMaxInfo( HWND hwnd, POINT *maxSize, POINT *maxPos, POINT *minTrack, POINT *maxTrack ) { LPINTERNALPOS lpPos; MINMAXINFO MinMax; INT xinc, yinc; LONG style = GetWindowLongA( hwnd, GWL_STYLE ); LONG exstyle = GetWindowLongA( hwnd, GWL_EXSTYLE ); RECT rc; /* Compute default values */ GetWindowRect(hwnd, &rc); MinMax.ptReserved.x = rc.left; MinMax.ptReserved.y = rc.top; if (style & WS_CHILD) { if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */ GetClientRect(GetParent(hwnd), &rc); AdjustWindowRectEx(&rc, style, 0, exstyle); /* avoid calculating this twice */ style &= ~(WS_DLGFRAME | WS_BORDER | WS_THICKFRAME); MinMax.ptMaxSize.x = rc.right - rc.left; MinMax.ptMaxSize.y = rc.bottom - rc.top; } else { MinMax.ptMaxSize.x = GetSystemMetrics(SM_CXSCREEN); MinMax.ptMaxSize.y = GetSystemMetrics(SM_CYSCREEN); } MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK); MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK); MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXSCREEN); MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYSCREEN); if (HAS_DLGFRAME( style, exstyle )) { xinc = GetSystemMetrics(SM_CXDLGFRAME); yinc = GetSystemMetrics(SM_CYDLGFRAME); } else { xinc = yinc = 0; if (HAS_THICKFRAME(style)) { xinc += GetSystemMetrics(SM_CXFRAME); yinc += GetSystemMetrics(SM_CYFRAME); } if (style & WS_BORDER) { xinc += GetSystemMetrics(SM_CXBORDER); yinc += GetSystemMetrics(SM_CYBORDER); } } MinMax.ptMaxSize.x += 2 * xinc; MinMax.ptMaxSize.y += 2 * yinc; lpPos = (LPINTERNALPOS)GetPropA( hwnd, atomInternalPos ); if( lpPos && !EMPTYPOINT(lpPos->ptMaxPos) ) { MinMax.ptMaxPosition.x = lpPos->ptMaxPos.x; MinMax.ptMaxPosition.y = lpPos->ptMaxPos.y; } else { MinMax.ptMaxPosition.x = -xinc; MinMax.ptMaxPosition.y = -yinc; } SendMessageA( hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax ); /* Some sanity checks */ TRACE("%ld %ld / %ld %ld / %ld %ld / %ld %ld\n", MinMax.ptMaxSize.x, MinMax.ptMaxSize.y, MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y, MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y, MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y); MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x, MinMax.ptMinTrackSize.x ); MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y, MinMax.ptMinTrackSize.y ); if (maxSize) *maxSize = MinMax.ptMaxSize; if (maxPos) *maxPos = MinMax.ptMaxPosition; if (minTrack) *minTrack = MinMax.ptMinTrackSize; if (maxTrack) *maxTrack = MinMax.ptMaxTrackSize; } /*********************************************************************** * ShowWindowAsync (USER32.@) * * doesn't wait; returns immediately. * used by threads to toggle windows in other (possibly hanging) threads */ BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd ) { HWND full_handle; if (is_broadcast(hwnd)) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } if ((full_handle = WIN_IsCurrentThread( hwnd ))) return USER_Driver.pShowWindow( full_handle, cmd ); return SendNotifyMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 ); } /*********************************************************************** * ShowWindow (USER32.@) */ BOOL WINAPI ShowWindow( HWND hwnd, INT cmd ) { HWND full_handle; if (is_broadcast(hwnd)) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } if ((full_handle = WIN_IsCurrentThread( hwnd ))) { if (USER_Driver.pShowWindow) return USER_Driver.pShowWindow( full_handle, cmd ); return FALSE; } return SendMessageW( hwnd, WM_WINE_SHOWWINDOW, cmd, 0 ); } /*********************************************************************** * GetInternalWindowPos (USER32.@) */ UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd, LPPOINT ptIcon ) { WINDOWPLACEMENT wndpl; if (GetWindowPlacement( hwnd, &wndpl )) { if (rectWnd) *rectWnd = wndpl.rcNormalPosition; if (ptIcon) *ptIcon = wndpl.ptMinPosition; return wndpl.showCmd; } return 0; } /*********************************************************************** * GetWindowPlacement (USER32.@) * * Win95: * Fails if wndpl->length of Win95 (!) apps is invalid. */ BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl ) { WND *pWnd = WIN_FindWndPtr( hwnd ); LPINTERNALPOS lpPos; if(!pWnd ) return FALSE; lpPos = WINPOS_InitInternalPos( pWnd, *(LPPOINT)&pWnd->rectWindow.left, &pWnd->rectWindow ); wndpl->length = sizeof(*wndpl); if( pWnd->dwStyle & WS_MINIMIZE ) wndpl->showCmd = SW_SHOWMINIMIZED; else wndpl->showCmd = ( pWnd->dwStyle & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ; if( pWnd->flags & WIN_RESTORE_MAX ) wndpl->flags = WPF_RESTORETOMAXIMIZED; else wndpl->flags = 0; wndpl->ptMinPosition.x = lpPos->ptIconPos.x; wndpl->ptMinPosition.y = lpPos->ptIconPos.y; wndpl->ptMaxPosition.x = lpPos->ptMaxPos.x; wndpl->ptMaxPosition.y = lpPos->ptMaxPos.y; wndpl->rcNormalPosition.left = lpPos->rectNormal.left; wndpl->rcNormalPosition.top = lpPos->rectNormal.top; wndpl->rcNormalPosition.right = lpPos->rectNormal.right; wndpl->rcNormalPosition.bottom = lpPos->rectNormal.bottom; WIN_ReleaseWndPtr(pWnd); return TRUE; } /*********************************************************************** * WINPOS_SetPlacement */ static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT flags ) { WND *pWnd = WIN_FindWndPtr( hwnd ); if( pWnd ) { LPINTERNALPOS lpPos = (LPINTERNALPOS)WINPOS_InitInternalPos( pWnd, *(LPPOINT)&pWnd->rectWindow.left, &pWnd->rectWindow ); if( flags & PLACE_MIN ) { lpPos->ptIconPos.x = wndpl->ptMinPosition.x; lpPos->ptIconPos.y = wndpl->ptMinPosition.y; } if( flags & PLACE_MAX ) { lpPos->ptMaxPos.x = wndpl->ptMaxPosition.x; lpPos->ptMaxPos.y = wndpl->ptMaxPosition.y; } if( flags & PLACE_RECT) { lpPos->rectNormal.left = wndpl->rcNormalPosition.left; lpPos->rectNormal.top = wndpl->rcNormalPosition.top; lpPos->rectNormal.right = wndpl->rcNormalPosition.right; lpPos->rectNormal.bottom = wndpl->rcNormalPosition.bottom; } if( pWnd->dwStyle & WS_MINIMIZE ) { WINPOS_ShowIconTitle( pWnd->hwndSelf, FALSE ); if( wndpl->flags & WPF_SETMINPOSITION && !EMPTYPOINT(lpPos->ptIconPos)) SetWindowPos( hwnd, 0, lpPos->ptIconPos.x, lpPos->ptIconPos.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); } else if( pWnd->dwStyle & WS_MAXIMIZE ) { if( !EMPTYPOINT(lpPos->ptMaxPos) ) SetWindowPos( hwnd, 0, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); } else if( flags & PLACE_RECT ) SetWindowPos( hwnd, 0, lpPos->rectNormal.left, lpPos->rectNormal.top, lpPos->rectNormal.right - lpPos->rectNormal.left, lpPos->rectNormal.bottom - lpPos->rectNormal.top, SWP_NOZORDER | SWP_NOACTIVATE ); ShowWindow( hwnd, wndpl->showCmd ); if( IsWindow(hwnd) && pWnd->dwStyle & WS_MINIMIZE ) { if( pWnd->dwStyle & WS_VISIBLE ) WINPOS_ShowIconTitle( pWnd->hwndSelf, TRUE ); /* SDK: ...valid only the next time... */ if( wndpl->flags & WPF_RESTORETOMAXIMIZED ) pWnd->flags |= WIN_RESTORE_MAX; } WIN_ReleaseWndPtr(pWnd); return TRUE; } return FALSE; } /*********************************************************************** * SetWindowPlacement (USER32.@) * * Win95: * Fails if wndpl->length of Win95 (!) apps is invalid. */ BOOL WINAPI SetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl ) { if (!wpl) return FALSE; return WINPOS_SetPlacement( hwnd, wpl, PLACE_MIN | PLACE_MAX | PLACE_RECT ); } /*********************************************************************** * AnimateWindow (USER32.@) * Shows/Hides a window with an animation * NO ANIMATION YET */ BOOL WINAPI AnimateWindow(HWND hwnd, DWORD dwTime, DWORD dwFlags) { FIXME("partial stub\n"); /* If trying to show/hide and it's already * * shown/hidden or invalid window, fail with * * invalid parameter */ if(!IsWindow(hwnd) || (IsWindowVisible(hwnd) && !(dwFlags & AW_HIDE)) || (!IsWindowVisible(hwnd) && (dwFlags & AW_HIDE))) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } ShowWindow(hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA)); return TRUE; } /*********************************************************************** * SetInternalWindowPos (USER32.@) */ void WINAPI SetInternalWindowPos( HWND hwnd, UINT showCmd, LPRECT rect, LPPOINT pt ) { if( IsWindow(hwnd) ) { WINDOWPLACEMENT wndpl; UINT flags; wndpl.length = sizeof(wndpl); wndpl.showCmd = showCmd; wndpl.flags = flags = 0; if( pt ) { flags |= PLACE_MIN; wndpl.flags |= WPF_SETMINPOSITION; wndpl.ptMinPosition = *pt; } if( rect ) { flags |= PLACE_RECT; wndpl.rcNormalPosition = *rect; } WINPOS_SetPlacement( hwnd, &wndpl, flags ); } } /******************************************************************* * can_activate_window * * Check if we can activate the specified window. */ static BOOL can_activate_window( HWND hwnd ) { LONG style; if (!hwnd) return FALSE; style = GetWindowLongW( hwnd, GWL_STYLE ); if (!(style & WS_VISIBLE)) return FALSE; if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE; return !(style & WS_DISABLED); } /******************************************************************* * WINPOS_ActivateOtherWindow * * Activates window other than pWnd. */ void WINPOS_ActivateOtherWindow(HWND hwnd) { HWND hwndTo, fg; if ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) && (hwndTo = GetWindow( hwnd, GW_OWNER ))) { hwndTo = GetAncestor( hwndTo, GA_ROOT ); if (can_activate_window( hwndTo )) goto done; } hwndTo = hwnd; for (;;) { if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break; if (can_activate_window( hwndTo )) break; } done: fg = GetForegroundWindow(); TRACE("win = %p fg = %p\n", hwndTo, fg); if (!fg || (hwnd == fg)) { if (SetForegroundWindow( hwndTo )) return; } if (!SetActiveWindow( hwndTo )) SetActiveWindow(0); } /*********************************************************************** * WINPOS_HandleWindowPosChanging16 * * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc(). */ LONG WINPOS_HandleWindowPosChanging16( HWND hwnd, WINDOWPOS16 *winpos ) { POINT minTrack, maxTrack; LONG style = GetWindowLongW( hwnd, GWL_STYLE ); if (winpos->flags & SWP_NOSIZE) return 0; if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0)) { WINPOS_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack ); if (winpos->cx > maxTrack.x) winpos->cx = maxTrack.x; if (winpos->cy > maxTrack.y) winpos->cy = maxTrack.y; if (!(style & WS_MINIMIZE)) { if (winpos->cx < minTrack.x ) winpos->cx = minTrack.x; if (winpos->cy < minTrack.y ) winpos->cy = minTrack.y; } } return 0; } /*********************************************************************** * WINPOS_HandleWindowPosChanging * * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc(). */ LONG WINPOS_HandleWindowPosChanging( HWND hwnd, WINDOWPOS *winpos ) { POINT minTrack, maxTrack; LONG style = GetWindowLongW( hwnd, GWL_STYLE ); if (winpos->flags & SWP_NOSIZE) return 0; if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0)) { WINPOS_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack ); if (winpos->cx > maxTrack.x) winpos->cx = maxTrack.x; if (winpos->cy > maxTrack.y) winpos->cy = maxTrack.y; if (!(style & WS_MINIMIZE)) { if (winpos->cx < minTrack.x ) winpos->cx = minTrack.x; if (winpos->cy < minTrack.y ) winpos->cy = minTrack.y; } } return 0; } /*********************************************************************** * dump_winpos_flags */ static void dump_winpos_flags(UINT flags) { TRACE("flags:"); if(flags & SWP_NOSIZE) TRACE(" SWP_NOSIZE"); if(flags & SWP_NOMOVE) TRACE(" SWP_NOMOVE"); if(flags & SWP_NOZORDER) TRACE(" SWP_NOZORDER"); if(flags & SWP_NOREDRAW) TRACE(" SWP_NOREDRAW"); if(flags & SWP_NOACTIVATE) TRACE(" SWP_NOACTIVATE"); if(flags & SWP_FRAMECHANGED) TRACE(" SWP_FRAMECHANGED"); if(flags & SWP_SHOWWINDOW) TRACE(" SWP_SHOWWINDOW"); if(flags & SWP_HIDEWINDOW) TRACE(" SWP_HIDEWINDOW"); if(flags & SWP_NOCOPYBITS) TRACE(" SWP_NOCOPYBITS"); if(flags & SWP_NOOWNERZORDER) TRACE(" SWP_NOOWNERZORDER"); if(flags & SWP_NOSENDCHANGING) TRACE(" SWP_NOSENDCHANGING"); if(flags & SWP_DEFERERASE) TRACE(" SWP_DEFERERASE"); if(flags & SWP_ASYNCWINDOWPOS) TRACE(" SWP_ASYNCWINDOWPOS"); #define DUMPED_FLAGS \ (SWP_NOSIZE | \ SWP_NOMOVE | \ SWP_NOZORDER | \ SWP_NOREDRAW | \ SWP_NOACTIVATE | \ SWP_FRAMECHANGED | \ SWP_SHOWWINDOW | \ SWP_HIDEWINDOW | \ SWP_NOCOPYBITS | \ SWP_NOOWNERZORDER | \ SWP_NOSENDCHANGING | \ SWP_DEFERERASE | \ SWP_ASYNCWINDOWPOS) if(flags & ~DUMPED_FLAGS) TRACE(" %08x", flags & ~DUMPED_FLAGS); TRACE("\n"); #undef DUMPED_FLAGS } /*********************************************************************** * SetWindowPos (USER32.@) */ BOOL WINAPI SetWindowPos( HWND hwnd, HWND hwndInsertAfter, INT x, INT y, INT cx, INT cy, UINT flags ) { WINDOWPOS winpos; TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n", hwnd, hwndInsertAfter, x, y, cx, cy, flags); if(TRACE_ON(win)) dump_winpos_flags(flags); if (is_broadcast(hwnd)) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } winpos.hwnd = WIN_GetFullHandle(hwnd); winpos.hwndInsertAfter = WIN_GetFullHandle(hwndInsertAfter); winpos.x = x; winpos.y = y; winpos.cx = cx; winpos.cy = cy; winpos.flags = flags; if (WIN_IsCurrentThread( hwnd )) return USER_Driver.pSetWindowPos( &winpos ); return SendMessageW( winpos.hwnd, WM_WINE_SETWINDOWPOS, 0, (LPARAM)&winpos ); } /*********************************************************************** * BeginDeferWindowPos (USER32.@) */ HDWP WINAPI BeginDeferWindowPos( INT count ) { HDWP handle; DWP *pDWP; TRACE("%d\n", count); if (count < 0) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } /* Windows allows zero count, in which case it allocates context for 8 moves */ if (count == 0) count = 8; handle = USER_HEAP_ALLOC( sizeof(DWP) + (count-1)*sizeof(WINDOWPOS) ); if (!handle) return 0; pDWP = (DWP *) USER_HEAP_LIN_ADDR( handle ); pDWP->actualCount = 0; pDWP->suggestedCount = count; pDWP->valid = TRUE; pDWP->wMagic = DWP_MAGIC; pDWP->hwndParent = 0; TRACE("returning hdwp %p\n", handle); return handle; } /*********************************************************************** * DeferWindowPos (USER32.@) */ HDWP WINAPI DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter, INT x, INT y, INT cx, INT cy, UINT flags ) { DWP *pDWP; int i; HDWP newhdwp = hdwp,retvalue; TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n", hdwp, hwnd, hwndAfter, x, y, cx, cy, flags); hwnd = WIN_GetFullHandle( hwnd ); if (hwnd == GetDesktopWindow()) return 0; if (!(pDWP = USER_HEAP_LIN_ADDR( hdwp ))) return 0; USER_Lock(); for (i = 0; i < pDWP->actualCount; i++) { if (pDWP->winPos[i].hwnd == hwnd) { /* Merge with the other changes */ if (!(flags & SWP_NOZORDER)) { pDWP->winPos[i].hwndInsertAfter = WIN_GetFullHandle(hwndAfter); } if (!(flags & SWP_NOMOVE)) { pDWP->winPos[i].x = x; pDWP->winPos[i].y = y; } if (!(flags & SWP_NOSIZE)) { pDWP->winPos[i].cx = cx; pDWP->winPos[i].cy = cy; } pDWP->winPos[i].flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE | SWP_NOCOPYBITS| SWP_NOOWNERZORDER); pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW | SWP_FRAMECHANGED); retvalue = hdwp; goto END; } } if (pDWP->actualCount >= pDWP->suggestedCount) { newhdwp = USER_HEAP_REALLOC( hdwp, sizeof(DWP) + pDWP->suggestedCount*sizeof(WINDOWPOS) ); if (!newhdwp) { retvalue = 0; goto END; } pDWP = (DWP *) USER_HEAP_LIN_ADDR( newhdwp ); pDWP->suggestedCount++; } pDWP->winPos[pDWP->actualCount].hwnd = hwnd; pDWP->winPos[pDWP->actualCount].hwndInsertAfter = hwndAfter; pDWP->winPos[pDWP->actualCount].x = x; pDWP->winPos[pDWP->actualCount].y = y; pDWP->winPos[pDWP->actualCount].cx = cx; pDWP->winPos[pDWP->actualCount].cy = cy; pDWP->winPos[pDWP->actualCount].flags = flags; pDWP->actualCount++; retvalue = newhdwp; END: USER_Unlock(); return retvalue; } /*********************************************************************** * EndDeferWindowPos (USER32.@) */ BOOL WINAPI EndDeferWindowPos( HDWP hdwp ) { DWP *pDWP; WINDOWPOS *winpos; BOOL res = TRUE; int i; TRACE("%p\n", hdwp); pDWP = (DWP *) USER_HEAP_LIN_ADDR( hdwp ); if (!pDWP) return FALSE; for (i = 0, winpos = pDWP->winPos; i < pDWP->actualCount; i++, winpos++) { if (!(res = USER_Driver.pSetWindowPos( winpos ))) break; } USER_HEAP_FREE( hdwp ); return res; } /*********************************************************************** * TileChildWindows (USER.199) */ void WINAPI TileChildWindows16( HWND16 parent, WORD action ) { FIXME("(%04x, %d): stub\n", parent, action); } /*********************************************************************** * CascadeChildWindows (USER.198) */ void WINAPI CascadeChildWindows16( HWND16 parent, WORD action ) { FIXME("(%04x, %d): stub\n", parent, action); }