diff --git a/dlls/user32/sysparams.c b/dlls/user32/sysparams.c index 3907c876176..b392ec35eb5 100644 --- a/dlls/user32/sysparams.c +++ b/dlls/user32/sysparams.c @@ -1011,24 +1011,9 @@ HMONITOR WINAPI MonitorFromPoint( POINT pt, DWORD flags ) /*********************************************************************** * MonitorFromWindow (USER32.@) */ -HMONITOR WINAPI MonitorFromWindow(HWND hWnd, DWORD dwFlags) +HMONITOR WINAPI MonitorFromWindow( HWND hwnd, DWORD flags ) { - RECT rect; - WINDOWPLACEMENT wp; - - TRACE("(%p, 0x%08x)\n", hWnd, dwFlags); - - wp.length = sizeof(wp); - if (IsIconic(hWnd) && GetWindowPlacement(hWnd, &wp)) - return MonitorFromRect( &wp.rcNormalPosition, dwFlags ); - - if (GetWindowRect( hWnd, &rect )) - return MonitorFromRect( &rect, dwFlags ); - - if (!(dwFlags & (MONITOR_DEFAULTTOPRIMARY|MONITOR_DEFAULTTONEAREST))) return 0; - /* retrieve the primary */ - SetRect( &rect, 0, 0, 1, 1 ); - return MonitorFromRect( &rect, dwFlags ); + return UlongToHandle( NtUserCallHwndParam( hwnd, flags, NtUserMonitorFromWindow )); } /*********************************************************************** diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c index 2d2c83f503c..8b815c4edc4 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -1219,85 +1219,7 @@ static void update_maximized_pos( WND *wnd, RECT *work_rect ) */ BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl ) { - RECT work_rect = get_maximized_work_rect( hwnd ); - WND *pWnd = WIN_GetPtr( hwnd ); - - if (!pWnd) return FALSE; - - if (pWnd == WND_DESKTOP) - { - wndpl->length = sizeof(*wndpl); - wndpl->showCmd = SW_SHOWNORMAL; - wndpl->flags = 0; - wndpl->ptMinPosition.x = -1; - wndpl->ptMinPosition.y = -1; - wndpl->ptMaxPosition.x = -1; - wndpl->ptMaxPosition.y = -1; - GetWindowRect( hwnd, &wndpl->rcNormalPosition ); - return TRUE; - } - if (pWnd == WND_OTHER_PROCESS) - { - RECT normal_position; - DWORD style; - - if (!GetWindowRect(hwnd, &normal_position)) - return FALSE; - - FIXME("not fully supported on other process window %p.\n", hwnd); - - wndpl->length = sizeof(*wndpl); - style = GetWindowLongW(hwnd, GWL_STYLE); - if (style & WS_MINIMIZE) - wndpl->showCmd = SW_SHOWMINIMIZED; - else - wndpl->showCmd = (style & WS_MAXIMIZE) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL; - /* provide some dummy information */ - wndpl->flags = 0; - wndpl->ptMinPosition.x = -1; - wndpl->ptMinPosition.y = -1; - wndpl->ptMaxPosition.x = -1; - wndpl->ptMaxPosition.y = -1; - wndpl->rcNormalPosition = normal_position; - return TRUE; - } - - /* update the placement according to the current style */ - if (pWnd->dwStyle & WS_MINIMIZE) - { - pWnd->min_pos.x = pWnd->window_rect.left; - pWnd->min_pos.y = pWnd->window_rect.top; - } - else if (pWnd->dwStyle & WS_MAXIMIZE) - { - pWnd->max_pos.x = pWnd->window_rect.left; - pWnd->max_pos.y = pWnd->window_rect.top; - } - else - { - pWnd->normal_rect = pWnd->window_rect; - } - update_maximized_pos( pWnd, &work_rect ); - - 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 = EMPTYPOINT(pWnd->min_pos) ? pWnd->min_pos : point_win_to_thread_dpi( hwnd, pWnd->min_pos ); - wndpl->ptMaxPosition = EMPTYPOINT(pWnd->max_pos) ? pWnd->max_pos : point_win_to_thread_dpi( hwnd, pWnd->max_pos ); - wndpl->rcNormalPosition = rect_win_to_thread_dpi( hwnd, pWnd->normal_rect ); - WIN_ReleasePtr( pWnd ); - - TRACE( "%p: returning min %d,%d max %d,%d normal %s\n", - hwnd, wndpl->ptMinPosition.x, wndpl->ptMinPosition.y, - wndpl->ptMaxPosition.x, wndpl->ptMaxPosition.y, - wine_dbgstr_rect(&wndpl->rcNormalPosition) ); - return TRUE; + return NtUserCallHwndParam( hwnd, (UINT_PTR)wndpl, NtUserGetWindowPlacement ); } /* make sure the specified rect is visible on screen */ diff --git a/dlls/win32u/region.c b/dlls/win32u/region.c index a51388c2fcb..35ef4a22256 100644 --- a/dlls/win32u/region.c +++ b/dlls/win32u/region.c @@ -1376,7 +1376,7 @@ BOOL mirror_window_region( HWND hwnd, HRGN hrgn ) { RECT rect; - if (!get_window_rect( hwnd, &rect )) return FALSE; + if (!get_window_rect( hwnd, &rect, get_thread_dpi() )) return FALSE; return mirror_region( hrgn, hrgn, rect.right - rect.left ) != ERROR; } diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index cffb45b2ef3..39f8cf53345 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1945,7 +1945,7 @@ BOOL WINAPI NtUserEnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc return ret; } -static BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info ) +BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info ) { struct monitor *monitor; UINT dpi_from, dpi_to; @@ -2062,6 +2062,27 @@ HMONITOR monitor_from_point( POINT pt, DWORD flags, UINT dpi ) return monitor_from_rect( &rect, flags, dpi ); } +/* see MonitorFromWindow */ +HMONITOR monitor_from_window( HWND hwnd, DWORD flags, UINT dpi ) +{ + RECT rect; + WINDOWPLACEMENT wp; + + TRACE( "(%p, 0x%08x)\n", hwnd, flags ); + + wp.length = sizeof(wp); + if (is_iconic( hwnd ) && get_window_placement( hwnd, &wp )) + return monitor_from_rect( &wp.rcNormalPosition, flags, dpi ); + + if (get_window_rect( hwnd, &rect, dpi )) + return monitor_from_rect( &rect, flags, dpi ); + + if (!(flags & (MONITOR_DEFAULTTOPRIMARY|MONITOR_DEFAULTTONEAREST))) return 0; + /* retrieve the primary */ + SetRect( &rect, 0, 0, 1, 1 ); + return monitor_from_rect( &rect, flags, dpi ); +} + /*********************************************************************** * NtUserGetSystemDpiForProcess (win32u.@) */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 9db06e1dd76..6bdad368f70 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -289,6 +289,7 @@ extern LRESULT send_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) /* sysparams.c */ extern RECT get_display_rect( const WCHAR *display ) DECLSPEC_HIDDEN; extern UINT get_monitor_dpi( HMONITOR monitor ) DECLSPEC_HIDDEN; +extern BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info ) DECLSPEC_HIDDEN; extern UINT get_win_monitor_dpi( HWND hwnd ) DECLSPEC_HIDDEN; extern RECT get_primary_monitor_rect( UINT dpi ) DECLSPEC_HIDDEN; extern UINT get_system_dpi(void) DECLSPEC_HIDDEN; @@ -299,6 +300,7 @@ extern POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to ) DECLSPEC_HIDD extern RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ) DECLSPEC_HIDDEN; extern HMONITOR monitor_from_point( POINT pt, DWORD flags, UINT dpi ) DECLSPEC_HIDDEN; extern HMONITOR monitor_from_rect( const RECT *rect, DWORD flags, UINT dpi ) DECLSPEC_HIDDEN; +extern HMONITOR monitor_from_window( HWND hwnd, DWORD flags, UINT dpi ) DECLSPEC_HIDDEN; extern void user_lock(void) DECLSPEC_HIDDEN; extern void user_unlock(void) DECLSPEC_HIDDEN; extern void user_check_not_lock(void) DECLSPEC_HIDDEN; @@ -306,10 +308,12 @@ extern void user_check_not_lock(void) DECLSPEC_HIDDEN; /* window.c */ struct tagWND; extern HWND get_desktop_window(void) DECLSPEC_HIDDEN; +extern BOOL get_window_placement( HWND hwnd, WINDOWPLACEMENT *placement ) DECLSPEC_HIDDEN; extern HWND is_current_thread_window( HWND hwnd ) DECLSPEC_HIDDEN; +extern BOOL is_iconic( HWND hwnd ) DECLSPEC_HIDDEN; extern void flush_window_surfaces( BOOL idle ) DECLSPEC_HIDDEN; extern DWORD get_window_long( HWND hwnd, INT offset ) DECLSPEC_HIDDEN; -extern BOOL get_window_rect( HWND hwnd, RECT *rect ) DECLSPEC_HIDDEN; +extern BOOL get_window_rect( HWND hwnd, RECT *rect, UINT dpi ) DECLSPEC_HIDDEN; extern void register_window_surface( struct window_surface *old, struct window_surface *new ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index e5907e8422d..1e80c5d39f8 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -764,7 +764,7 @@ static LONG_PTR get_win_data( const void *ptr, UINT size ) } } -static BOOL is_iconic( HWND hwnd ) +BOOL is_iconic( HWND hwnd ) { return (get_window_long( hwnd, GWL_STYLE ) & WS_MINIMIZE) != 0; } @@ -1001,8 +1001,8 @@ static void mirror_rect( const RECT *window_rect, RECT *rect ) * * Get the window and client rectangles. */ -static BOOL get_window_rects( HWND hwnd, enum coords_relative relative, RECT *window_rect, - RECT *client_rect, UINT dpi ) +BOOL get_window_rects( HWND hwnd, enum coords_relative relative, RECT *window_rect, + RECT *client_rect, UINT dpi ) { WND *win = get_win_ptr( hwnd ); BOOL ret = TRUE; @@ -1134,9 +1134,9 @@ other_process: } /* see GetWindowRect */ -BOOL get_window_rect( HWND hwnd, RECT *rect ) +BOOL get_window_rect( HWND hwnd, RECT *rect, UINT dpi ) { - return get_window_rects( hwnd, COORDS_SCREEN, rect, NULL, get_thread_dpi() ); + return get_window_rects( hwnd, COORDS_SCREEN, rect, NULL, dpi ); } /* see GetClientRect */ @@ -1412,6 +1412,164 @@ HWND WINAPI NtUserWindowFromPoint( LONG x, LONG y ) return window_from_point( 0, pt, &hittest ); } +/******************************************************************* + * get_work_rect + * + * Get the work area that a maximized window can cover, depending on style. + */ +static BOOL get_work_rect( HWND hwnd, RECT *rect ) +{ + HMONITOR monitor = monitor_from_window( hwnd, MONITOR_DEFAULTTOPRIMARY, get_thread_dpi() ); + MONITORINFO mon_info; + DWORD style; + + if (!monitor) return FALSE; + + mon_info.cbSize = sizeof(mon_info); + get_monitor_info( monitor, &mon_info ); + *rect = mon_info.rcMonitor; + + style = get_window_long( hwnd, GWL_STYLE ); + if (style & WS_MAXIMIZEBOX) + { + if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP))) + *rect = mon_info.rcWork; + } + return TRUE; +} + +static RECT get_maximized_work_rect( HWND hwnd ) +{ + RECT work_rect = { 0 }; + + if ((get_window_long( hwnd, GWL_STYLE ) & (WS_MINIMIZE | WS_MAXIMIZE)) == WS_MAXIMIZE) + { + if (!get_work_rect( hwnd, &work_rect )) + work_rect = get_primary_monitor_rect( get_thread_dpi() ); + } + return work_rect; +} + +/******************************************************************* + * update_maximized_pos + * + * For top level windows covering the work area, we might have to + * "forget" the maximized position. Windows presumably does this + * to avoid situations where the border style changes, which would + * lead the window to be outside the screen, or the window gets + * reloaded on a different screen, and the "saved" position no + * longer applies to it (despite being maximized). + * + * Some applications (e.g. Imperiums: Greek Wars) depend on this. + */ +static void update_maximized_pos( WND *wnd, RECT *work_rect ) +{ + if (wnd->parent && wnd->parent != get_desktop_window()) + return; + + if (wnd->dwStyle & WS_MAXIMIZE) + { + if (wnd->window_rect.left <= work_rect->left && wnd->window_rect.top <= work_rect->top && + wnd->window_rect.right >= work_rect->right && wnd->window_rect.bottom >= work_rect->bottom) + wnd->max_pos.x = wnd->max_pos.y = -1; + } + else + wnd->max_pos.x = wnd->max_pos.y = -1; +} + +static BOOL empty_point( POINT pt ) +{ + return pt.x == -1 && pt.y == -1; +} + +/* see GetWindowPlacement */ +BOOL get_window_placement( HWND hwnd, WINDOWPLACEMENT *placement ) +{ + RECT work_rect = get_maximized_work_rect( hwnd ); + WND *win = get_win_ptr( hwnd ); + UINT win_dpi; + + if (!win) return FALSE; + + if (win == WND_DESKTOP) + { + placement->length = sizeof(*placement); + placement->showCmd = SW_SHOWNORMAL; + placement->flags = 0; + placement->ptMinPosition.x = -1; + placement->ptMinPosition.y = -1; + placement->ptMaxPosition.x = -1; + placement->ptMaxPosition.y = -1; + get_window_rect( hwnd, &placement->rcNormalPosition, get_thread_dpi() ); + return TRUE; + } + if (win == WND_OTHER_PROCESS) + { + RECT normal_position; + DWORD style; + + if (!get_window_rect( hwnd, &normal_position, get_thread_dpi() )) + return FALSE; + + FIXME("not fully supported on other process window %p.\n", hwnd); + + placement->length = sizeof(*placement); + style = get_window_long( hwnd, GWL_STYLE ); + if (style & WS_MINIMIZE) + placement->showCmd = SW_SHOWMINIMIZED; + else + placement->showCmd = (style & WS_MAXIMIZE) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL; + /* provide some dummy information */ + placement->flags = 0; + placement->ptMinPosition.x = -1; + placement->ptMinPosition.y = -1; + placement->ptMaxPosition.x = -1; + placement->ptMaxPosition.y = -1; + placement->rcNormalPosition = normal_position; + return TRUE; + } + + /* update the placement according to the current style */ + if (win->dwStyle & WS_MINIMIZE) + { + win->min_pos.x = win->window_rect.left; + win->min_pos.y = win->window_rect.top; + } + else if (win->dwStyle & WS_MAXIMIZE) + { + win->max_pos.x = win->window_rect.left; + win->max_pos.y = win->window_rect.top; + } + else + { + win->normal_rect = win->window_rect; + } + update_maximized_pos( win, &work_rect ); + + placement->length = sizeof(*placement); + if (win->dwStyle & WS_MINIMIZE) + placement->showCmd = SW_SHOWMINIMIZED; + else + placement->showCmd = ( win->dwStyle & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ; + if (win->flags & WIN_RESTORE_MAX) + placement->flags = WPF_RESTORETOMAXIMIZED; + else + placement->flags = 0; + win_dpi = get_dpi_for_window( hwnd ); + placement->ptMinPosition = empty_point(win->min_pos) ? win->min_pos + : map_dpi_point( win->min_pos, win_dpi, get_thread_dpi() ); + placement->ptMaxPosition = empty_point(win->max_pos) ? win->max_pos + : map_dpi_point( win->max_pos, win_dpi, get_thread_dpi() ); + placement->rcNormalPosition = map_dpi_rect( win->normal_rect, win_dpi, get_thread_dpi() ); + release_win_ptr( win ); + + TRACE( "%p: returning min %d,%d max %d,%d normal %s\n", + hwnd, placement->ptMinPosition.x, placement->ptMinPosition.y, + placement->ptMaxPosition.x, placement->ptMaxPosition.y, + wine_dbgstr_rect(&placement->rcNormalPosition) ); + return TRUE; +} + /***************************************************************************** * NtUserBuildHwndList (win32u.@) */ @@ -1602,8 +1760,10 @@ ULONG_PTR WINAPI NtUserCallHwndParam( HWND hwnd, DWORD_PTR param, DWORD code ) return get_window_long_ptr( hwnd, param, TRUE ); case NtUserGetWindowLongPtrW: return get_window_long_ptr( hwnd, param, FALSE ); + case NtUserGetWindowPlacement: + return get_window_placement( hwnd, (WINDOWPLACEMENT *)param ); case NtUserGetWindowRect: - return get_window_rect( hwnd, (RECT *)param ); + return get_window_rect( hwnd, (RECT *)param, get_thread_dpi() ); case NtUserGetWindowRelative: return HandleToUlong( get_window_relative( hwnd, param )); case NtUserGetWindowThread: @@ -1612,6 +1772,8 @@ ULONG_PTR WINAPI NtUserCallHwndParam( HWND hwnd, DWORD_PTR param, DWORD code ) return get_window_word( hwnd, param ); case NtUserIsChild: return is_child( hwnd, UlongToHandle(param) ); + case NtUserMonitorFromWindow: + return HandleToUlong( monitor_from_window( hwnd, param, NtUserMonitorFromWindow )); /* temporary exports */ case NtUserIsWindowDrawable: return is_window_drawable( hwnd, param ); diff --git a/include/ntuser.h b/include/ntuser.h index e6c724fa683..9a25fe72419 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -166,11 +166,13 @@ enum NtUserGetWindowLongW, NtUserGetWindowLongPtrA, NtUserGetWindowLongPtrW, + NtUserGetWindowPlacement, NtUserGetWindowRect, NtUserGetWindowRelative, NtUserGetWindowThread, NtUserGetWindowWord, NtUserIsChild, + NtUserMonitorFromWindow, /* temporary exports */ NtUserIsWindowDrawable, };