From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@codeweavers.com --- dlls/user32/user32.spec | 2 +- dlls/user32/winpos.c | 15 ----- dlls/win32u/gdiobj.c | 1 + dlls/win32u/sysparams.c | 20 ++++++ dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 3 + dlls/win32u/window.c | 119 +++++++++++++++++++++++++++++++++++ dlls/win32u/wrappers.c | 6 ++ include/ntuser.h | 1 + 9 files changed, 152 insertions(+), 17 deletions(-)
diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 555023de110..dfa5c2516b9 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -725,7 +725,7 @@ @ stdcall -arch=win64 SetWindowLongPtrA(long long long) @ stdcall -arch=win64 SetWindowLongPtrW(long long long) @ stdcall SetWindowLongW(long long long) -@ stdcall SetWindowPlacement(long ptr) +@ stdcall SetWindowPlacement(long ptr) NtUserSetWindowPlacement @ stdcall SetWindowPos(long long long long long long long) NtUserSetWindowPos @ stdcall SetWindowRgn(long long long) NtUserSetWindowRgn @ stdcall SetWindowStationUser(long long) diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c index 5987d06c257..d19ebab3e6e 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -428,21 +428,6 @@ static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT f }
-/*********************************************************************** - * SetWindowPlacement (USER32.@) - * - * Win95: - * Fails if wndpl->length of Win95 (!) apps is invalid. - */ -BOOL WINAPI SetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl ) -{ - UINT flags = PLACE_MAX | PLACE_RECT; - if (!wpl) return FALSE; - if (wpl->flags & WPF_SETMINPOSITION) flags |= PLACE_MIN; - return WINPOS_SetPlacement( hwnd, wpl, flags ); -} - - /*********************************************************************** * AnimateWindow (USER32.@) * Shows/Hides a window with an animation diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index 96d52e4d38e..b9c71674e75 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1219,6 +1219,7 @@ static struct unix_funcs unix_funcs = NtUserSetSystemMenu, NtUserSetWindowLong, NtUserSetWindowLongPtr, + NtUserSetWindowPlacement, NtUserSetWindowPos, NtUserSetWindowRgn, NtUserSetWindowWord, diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index dd494188121..f9491313384 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1515,6 +1515,26 @@ POINT point_phys_to_win_dpi( HWND hwnd, POINT pt ) return map_dpi_point( pt, get_win_monitor_dpi( hwnd ), get_dpi_for_window( hwnd )); }
+/********************************************************************** + * point_thread_to_win_dpi + */ +POINT point_thread_to_win_dpi( HWND hwnd, POINT pt ) +{ + UINT dpi = get_thread_dpi(); + if (!dpi) dpi = get_win_monitor_dpi( hwnd ); + return map_dpi_point( pt, dpi, get_dpi_for_window( hwnd )); +} + +/********************************************************************** + * rect_thread_to_win_dpi + */ +RECT rect_thread_to_win_dpi( HWND hwnd, RECT rect ) +{ + UINT dpi = get_thread_dpi(); + if (!dpi) dpi = get_win_monitor_dpi( hwnd ); + return map_dpi_rect( rect, dpi, get_dpi_for_window( hwnd ) ); +} + /* map value from system dpi to standard 96 dpi for storing in the registry */ static int map_from_system_dpi( int val ) { diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 1c3cbc59dc2..1652446a503 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1248,7 +1248,7 @@ @ stub NtUserSetWindowGroup @ stdcall NtUserSetWindowLong(long long long long) @ stdcall NtUserSetWindowLongPtr(long long long long) -@ stub NtUserSetWindowPlacement +@ stdcall NtUserSetWindowPlacement(long ptr) @ stdcall NtUserSetWindowPos(long long long long long long long) @ stdcall NtUserSetWindowRgn(long long long) @ stub NtUserSetWindowRgnEx diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 02784df64f8..c9da765e6a1 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -289,6 +289,7 @@ struct unix_funcs BOOL (WINAPI *pNtUserSetSystemMenu)( HWND hwnd, HMENU menu ); LONG (WINAPI *pNtUserSetWindowLong)( HWND hwnd, INT offset, LONG newval, BOOL ansi ); LONG_PTR (WINAPI *pNtUserSetWindowLongPtr)( HWND hwnd, INT offset, LONG_PTR newval, BOOL ansi ); + BOOL (WINAPI *pNtUserSetWindowPlacement)( HWND hwnd, const WINDOWPLACEMENT *wpl ); BOOL (WINAPI *pNtUserSetWindowPos)( HWND hwnd, HWND after, INT x, INT y, INT cx, INT cy, UINT flags ); int (WINAPI *pNtUserSetWindowRgn)( HWND hwnd, HRGN hrgn, BOOL redraw ); WORD (WINAPI *pNtUserSetWindowWord)( HWND hwnd, INT offset, WORD newval ); @@ -418,6 +419,8 @@ extern BOOL is_exiting_thread( DWORD tid ) DECLSPEC_HIDDEN; extern POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to ) DECLSPEC_HIDDEN; extern RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ) DECLSPEC_HIDDEN; extern POINT point_phys_to_win_dpi( HWND hwnd, POINT pt ) DECLSPEC_HIDDEN; +extern POINT point_thread_to_win_dpi( HWND hwnd, POINT pt ) DECLSPEC_HIDDEN; +extern RECT rect_thread_to_win_dpi( HWND hwnd, RECT rect ) 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; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 31512c03e15..e75f47a2fe6 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -48,6 +48,10 @@ static void *user_handles[NB_USER_HANDLES]; #define SWP_AGG_NOCLIENTCHANGE \ (SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
+#define PLACE_MIN 0x0001 +#define PLACE_MAX 0x0002 +#define PLACE_RECT 0x0004 + /*********************************************************************** * alloc_user_handle */ @@ -2484,6 +2488,121 @@ BOOL get_window_placement( HWND hwnd, WINDOWPLACEMENT *placement ) return TRUE; }
+/* make sure the specified rect is visible on screen */ +static void make_rect_onscreen( RECT *rect ) +{ + MONITORINFO info; + HMONITOR monitor = monitor_from_rect( rect, MONITOR_DEFAULTTONEAREST, get_thread_dpi() ); + + info.cbSize = sizeof(info); + if (!monitor || !get_monitor_info( monitor, &info )) return; + /* FIXME: map coordinates from rcWork to rcMonitor */ + if (rect->right <= info.rcWork.left) + { + rect->right += info.rcWork.left - rect->left; + rect->left = info.rcWork.left; + } + else if (rect->left >= info.rcWork.right) + { + rect->left += info.rcWork.right - rect->right; + rect->right = info.rcWork.right; + } + if (rect->bottom <= info.rcWork.top) + { + rect->bottom += info.rcWork.top - rect->top; + rect->top = info.rcWork.top; + } + else if (rect->top >= info.rcWork.bottom) + { + rect->top += info.rcWork.bottom - rect->bottom; + rect->bottom = info.rcWork.bottom; + } +} + +/* make sure the specified point is visible on screen */ +static void make_point_onscreen( POINT *pt ) +{ + RECT rect; + + SetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 ); + make_rect_onscreen( &rect ); + pt->x = rect.left; + pt->y = rect.top; +} + +static BOOL set_window_placement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT flags ) +{ + RECT work_rect = get_maximized_work_rect( hwnd ); + WND *win = get_win_ptr( hwnd ); + WINDOWPLACEMENT wp = *wndpl; + DWORD style; + + if (flags & PLACE_MIN) make_point_onscreen( &wp.ptMinPosition ); + if (flags & PLACE_MAX) make_point_onscreen( &wp.ptMaxPosition ); + if (flags & PLACE_RECT) make_rect_onscreen( &wp.rcNormalPosition ); + + TRACE( "%p: setting min %d,%d max %d,%d normal %s flags %x adjusted to 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), flags, + wp.ptMinPosition.x, wp.ptMinPosition.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y, + wine_dbgstr_rect(&wp.rcNormalPosition) ); + + if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP) return FALSE; + + if (flags & PLACE_MIN) win->min_pos = point_thread_to_win_dpi( hwnd, wp.ptMinPosition ); + if (flags & PLACE_MAX) + { + win->max_pos = point_thread_to_win_dpi( hwnd, wp.ptMaxPosition ); + update_maximized_pos( win, &work_rect ); + } + if (flags & PLACE_RECT) win->normal_rect = rect_thread_to_win_dpi( hwnd, wp.rcNormalPosition ); + + style = win->dwStyle; + + release_win_ptr( win ); + + if (style & WS_MINIMIZE) + { + if (flags & PLACE_MIN) + { + NtUserSetWindowPos( hwnd, 0, wp.ptMinPosition.x, wp.ptMinPosition.y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); + } + } + else if (style & WS_MAXIMIZE) + { + if (flags & PLACE_MAX) + NtUserSetWindowPos( hwnd, 0, wp.ptMaxPosition.x, wp.ptMaxPosition.y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); + } + else if (flags & PLACE_RECT) + NtUserSetWindowPos( hwnd, 0, wp.rcNormalPosition.left, wp.rcNormalPosition.top, + wp.rcNormalPosition.right - wp.rcNormalPosition.left, + wp.rcNormalPosition.bottom - wp.rcNormalPosition.top, + SWP_NOZORDER | SWP_NOACTIVATE ); + + NtUserShowWindow( hwnd, wndpl->showCmd ); + + if (is_iconic( hwnd )) + { + if (wndpl->flags & WPF_RESTORETOMAXIMIZED) + win_set_flags( hwnd, WIN_RESTORE_MAX, 0 ); + } + return TRUE; +} + +/*********************************************************************** + * NtUserSetWindowPlacement (win32u.@) + */ +BOOL WINAPI NtUserSetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl ) +{ + UINT flags = PLACE_MAX | PLACE_RECT; + if (!wpl) return FALSE; + if (wpl->flags & WPF_SETMINPOSITION) flags |= PLACE_MIN; + return set_window_placement( hwnd, wpl, flags ); +} + /***************************************************************************** * NtUserBuildHwndList (win32u.@) */ diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index 4e750e5aea2..64f823ccd26 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -1227,6 +1227,12 @@ LONG_PTR WINAPI NtUserSetWindowLongPtr( HWND hwnd, INT offset, LONG_PTR newval, return unix_funcs->pNtUserSetWindowLongPtr( hwnd, offset, newval, ansi ); }
+BOOL WINAPI NtUserSetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl ) +{ + if (!unix_funcs) return 0; + return unix_funcs->pNtUserSetWindowPlacement( hwnd, wpl ); +} + BOOL WINAPI NtUserSetWindowPos( HWND hwnd, HWND after, INT x, INT y, INT cx, INT cy, UINT flags ) { if (!unix_funcs) return 0; diff --git a/include/ntuser.h b/include/ntuser.h index a39fffaedf9..af87d8a5fec 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -641,6 +641,7 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ); UINT_PTR WINAPI NtUserSetTimer( HWND hwnd, UINT_PTR id, UINT timeout, TIMERPROC proc, ULONG tolerance ); LONG WINAPI NtUserSetWindowLong( HWND hwnd, INT offset, LONG newval, BOOL ansi ); LONG_PTR WINAPI NtUserSetWindowLongPtr( HWND hwnd, INT offset, LONG_PTR newval, BOOL ansi ); +BOOL WINAPI NtUserSetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl ); BOOL WINAPI NtUserSetWindowPos( HWND hwnd, HWND after, INT x, INT y, INT cx, INT cy, UINT flags ); int WINAPI NtUserSetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw ); WORD WINAPI NtUserSetWindowWord( HWND hwnd, INT offset, WORD newval );