[PATCH v3 0/5] MR11301: win32u: Introduce a ratio struct for unix-side DPI values.
When display mode emulation is used, DPI values computed from monitor emulated resolution may cause precision loss and small window size and position innacuracies when converting virtual to physical coordinates. Based on patches from Paul Gofman. -- v3: server: Move window monitor DPI to the shared memory. win32u: Represent raw monitor dpi as rational value. server: Use the ratio struct for DPI values. win32u: Introduce a ratio struct for unix-side DPI values. win32u: Use internal helpers to get present / client rects and dpi. https://gitlab.winehq.org/wine/wine/-/merge_requests/11301
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/win32u/vulkan.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 310ce8923c9..416d4eeb833 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -1576,7 +1576,7 @@ static void win32u_vkDestroySurfaceKHR( VkInstance client_instance, VkSurfaceKHR static BOOL get_surface_rect( HWND hwnd, RECT *rect, UINT dpi ) { - if (!NtUserGetPresentRect( hwnd, rect, dpi ) && !NtUserGetClientRect( hwnd, rect, dpi )) return FALSE; + if (!get_present_rect( hwnd, rect, dpi ) && !get_client_rect( hwnd, rect, dpi )) return FALSE; OffsetRect( rect, -rect->left, -rect->top ); return TRUE; } @@ -1597,7 +1597,7 @@ static void adjust_surface_capabilities( struct vulkan_instance *instance, struc /* Update the image extents to match what the Win32 WSI would provide. */ /* FIXME: handle DPI scaling, somehow */ - get_surface_rect( surface->hwnd, &client_rect, NtUserGetDpiForWindow( surface->hwnd ) ); + get_surface_rect( surface->hwnd, &client_rect, get_dpi_for_window( surface->hwnd ) ); capabilities->minImageExtent.width = client_rect.right - client_rect.left; capabilities->minImageExtent.height = client_rect.bottom - client_rect.top; capabilities->maxImageExtent.width = client_rect.right - client_rect.left; @@ -1827,6 +1827,7 @@ static VkResult win32u_vkCreateSwapchainKHR( VkDevice client_device, const VkSwa VkSwapchainKHR host_swapchain; RECT client_rect; VkResult res; + UINT raw_dpi; if (!NtUserIsWindow( surface->hwnd )) { @@ -1848,7 +1849,8 @@ static VkResult win32u_vkCreateSwapchainKHR( VkDevice client_device, const VkSwa * display mode change emulation), MoltenVK's vkQueuePresentKHR returns VK_SUBOPTIMAL_KHR. * Create the swapchain with VkSwapchainPresentScalingCreateInfoEXT to avoid this. */ - if (get_surface_rect( surface->hwnd, &client_rect, NtUserGetWinMonitorDpi( surface->hwnd, MDT_RAW_DPI ) ) && + get_win_monitor_dpi( surface->hwnd, &raw_dpi ); + if (get_surface_rect( surface->hwnd, &client_rect, raw_dpi ) && !extents_equals( &create_info_host.imageExtent, &client_rect ) && instance->extensions.has_VK_EXT_surface_maintenance1 && physical_device->extensions.has_VK_KHR_swapchain_maintenance1) @@ -1907,7 +1909,7 @@ static VkResult win32u_vkAcquireNextImage2KHR( VkDevice client_device, const VkA acquire_info_host.fence = fence ? fence->host.fence : 0; res = device->p_vkAcquireNextImage2KHR( device->host.device, &acquire_info_host, image_index ); - if (!res && get_surface_rect( surface->hwnd, &client_rect, NtUserGetDpiForWindow( surface->hwnd ) ) && + if (!res && get_surface_rect( surface->hwnd, &client_rect, get_dpi_for_window( surface->hwnd ) ) && !extents_equals( &swapchain->extents, &client_rect )) { WARN( "Swapchain size %dx%d does not match client rect %s, returning VK_SUBOPTIMAL_KHR\n", @@ -1933,7 +1935,7 @@ static VkResult win32u_vkAcquireNextImageKHR( VkDevice client_device, VkSwapchai semaphore ? semaphore->host.semaphore : 0, fence ? fence->host.fence : 0, image_index ); - if (!res && get_surface_rect( surface->hwnd, &client_rect, NtUserGetDpiForWindow( surface->hwnd ) ) && + if (!res && get_surface_rect( surface->hwnd, &client_rect, get_dpi_for_window( surface->hwnd ) ) && !extents_equals( &swapchain->extents, &client_rect )) { WARN( "Swapchain size %dx%d does not match client rect %s, returning VK_SUBOPTIMAL_KHR\n", @@ -1994,7 +1996,7 @@ static VkResult win32u_vkQueuePresentKHR( VkQueue client_queue, const VkPresentI client_surface_present( surface->client ); if (swapchain_res < VK_SUCCESS) continue; - if (!get_surface_rect( surface->hwnd, &client_rect, NtUserGetDpiForWindow( surface->hwnd ) )) + if (!get_surface_rect( surface->hwnd, &client_rect, get_dpi_for_window( surface->hwnd ) )) { WARN( "Swapchain window %p is invalid, returning VK_ERROR_OUT_OF_DATE_KHR\n", surface->hwnd ); if (present_info->pResults) present_info->pResults[i] = VK_ERROR_OUT_OF_DATE_KHR; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11301
From: Rémi Bernon <rbernon@codeweavers.com> When display mode emulation is used, DPI values computed from monitor emulated resolution may cause precision loss and small window size and position innacuracies when converting virtual to physical coordinates. Based on patches from Paul Gofman. --- dlls/win32u/clipping.c | 2 +- dlls/win32u/d3dkmt.c | 2 +- dlls/win32u/dce.c | 20 ++-- dlls/win32u/defwnd.c | 9 +- dlls/win32u/driver.c | 5 +- dlls/win32u/input.c | 18 ++-- dlls/win32u/message.c | 4 +- dlls/win32u/scroll.c | 4 +- dlls/win32u/sysparams.c | 193 ++++++++++++++++++++--------------- dlls/win32u/vulkan.c | 4 +- dlls/win32u/win32u_private.h | 49 ++++----- dlls/win32u/window.c | 115 +++++++++++---------- server/protocol.def | 6 ++ 13 files changed, 242 insertions(+), 189 deletions(-) diff --git a/dlls/win32u/clipping.c b/dlls/win32u/clipping.c index cf71cf0645c..60e8ee6ba16 100644 --- a/dlls/win32u/clipping.c +++ b/dlls/win32u/clipping.c @@ -463,7 +463,7 @@ INT WINAPI NtGdiGetRandomRgn( HDC hDC, HRGN hRgn, INT iCode ) if (ret > 0 && (iCode & NTGDI_RGN_MONITOR_DPI)) { HWND hwnd = NtUserWindowFromDC( hDC ); - UINT raw_dpi; + struct ratio raw_dpi; HRGN region; get_win_monitor_dpi( hwnd, &raw_dpi ); diff --git a/dlls/win32u/d3dkmt.c b/dlls/win32u/d3dkmt.c index 1b33976f333..9b5d4a8c919 100644 --- a/dlls/win32u/d3dkmt.c +++ b/dlls/win32u/d3dkmt.c @@ -550,7 +550,7 @@ NTSTATUS WINAPI NtGdiDdDDIEscape( const D3DKMT_ESCAPE *desc ) { HWND hwnd = UlongToHandle( desc->hContext ); RECT *rect = desc->pPrivateDriverData; - UINT dpi = get_dpi_for_window( hwnd ); + struct ratio dpi = get_dpi_for_window( hwnd ); WND *win; if (desc->PrivateDriverDataSize != sizeof(*rect)) return STATUS_INVALID_PARAMETER; diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index ad27cb143ae..5e8d82aed34 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -144,8 +144,8 @@ struct scaled_surface { struct window_surface header; struct window_surface *target_surface; - UINT dpi_from; - UINT dpi_to; + struct ratio dpi_from; + struct ratio dpi_to; }; static struct scaled_surface *get_scaled_surface( struct window_surface *window_surface ) @@ -223,14 +223,14 @@ static const struct window_surface_funcs scaled_surface_funcs = scaled_surface_destroy }; -static void scaled_surface_set_target( struct scaled_surface *surface, struct window_surface *target, UINT dpi_to ) +static void scaled_surface_set_target( struct scaled_surface *surface, struct window_surface *target, struct ratio dpi_to ) { if (surface->target_surface) window_surface_release( surface->target_surface ); window_surface_add_ref( (surface->target_surface = target) ); surface->dpi_to = dpi_to; } -static struct window_surface *scaled_surface_create( HWND hwnd, const RECT *surface_rect, UINT dpi_from, UINT dpi_to, +static struct window_surface *scaled_surface_create( HWND hwnd, const RECT *surface_rect, struct ratio dpi_from, struct ratio dpi_to, struct window_surface *target_surface ) { char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; @@ -269,11 +269,11 @@ static RECT get_surface_rect( RECT rect ) return rect; } -void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, UINT monitor_dpi, +void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, struct ratio monitor_dpi, struct window_surface **window_surface ) { struct window_surface *previous, *driver_surface; - UINT dpi = get_dpi_for_window( hwnd ); + struct ratio dpi = get_dpi_for_window( hwnd ); RECT monitor_rect; @@ -296,7 +296,7 @@ void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_ return; } - if (!driver_surface || dpi == monitor_dpi) + if (!driver_surface || !memcmp( &dpi, &monitor_dpi, sizeof(monitor_dpi) )) { if (*window_surface) window_surface_release( *window_surface ); *window_surface = driver_surface; @@ -317,11 +317,11 @@ void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_ window_surface_release( driver_surface ); } -struct window_surface *get_driver_window_surface( struct window_surface *surface, UINT monitor_dpi ) +struct window_surface *get_driver_window_surface( struct window_surface *surface, struct ratio monitor_dpi ) { if (!surface || surface == &dummy_surface) return surface; if (surface->funcs != &scaled_surface_funcs) return surface; - if (get_scaled_surface( surface )->dpi_to != monitor_dpi) return &dummy_surface; + if (memcmp( &get_scaled_surface( surface )->dpi_to, &monitor_dpi, sizeof(monitor_dpi) )) return &dummy_surface; return get_scaled_surface( surface )->target_surface; } @@ -1936,7 +1936,7 @@ BOOL WINAPI NtUserGetUpdateRect( HWND hwnd, RECT *rect, BOOL erase ) { HDC hdc = NtUserGetDCEx( hwnd, 0, DCX_USESTYLE ); DWORD layout = NtGdiSetLayout( hdc, -1, 0 ); /* map_window_points mirrors already */ - UINT win_dpi = get_dpi_for_window( hwnd ); + struct ratio win_dpi = get_dpi_for_window( hwnd ); map_window_points( 0, hwnd, (POINT *)rect, 2, win_dpi ); *rect = map_dpi_rect( *rect, win_dpi, get_thread_dpi() ); NtGdiTransformPoints( hdc, (POINT *)rect, (POINT *)rect, 2, NtGdiDPtoLP ); diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index 5951374fc9a..d6852b33ce2 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -37,6 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); #define KEYDATA_ALT 0x2000 #define KEYDATA_PREVSTATE 0x4000 +static const struct ratio no_dpi; static short f10_key = 0; static short menu_sys_key = 0; @@ -682,8 +683,8 @@ static void sys_command_size_move( HWND hwnd, WPARAM wparam ) UINT style = get_window_long( hwnd, GWL_STYLE ); POINT capture_point, pt; MINMAXINFO minmax; + struct ratio dpi; HWND parent; - UINT dpi; HDC hdc; MSG msg; @@ -975,7 +976,7 @@ static LRESULT handle_sys_command( HWND hwnd, WPARAM wparam, LPARAM lparam ) pos.y = (short)HIWORD( msgpos ); NtUserLogicalToPerMonitorDPIPhysicalPoint( hwnd, &pos ); SetRect( &rect, pos.x, pos.y, pos.x, pos.y ); - rect = map_rect_virt_to_raw( rect, 0 ); + rect = map_rect_virt_to_raw( rect, no_dpi ); pos.x = rect.left; pos.y = rect.top; @@ -1477,7 +1478,7 @@ static void draw_close_button( HWND hwnd, HDC hdc, BOOL down, BOOL grayed ) { /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE * it uses 11x11 for the close button in tool window */ - int bmp_height = muldiv( 11, get_dpi_for_window( hwnd ), 96 ); + int bmp_height = map_user_dpi( 11, get_dpi_for_window( hwnd ) ); int bmp_width = bmp_height; int caption_height = get_system_metrics( SM_CYSMCAPTION ); @@ -3038,7 +3039,7 @@ LRESULT desktop_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, { static RECT virtual_rect = {INT_MIN,INT_MIN,INT_MAX,INT_MAX}; - RECT new_rect = get_virtual_screen_rect( 0, MDT_DEFAULT ), old_rect = virtual_rect; + RECT new_rect = get_virtual_screen_rect( no_dpi, MDT_DEFAULT ), old_rect = virtual_rect; UINT context, flags = 0; if (EqualRect( &new_rect, &old_rect )) return TRUE; diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 27259fd8506..6270d9bbe10 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -36,6 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(driver); WINE_DECLARE_DEBUG_CHANNEL(winediag); +static const struct ratio no_dpi; static const struct user_driver_funcs lazy_load_driver; static struct user_driver_funcs null_user_driver; static WCHAR driver_load_error[80]; @@ -252,14 +253,14 @@ static INT nulldrv_GetDeviceCaps( PHYSDEV dev, INT cap ) case DESKTOPHORZRES: if (NtGdiGetDeviceCaps( dev->hdc, TECHNOLOGY ) == DT_RASDISPLAY) { - RECT rect = get_virtual_screen_rect( 0, MDT_DEFAULT ); + RECT rect = get_virtual_screen_rect( no_dpi, MDT_DEFAULT ); return rect.right - rect.left; } return NtGdiGetDeviceCaps( dev->hdc, HORZRES ); case DESKTOPVERTRES: if (NtGdiGetDeviceCaps( dev->hdc, TECHNOLOGY ) == DT_RASDISPLAY) { - RECT rect = get_virtual_screen_rect( 0, MDT_DEFAULT ); + RECT rect = get_virtual_screen_rect( no_dpi, MDT_DEFAULT ); return rect.bottom - rect.top; } return NtGdiGetDeviceCaps( dev->hdc, VERTRES ); diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index ce7d0d4de58..8a130c4660c 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -42,6 +42,8 @@ WINE_DECLARE_DEBUG_CHANNEL(keyboard); #define HIMETRIC_PER_INCH 2540 +static const struct ratio no_dpi; + static const WCHAR keyboard_layouts_keyW[] = { '\\','R','e','g','i','s','t','r','y', @@ -621,9 +623,9 @@ static void update_mouse_coords( INPUT *input ) RECT rc; if (input->mi.dwFlags & MOUSEEVENTF_VIRTUALDESK) - rc = get_virtual_screen_rect( 0, MDT_DEFAULT ); + rc = get_virtual_screen_rect( no_dpi, MDT_DEFAULT ); else - rc = get_primary_monitor_rect( 0 ); + rc = get_primary_monitor_rect( no_dpi ); input->mi.dx = rc.left + ((input->mi.dx * (rc.right - rc.left)) >> 16); input->mi.dy = rc.top + ((input->mi.dy * (rc.bottom - rc.top)) >> 16); @@ -2480,7 +2482,7 @@ BOOL set_ime_composition_rect( HWND hwnd, RECT rect ) { if (!NtUserIsWindow( hwnd )) return FALSE; NtUserMapWindowPoints( hwnd, 0, (POINT *)&rect, 2, 0 /* per-monitor DPI */ ); - rect = map_rect_virt_to_raw( rect, 0 /* per-monitor DPI */ ); + rect = map_rect_virt_to_raw( rect, no_dpi /* per-monitor DPI */ ); return user_driver->pSetIMECompositionRect( NtUserGetAncestor( hwnd, GA_ROOT ), rect ); } @@ -2748,7 +2750,7 @@ BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_P return FALSE; } -static BOOL get_clip_cursor( RECT *rect, UINT dpi, MONITOR_DPI_TYPE type ) +static BOOL get_clip_cursor( RECT *rect, struct ratio dpi, MONITOR_DPI_TYPE type ) { struct object_lock lock = OBJECT_LOCK_INIT; const desktop_shm_t *desktop_shm; @@ -2766,7 +2768,7 @@ static BOOL get_clip_cursor( RECT *rect, UINT dpi, MONITOR_DPI_TYPE type ) BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) { struct user_thread_info *thread_info = get_user_thread_info(); - RECT rect, virtual_rect = get_virtual_screen_rect( 0, MDT_RAW_DPI ); + RECT rect, virtual_rect = get_virtual_screen_rect( no_dpi, MDT_RAW_DPI ); BOOL was_clipping, empty = !!(flags & SET_CURSOR_NOCLIP); TRACE( "hwnd %p, flags %#x, reset %u\n", hwnd, flags, reset ); @@ -2783,7 +2785,7 @@ BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) if (!grab_pointer) return TRUE; /* we are clipping if the clip rectangle is smaller than the screen */ - get_clip_cursor( &rect, 0, MDT_RAW_DPI ); + get_clip_cursor( &rect, no_dpi, MDT_RAW_DPI ); intersect_rect( &rect, &rect, &virtual_rect ); if (EqualRect( &rect, &virtual_rect )) empty = TRUE; if (empty && !(flags & SET_CURSOR_FSCLIP)) @@ -2812,7 +2814,7 @@ BOOL WINAPI NtUserGetClipCursor( RECT *rect ) */ BOOL WINAPI NtUserClipCursor( const RECT *rect ) { - UINT dpi = get_thread_dpi(); + struct ratio dpi = get_thread_dpi(); RECT new_rect; BOOL ret; @@ -2903,7 +2905,7 @@ BOOL WINAPI NtUserGetPointerDeviceRects( HANDLE handle, RECT *device_rect, RECT return FALSE; } - rect = get_virtual_screen_rect( 0, MDT_DEFAULT ); + rect = get_virtual_screen_rect( no_dpi, MDT_DEFAULT ); SetRect( device_rect, 0, 0, (rect.right - rect.left) * HIMETRIC_PER_INCH / get_system_dpi(), (rect.bottom - rect.top) * HIMETRIC_PER_INCH / get_system_dpi() ); *display_rect = get_virtual_screen_rect( get_thread_dpi(), MDT_DEFAULT ); diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index b6cdd3efa0e..13356ea3a7a 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -47,6 +47,8 @@ WINE_DECLARE_DEBUG_CHANNEL(relay); static const struct _KUSER_SHARED_DATA *user_shared_data = (struct _KUSER_SHARED_DATA *)0x7ffe0000; +static const struct ratio no_dpi; + static LONG atomic_load_long( const volatile LONG *ptr ) { #if defined(__i386__) || defined(__x86_64__) @@ -3116,7 +3118,7 @@ static int peek_message( MSG *msg, const struct peek_message_filter *filter ) RECT rect = {info.msg.pt.x, info.msg.pt.y, info.msg.pt.x, info.msg.pt.y}; MSLLHOOKSTRUCT hook; - rect = map_rect_raw_to_virt( rect, 0 ); + rect = map_rect_raw_to_virt( rect, no_dpi ); info.msg.pt.x = rect.left; info.msg.pt.y = rect.top; diff --git a/dlls/win32u/scroll.c b/dlls/win32u/scroll.c index 00450c20709..e864b271225 100644 --- a/dlls/win32u/scroll.c +++ b/dlls/win32u/scroll.c @@ -253,7 +253,7 @@ static BOOL get_scroll_bar_rect( HWND hwnd, int bar, RECT *rect, int *arrow_size if (info->page) { *thumb_size = muldiv( pixels,info->page, info->maxVal - info->minVal + 1 ); - min_thumb_size = muldiv( SCROLL_MIN_THUMB, get_dpi_for_window( hwnd ), 96 ); + min_thumb_size = map_user_dpi( SCROLL_MIN_THUMB, get_dpi_for_window( hwnd ) ); if (*thumb_size < min_thumb_size) *thumb_size = min_thumb_size; } else *thumb_size = get_system_metrics( SM_CXVSCROLL ); @@ -475,7 +475,7 @@ static UINT get_thumb_val( HWND hwnd, int bar, RECT *rect, BOOL vertical, int po if (info->page) { thumb_size = muldiv( pixels, info->page, info->maxVal - info->minVal + 1 ); - min_thumb_size = muldiv( SCROLL_MIN_THUMB, get_dpi_for_window( hwnd ), 96 ); + min_thumb_size = map_user_dpi( SCROLL_MIN_THUMB, get_dpi_for_window( hwnd ) ); if (thumb_size < min_thumb_size) thumb_size = min_thumb_size; } else thumb_size = get_system_metrics( SM_CXVSCROLL ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 239d13df6cc..e1b04b0317e 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -292,6 +292,7 @@ union sysparam_all_entry struct sysparam_pref_entry pref; }; +static const struct ratio no_dpi; static UINT system_dpi; static RECT work_area; static DWORD process_layout = ~0u; @@ -2304,7 +2305,7 @@ static void monitor_virt_to_raw_ratio( struct monitor *monitor, UINT *num, UINT } /* display_lock must be held */ -static UINT monitor_get_dpi( struct monitor *monitor, MONITOR_DPI_TYPE type, UINT *dpi_x, UINT *dpi_y ) +static struct ratio monitor_get_dpi( struct monitor *monitor, MONITOR_DPI_TYPE type, struct ratio *dpi_x, struct ratio *dpi_y ) { struct source *source = monitor->source; float scale_x = 1.0, scale_y = 1.0; @@ -2317,16 +2318,18 @@ static UINT monitor_get_dpi( struct monitor *monitor, MONITOR_DPI_TYPE type, UIN scale_y = source->physical.dmPelsHeight / (float)source->current.dmPelsHeight; } - *dpi_x = round( dpi * scale_x ); - *dpi_y = round( dpi * scale_y ); - return min( *dpi_x, *dpi_y ); + dpi_x->num = round( dpi * scale_x ); + dpi_x->den = 1; + dpi_y->num = round( dpi * scale_y ); + dpi_y->den = 1; + return dpi_x->num < dpi_y->num ? *dpi_x : *dpi_y; } /* display_lock must be held */ -static RECT map_monitor_rect( struct monitor *monitor, RECT rect, UINT dpi_from, MONITOR_DPI_TYPE type_from, - UINT dpi_to, MONITOR_DPI_TYPE type_to ) +static RECT map_monitor_rect( struct monitor *monitor, RECT rect, struct ratio dpi_from, MONITOR_DPI_TYPE type_from, + struct ratio dpi_to, MONITOR_DPI_TYPE type_to ) { - UINT x, y; + struct ratio x, y; assert( type_from != type_to ); @@ -2334,14 +2337,15 @@ static RECT map_monitor_rect( struct monitor *monitor, RECT rect, UINT dpi_from, { double points[4] = {rect.left, rect.top, rect.right, rect.bottom}, from[2], to[2]; DEVMODEW current_mode = {.dmSize = sizeof(DEVMODEW)}, physical_mode; - UINT num, den, dpi; + struct ratio dpi; + UINT num, den; source_get_current_settings( monitor->source, ¤t_mode ); physical_mode = monitor->source->physical; dpi = monitor_get_dpi( monitor, MDT_DEFAULT, &x, &y ); - if (!dpi_from) dpi_from = dpi; - if (!dpi_to) dpi_to = dpi; + if (!dpi_from.num) dpi_from = dpi; + if (!dpi_to.num) dpi_to = dpi; if (type_from == MDT_RAW_DPI) { @@ -2362,11 +2366,11 @@ static RECT map_monitor_rect( struct monitor *monitor, RECT rect, UINT dpi_from, for (int i = 0; i < ARRAY_SIZE(points); i++) { - points[i] *= (double)dpi / dpi_from; + points[i] *= (double)dpi.num / dpi_from.num; points[i] -= from[i & 1]; points[i] *= (double)num / den; points[i] += to[i & 1]; - points[i] *= (double)dpi_to / dpi; + points[i] *= (double)dpi_to.num / dpi.num; points[i] = roundf( points[i] ); points[i] = min( INT_MAX, max( INT_MIN, (INT64)points[i] )); } @@ -2375,18 +2379,18 @@ static RECT map_monitor_rect( struct monitor *monitor, RECT rect, UINT dpi_from, return rect; } - if (!dpi_from) dpi_from = monitor_get_dpi( monitor, type_from, &x, &y ); - if (!dpi_to) dpi_to = monitor_get_dpi( monitor, type_to, &x, &y ); + if (!dpi_from.num) dpi_from = monitor_get_dpi( monitor, type_from, &x, &y ); + if (!dpi_to.num) dpi_to = monitor_get_dpi( monitor, type_to, &x, &y ); return map_dpi_rect( rect, dpi_from, dpi_to ); } /* display_lock must be held */ -static RECT monitor_get_rect( struct monitor *monitor, UINT dpi, MONITOR_DPI_TYPE type ) +static RECT monitor_get_rect( struct monitor *monitor, struct ratio dpi, MONITOR_DPI_TYPE type ) { DEVMODEW current_mode = {.dmSize = sizeof(DEVMODEW)}; RECT rect = {0, 0, 1024, 768}; + struct ratio dpi_from, x, y; struct source *source; - UINT dpi_from, x, y; DEVMODEW *mode; /* services do not have any adapters, only a virtual monitor */ @@ -2406,10 +2410,10 @@ static RECT monitor_get_rect( struct monitor *monitor, UINT dpi, MONITOR_DPI_TYP } /* display_lock must be held */ -static void monitor_get_info( struct monitor *monitor, MONITORINFO *info, UINT dpi ) +static void monitor_get_info( struct monitor *monitor, MONITORINFO *info, struct ratio dpi ) { info->rcMonitor = monitor_get_rect( monitor, dpi, MDT_DEFAULT ); - info->rcWork = map_monitor_rect( monitor, monitor->rc_work, 0, MDT_RAW_DPI, dpi, MDT_DEFAULT ); + info->rcWork = map_monitor_rect( monitor, monitor->rc_work, no_dpi, MDT_RAW_DPI, dpi, MDT_DEFAULT ); intersect_rect( &info->rcWork, &info->rcWork, &info->rcMonitor ); info->dwFlags = is_monitor_primary( monitor ) ? MONITORINFOF_PRIMARY : 0; @@ -2427,7 +2431,8 @@ static void set_winstation_monitors( BOOL increment ) { struct monitor_info *infos, *info; struct monitor *monitor; - UINT count, x, y; + struct ratio x, y; + UINT count; if (!(count = list_count( &monitors ))) return; if (!(info = infos = calloc( count, sizeof(*infos) ))) return; @@ -2437,9 +2442,9 @@ static void set_winstation_monitors( BOOL increment ) if (is_monitor_primary( monitor )) info->flags |= MONITOR_FLAG_PRIMARY; if (!is_monitor_active( monitor )) info->flags |= MONITOR_FLAG_INACTIVE; if (monitor->is_clone) info->flags |= MONITOR_FLAG_CLONE; - info->dpi = monitor_get_dpi( monitor, MDT_EFFECTIVE_DPI, &x, &y ); - info->virt = wine_server_rectangle( monitor_get_rect( monitor, 0, MDT_EFFECTIVE_DPI ) ); - info->raw = wine_server_rectangle( monitor_get_rect( monitor, 0, MDT_RAW_DPI ) ); + info->dpi = monitor_get_dpi( monitor, MDT_EFFECTIVE_DPI, &x, &y ).num; + info->virt = wine_server_rectangle( monitor_get_rect( monitor, no_dpi, MDT_EFFECTIVE_DPI ) ); + info->raw = wine_server_rectangle( monitor_get_rect( monitor, no_dpi, MDT_RAW_DPI ) ); info++; } @@ -2924,7 +2929,7 @@ HBITMAP get_display_bitmap(void) RECT virtual_rect; HBITMAP ret; - virtual_rect = get_virtual_screen_rect( 0, MDT_DEFAULT ); + virtual_rect = get_virtual_screen_rect( no_dpi, MDT_DEFAULT ); pthread_mutex_lock( &display_dc_lock ); if (!EqualRect( &old_virtual_rect, &virtual_rect )) { @@ -2944,7 +2949,7 @@ static void release_display_dc( HDC hdc ) } /* display_lock must be held, keep in sync with server/window.c */ -static struct monitor *get_monitor_from_rect( RECT rect, UINT flags, UINT dpi, MONITOR_DPI_TYPE type ) +static struct monitor *get_monitor_from_rect( RECT rect, UINT flags, struct ratio dpi, MONITOR_DPI_TYPE type ) { struct monitor *monitor, *primary = NULL, *nearest = NULL, *found = NULL; UINT max_area = 0, min_distance = -1; @@ -3019,7 +3024,7 @@ static struct monitor *get_monitor_from_handle( HMONITOR handle ) } /* display_lock must be held */ -static RECT monitors_get_union_rect( UINT dpi, MONITOR_DPI_TYPE type ) +static RECT monitors_get_union_rect( struct ratio dpi, MONITOR_DPI_TYPE type ) { struct monitor *monitor; RECT rect = {0}; @@ -3036,35 +3041,35 @@ static RECT monitors_get_union_rect( UINT dpi, MONITOR_DPI_TYPE type ) } /* map a monitor rect from MDT_RAW_DPI to MDT_DEFAULT coordinates */ -RECT map_rect_raw_to_virt( RECT rect, UINT dpi_to ) +RECT map_rect_raw_to_virt( RECT rect, struct ratio dpi_to ) { RECT pos = {rect.left, rect.top, rect.left, rect.top}; struct monitor *monitor; if (!lock_display_devices( FALSE )) return rect; - if ((monitor = get_monitor_from_rect( pos, MONITOR_DEFAULTTONEAREST, 0, MDT_RAW_DPI ))) - rect = map_monitor_rect( monitor, rect, 0, MDT_RAW_DPI, dpi_to, MDT_DEFAULT ); + if ((monitor = get_monitor_from_rect( pos, MONITOR_DEFAULTTONEAREST, no_dpi, MDT_RAW_DPI ))) + rect = map_monitor_rect( monitor, rect, no_dpi, MDT_RAW_DPI, dpi_to, MDT_DEFAULT ); unlock_display_devices(); return rect; } /* map a monitor rect from MDT_DEFAULT to MDT_RAW_DPI coordinates */ -RECT map_rect_virt_to_raw( RECT rect, UINT dpi_from ) +RECT map_rect_virt_to_raw( RECT rect, struct ratio dpi_from ) { RECT pos = {rect.left, rect.top, rect.left, rect.top}; struct monitor *monitor; if (!lock_display_devices( FALSE )) return rect; if ((monitor = get_monitor_from_rect( pos, MONITOR_DEFAULTTONEAREST, dpi_from, MDT_DEFAULT ))) - rect = map_monitor_rect( monitor, rect, dpi_from, MDT_DEFAULT, 0, MDT_RAW_DPI ); + rect = map_monitor_rect( monitor, rect, dpi_from, MDT_DEFAULT, no_dpi, MDT_RAW_DPI ); unlock_display_devices(); return rect; } /* map (absolute) window rects from MDT_DEFAULT to MDT_RAW_DPI coordinates */ -struct window_rects map_window_rects_virt_to_raw( struct window_rects rects, UINT dpi_from ) +struct window_rects map_window_rects_virt_to_raw( struct window_rects rects, struct ratio dpi_from ) { RECT rect, monitor_rect, virt_visible_rect = rects.visible; struct monitor *monitor; @@ -3073,9 +3078,9 @@ struct window_rects map_window_rects_virt_to_raw( struct window_rects rects, UIN if (!lock_display_devices( FALSE )) return rects; if ((monitor = get_monitor_from_rect( rects.window, MONITOR_DEFAULTTONEAREST, dpi_from, MDT_DEFAULT ))) { - rects.visible = map_monitor_rect( monitor, rects.visible, dpi_from, MDT_DEFAULT, 0, MDT_RAW_DPI ); - rects.window = map_monitor_rect( monitor, rects.window, dpi_from, MDT_DEFAULT, 0, MDT_RAW_DPI ); - rects.client = map_monitor_rect( monitor, rects.client, dpi_from, MDT_DEFAULT, 0, MDT_RAW_DPI ); + rects.visible = map_monitor_rect( monitor, rects.visible, dpi_from, MDT_DEFAULT, no_dpi, MDT_RAW_DPI ); + rects.window = map_monitor_rect( monitor, rects.window, dpi_from, MDT_DEFAULT, no_dpi, MDT_RAW_DPI ); + rects.client = map_monitor_rect( monitor, rects.client, dpi_from, MDT_DEFAULT, no_dpi, MDT_RAW_DPI ); } /* if the visible rect is fullscreen, make it cover the full raw monitor, regardless of aspect ratio */ LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry) @@ -3086,7 +3091,7 @@ struct window_rects map_window_rects_virt_to_raw( struct window_rects rects, UIN is_fullscreen = intersect_rect( &rect, &monitor_rect, &virt_visible_rect ) && EqualRect( &rect, &monitor_rect ); if (is_fullscreen) { - rect = monitor_get_rect( monitor, 0, MDT_RAW_DPI ); + rect = monitor_get_rect( monitor, no_dpi, MDT_RAW_DPI ); union_rect( &rects.visible, &rects.visible, &rect ); } } @@ -3095,12 +3100,12 @@ struct window_rects map_window_rects_virt_to_raw( struct window_rects rects, UIN return rects; } -static UINT get_monitor_dpi( HMONITOR handle, UINT type, UINT *x, UINT *y ) +static struct ratio get_monitor_dpi( HMONITOR handle, UINT type, struct ratio *x, struct ratio *y ) { + struct ratio dpi = {system_dpi, 1}; struct monitor *monitor; - UINT dpi = system_dpi; - if (!lock_display_devices( FALSE )) return 0; + if (!lock_display_devices( FALSE )) return no_dpi; if ((monitor = get_monitor_from_handle( handle ))) dpi = monitor_get_dpi( monitor, type, x, y ); unlock_display_devices(); @@ -3110,9 +3115,9 @@ static UINT get_monitor_dpi( HMONITOR handle, UINT type, UINT *x, UINT *y ) /********************************************************************** * get_win_monitor_dpi */ -UINT get_win_monitor_dpi( HWND hwnd, UINT *raw_dpi ) +struct ratio get_win_monitor_dpi( HWND hwnd, struct ratio *raw_dpi ) { - UINT dpi = NTUSER_DPI_CONTEXT_GET_DPI( get_window_dpi_awareness_context( hwnd ) ); + struct ratio dpi = {NTUSER_DPI_CONTEXT_GET_DPI( get_window_dpi_awareness_context( hwnd ) ), 1}; HWND parent = get_parent( hwnd ); RECT rect = {0}; WND *win; @@ -3120,13 +3125,13 @@ UINT get_win_monitor_dpi( HWND hwnd, UINT *raw_dpi ) if (!(win = get_win_ptr( hwnd ))) { RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE ); - return 0; + return no_dpi; } if (win == WND_DESKTOP) return monitor_dpi_from_rect( rect, get_thread_dpi(), raw_dpi ); if (win == WND_OTHER_PROCESS) { - if (!get_window_rect( hwnd, &rect, dpi )) return 0; + if (!get_window_rect( hwnd, &rect, dpi )) return no_dpi; } /* avoid recursive calls from get_window_rects for the process windows */ else if ((parent = win->parent) && parent != get_desktop_window()) @@ -3190,14 +3195,18 @@ DWORD get_process_layout(void) /********************************************************************** * get_thread_dpi */ -UINT get_thread_dpi(void) +struct ratio get_thread_dpi(void) { + struct ratio dpi = {1, 1}; + switch (NTUSER_DPI_CONTEXT_GET_AWARENESS( get_thread_dpi_awareness_context() )) { - case DPI_AWARENESS_UNAWARE: return USER_DEFAULT_SCREEN_DPI; - case DPI_AWARENESS_SYSTEM_AWARE: return system_dpi; - default: return 0; /* no scaling */ + case DPI_AWARENESS_UNAWARE: dpi.num = USER_DEFAULT_SCREEN_DPI; break; + case DPI_AWARENESS_SYSTEM_AWARE: dpi.num = system_dpi; break; + default: return no_dpi; /* no scaling */ } + + return dpi; } /* see GetDpiForSystem */ @@ -3229,17 +3238,22 @@ UINT set_thread_dpi_awareness_context( UINT context ) return prev; } +static BOOL needs_dpi_mapping( struct ratio dpi_from, struct ratio dpi_to ) +{ + return dpi_from.num && dpi_to.num && dpi_from.num != dpi_to.num; +} + /********************************************************************** * map_dpi_rect */ -RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ) +RECT map_dpi_rect( RECT rect, struct ratio dpi_from, struct ratio dpi_to ) { - if (dpi_from && dpi_to && dpi_from != dpi_to) + if (needs_dpi_mapping( dpi_from, dpi_to )) { - rect.left = muldiv( rect.left, dpi_to, dpi_from ); - rect.top = muldiv( rect.top, dpi_to, dpi_from ); - rect.right = muldiv( rect.right, dpi_to, dpi_from ); - rect.bottom = muldiv( rect.bottom, dpi_to, dpi_from ); + rect.left = muldiv( rect.left, dpi_to.num, dpi_from.num ); + rect.top = muldiv( rect.top, dpi_to.num, dpi_from.num ); + rect.right = muldiv( rect.right, dpi_to.num, dpi_from.num ); + rect.bottom = muldiv( rect.bottom, dpi_to.num, dpi_from.num ); } return rect; } @@ -3247,7 +3261,7 @@ RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ) /********************************************************************** * map_dpi_region */ -HRGN map_dpi_region( HRGN hrgn, UINT dpi_from, UINT dpi_to ) +HRGN map_dpi_region( HRGN hrgn, struct ratio dpi_from, struct ratio dpi_to ) { RGNDATA *data; UINT i, size; @@ -3256,7 +3270,7 @@ HRGN map_dpi_region( HRGN hrgn, UINT dpi_from, UINT dpi_to ) if (!(data = malloc( size ))) return 0; NtGdiGetRegionData( hrgn, size, data ); - if (dpi_from && dpi_to && dpi_from != dpi_to) + if (needs_dpi_mapping( dpi_from, dpi_to )) { RECT *rects = (RECT *)data->Buffer; for (i = 0; i < data->rdh.nCount; i++) rects[i] = map_dpi_rect( rects[i], dpi_from, dpi_to ); @@ -3270,7 +3284,7 @@ HRGN map_dpi_region( HRGN hrgn, UINT dpi_from, UINT dpi_to ) /********************************************************************** * map_dpi_window_rects */ -struct window_rects map_dpi_window_rects( struct window_rects rects, UINT dpi_from, UINT dpi_to ) +struct window_rects map_dpi_window_rects( struct window_rects rects, struct ratio dpi_from, struct ratio dpi_to ) { rects.window = map_dpi_rect( rects.window, dpi_from, dpi_to ); rects.client = map_dpi_rect( rects.client, dpi_from, dpi_to ); @@ -3278,15 +3292,21 @@ struct window_rects map_dpi_window_rects( struct window_rects rects, UINT dpi_fr return rects; } +/* map value from given DPI to user default screen DPI */ +UINT map_user_dpi( UINT value, struct ratio dpi_from ) +{ + return muldiv( value, dpi_from.num, USER_DEFAULT_SCREEN_DPI ); +} + /********************************************************************** * map_dpi_point */ -POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to ) +POINT map_dpi_point( POINT pt, struct ratio dpi_from, struct ratio dpi_to ) { - if (dpi_from && dpi_to && dpi_from != dpi_to) + if (needs_dpi_mapping( dpi_from, dpi_to )) { - pt.x = muldiv( pt.x, dpi_to, dpi_from ); - pt.y = muldiv( pt.y, dpi_to, dpi_from ); + pt.x = muldiv( pt.x, dpi_to.num, dpi_from.num ); + pt.y = muldiv( pt.y, dpi_to.num, dpi_from.num ); } return pt; } @@ -3296,7 +3316,7 @@ POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to ) */ static POINT point_win_to_phys_dpi( HWND hwnd, POINT pt ) { - UINT raw_dpi, dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); + struct ratio raw_dpi, dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); return map_dpi_point( pt, get_dpi_for_window( hwnd ), dpi ); } @@ -3305,7 +3325,7 @@ static POINT point_win_to_phys_dpi( HWND hwnd, POINT pt ) */ POINT point_phys_to_win_dpi( HWND hwnd, POINT pt ) { - UINT raw_dpi, dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); + struct ratio raw_dpi, dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); return map_dpi_point( pt, dpi, get_dpi_for_window( hwnd ) ); } @@ -3314,8 +3334,8 @@ POINT point_phys_to_win_dpi( HWND hwnd, POINT pt ) */ POINT point_thread_to_win_dpi( HWND hwnd, POINT pt ) { - UINT dpi = get_thread_dpi(), raw_dpi; - if (!dpi) dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); + struct ratio dpi = get_thread_dpi(), raw_dpi; + if (!dpi.num) dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); return map_dpi_point( pt, dpi, get_dpi_for_window( hwnd )); } @@ -3324,8 +3344,8 @@ POINT point_thread_to_win_dpi( HWND hwnd, POINT pt ) */ RECT rect_thread_to_win_dpi( HWND hwnd, RECT rect ) { - UINT dpi = get_thread_dpi(), raw_dpi; - if (!dpi) dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); + struct ratio dpi = get_thread_dpi(), raw_dpi; + if (!dpi.num) dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); return map_dpi_rect( rect, dpi, get_dpi_for_window( hwnd ) ); } @@ -3342,7 +3362,7 @@ static int map_to_dpi( int val, UINT dpi ) return muldiv( val, dpi, USER_DEFAULT_SCREEN_DPI ); } -RECT get_virtual_screen_rect( UINT dpi, MONITOR_DPI_TYPE type ) +RECT get_virtual_screen_rect( struct ratio dpi, MONITOR_DPI_TYPE type ) { RECT rect = {0}; @@ -3367,10 +3387,11 @@ static UINT get_display_index( const UNICODE_STRING *name ) RECT get_display_rect( const WCHAR *display ) { + struct ratio dpi = get_thread_dpi(); struct monitor *monitor; UNICODE_STRING name; RECT rect = {0}; - UINT index, dpi = get_thread_dpi(); + UINT index; RtlInitUnicodeString( &name, display ); if (!(index = get_display_index( &name ))) return rect; @@ -3387,7 +3408,7 @@ RECT get_display_rect( const WCHAR *display ) return rect; } -RECT get_primary_monitor_rect( UINT dpi ) +RECT get_primary_monitor_rect( struct ratio dpi ) { struct monitor *monitor; RECT rect = {0}; @@ -4667,7 +4688,7 @@ BOOL WINAPI NtUserEnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc return ret; } -static BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info, UINT dpi ) +static BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info, struct ratio dpi ) { struct monitor *monitor; @@ -4691,23 +4712,24 @@ static BOOL get_monitor_info( HMONITOR handle, MONITORINFO *info, UINT dpi ) return FALSE; } -static HMONITOR monitor_from_rect( const RECT *rect, UINT flags, UINT dpi ) +static HMONITOR monitor_from_rect( const RECT *rect, UINT flags, struct ratio dpi_from ) { + struct ratio dpi = {system_dpi, 1}; struct monitor *monitor; HMONITOR ret = 0; RECT r; - r = map_dpi_rect( *rect, dpi, system_dpi ); + r = map_dpi_rect( *rect, dpi_from, dpi ); if (!lock_display_devices( FALSE )) return 0; - if ((monitor = get_monitor_from_rect( r, flags, system_dpi, MDT_DEFAULT ))) ret = monitor->handle; + if ((monitor = get_monitor_from_rect( r, flags, dpi, MDT_DEFAULT ))) ret = monitor->handle; unlock_display_devices(); TRACE( "%s flags %x returning %p\n", wine_dbgstr_rect(rect), flags, ret ); return ret; } -MONITORINFO monitor_info_from_rect( RECT rect, UINT dpi ) +MONITORINFO monitor_info_from_rect( RECT rect, struct ratio dpi ) { MONITORINFO info = {.cbSize = sizeof(info)}; struct monitor *monitor; @@ -4720,12 +4742,12 @@ MONITORINFO monitor_info_from_rect( RECT rect, UINT dpi ) return info; } -UINT monitor_dpi_from_rect( RECT rect, UINT dpi, UINT *raw_dpi ) +struct ratio monitor_dpi_from_rect( RECT rect, struct ratio dpi, struct ratio *raw_dpi ) { + struct ratio ret = {system_dpi, 1}, x, y; struct monitor *monitor; - UINT ret = system_dpi, x, y; - if (!lock_display_devices( FALSE )) return 0; + if (!lock_display_devices( FALSE )) return no_dpi; if ((monitor = get_monitor_from_rect( rect, MONITOR_DEFAULTTONEAREST, dpi, MDT_DEFAULT ))) { *raw_dpi = monitor_get_dpi( monitor, MDT_RAW_DPI, &x, &y ); @@ -4737,7 +4759,7 @@ UINT monitor_dpi_from_rect( RECT rect, UINT dpi, UINT *raw_dpi ) } /* see MonitorFromWindow */ -HMONITOR monitor_from_window( HWND hwnd, UINT flags, UINT dpi ) +HMONITOR monitor_from_window( HWND hwnd, UINT flags, struct ratio dpi ) { RECT rect; WINDOWPLACEMENT wp; @@ -4798,7 +4820,14 @@ BOOL WINAPI NtUserGetDpiForMonitor( HMONITOR monitor, UINT type, UINT *x, UINT * { case DPI_AWARENESS_UNAWARE: *x = *y = USER_DEFAULT_SCREEN_DPI; break; case DPI_AWARENESS_SYSTEM_AWARE: *x = *y = system_dpi; break; - default: get_monitor_dpi( monitor, type, x, y ); break; + default: + { + struct ratio dpi_x, dpi_y; + get_monitor_dpi( monitor, type, &dpi_x, &dpi_y ); + *x = dpi_x.num; + *y = dpi_y.num; + break; + } } return TRUE; } @@ -4824,7 +4853,7 @@ BOOL WINAPI NtUserPerMonitorDPIPhysicalToLogicalPoint( HWND hwnd, POINT *pt ) RECT rect; BOOL ret = FALSE; - if (get_window_rect( hwnd, &rect, 0 ) && + if (get_window_rect( hwnd, &rect, no_dpi ) && pt->x >= rect.left && pt->y >= rect.top && pt->x <= rect.right && pt->y <= rect.bottom) { *pt = point_phys_to_win_dpi( hwnd, *pt ); @@ -6347,7 +6376,7 @@ BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT w case SPI_GETWORKAREA: { MONITORINFO info = {.cbSize = sizeof(info)}; - UINT dpi = get_thread_dpi(); + struct ratio dpi = get_thread_dpi(); if (!ptr) return FALSE; @@ -7557,7 +7586,7 @@ ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code ) return get_sys_color( arg ); case NtUserCallOneParam_GetPrimaryMonitorRect: - *(RECT *)arg = get_primary_monitor_rect( 0 ); + *(RECT *)arg = get_primary_monitor_rect( no_dpi ); return 1; case NtUserCallOneParam_GetSysColorBrush: @@ -7626,7 +7655,7 @@ ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code } case NtUserCallTwoParam_GetVirtualScreenRect: - *(RECT *)arg1 = get_virtual_screen_rect( 0, arg2 ); + *(RECT *)arg1 = get_virtual_screen_rect( no_dpi, arg2 ); return 1; /* temporary exports */ diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c index 416d4eeb833..1bb4735587f 100644 --- a/dlls/win32u/vulkan.c +++ b/dlls/win32u/vulkan.c @@ -1574,7 +1574,7 @@ static void win32u_vkDestroySurfaceKHR( VkInstance client_instance, VkSurfaceKHR free( surface ); } -static BOOL get_surface_rect( HWND hwnd, RECT *rect, UINT dpi ) +static BOOL get_surface_rect( HWND hwnd, RECT *rect, struct ratio dpi ) { if (!get_present_rect( hwnd, rect, dpi ) && !get_client_rect( hwnd, rect, dpi )) return FALSE; OffsetRect( rect, -rect->left, -rect->top ); @@ -1825,9 +1825,9 @@ static VkResult win32u_vkCreateSwapchainKHR( VkDevice client_device, const VkSwa VkSwapchainCreateInfoKHR create_info_host = *create_info; VkSurfaceCapabilitiesKHR capabilities; VkSwapchainKHR host_swapchain; + struct ratio raw_dpi; RECT client_rect; VkResult res; - UINT raw_dpi; if (!NtUserIsWindow( surface->hwnd )) { diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index c217aa9ead6..3a7769b5588 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -45,9 +45,9 @@ extern HICON create_small_icon( HICON handle ); /* dce.c */ extern struct window_surface dummy_surface; -extern void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, UINT monitor_dpi, +extern void create_window_surface( HWND hwnd, BOOL create_layered, const RECT *surface_rect, struct ratio monitor_dpi, struct window_surface **window_surface ); -extern struct window_surface *get_driver_window_surface( struct window_surface *surface, UINT monitor_dpi ); +extern struct window_surface *get_driver_window_surface( struct window_surface *surface, struct ratio monitor_dpi ); extern void erase_now( HWND hwnd, UINT rdw_flags ); extern void flush_window_surfaces( BOOL idle ); extern void move_window_bits( HWND hwnd, const struct window_rects *rects, const RECT *valid_rects ); @@ -163,34 +163,35 @@ extern LONG get_char_dimensions( HDC hdc, TEXTMETRICW *metric, int *height ); extern HBITMAP get_display_bitmap(void); extern INT get_display_depth( UNICODE_STRING *name ); extern RECT get_display_rect( const WCHAR *display ); -extern UINT get_win_monitor_dpi( HWND hwnd, UINT *raw_dpi ); -extern RECT get_primary_monitor_rect( UINT dpi ); +extern struct ratio get_win_monitor_dpi( HWND hwnd, struct ratio *raw_dpi ); +extern RECT get_primary_monitor_rect( struct ratio dpi ); extern DWORD get_process_layout(void); extern COLORREF get_sys_color( int index ); extern HBRUSH get_sys_color_brush( unsigned int index ); extern HPEN get_sys_color_pen( unsigned int index ); extern UINT get_system_dpi(void); extern int get_system_metrics( int index ); -extern UINT get_thread_dpi(void); +extern struct ratio get_thread_dpi(void); extern UINT set_thread_dpi_awareness_context( UINT context ); extern UINT get_thread_dpi_awareness_context(void); -extern RECT get_virtual_screen_rect( UINT dpi, MONITOR_DPI_TYPE type ); +extern RECT get_virtual_screen_rect( struct ratio dpi, MONITOR_DPI_TYPE type ); extern const char *gpu_device_name( UINT16 vendor, UINT16 device, const char *name ); extern BOOL is_exiting_thread( DWORD tid ); -extern POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to ); -extern RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ); -extern HRGN map_dpi_region( HRGN region, UINT dpi_from, UINT dpi_to ); -extern struct window_rects map_dpi_window_rects( struct window_rects rects, UINT dpi_from, UINT dpi_to ); -extern RECT map_rect_raw_to_virt( RECT rect, UINT dpi_to ); -extern RECT map_rect_virt_to_raw( RECT rect, UINT dpi_from ); -extern struct window_rects map_window_rects_virt_to_raw( struct window_rects rects, UINT dpi_from ); +extern UINT map_user_dpi( UINT value, struct ratio dpi_from ); +extern POINT map_dpi_point( POINT pt, struct ratio dpi_from, struct ratio dpi_to ); +extern RECT map_dpi_rect( RECT rect, struct ratio dpi_from, struct ratio dpi_to ); +extern HRGN map_dpi_region( HRGN region, struct ratio dpi_from, struct ratio dpi_to ); +extern struct window_rects map_dpi_window_rects( struct window_rects rects, struct ratio dpi_from, struct ratio dpi_to ); +extern RECT map_rect_raw_to_virt( RECT rect, struct ratio dpi_to ); +extern RECT map_rect_virt_to_raw( RECT rect, struct ratio dpi_from ); +extern struct window_rects map_window_rects_virt_to_raw( struct window_rects rects, struct ratio dpi_from ); extern POINT point_phys_to_win_dpi( HWND hwnd, POINT pt ); extern POINT point_thread_to_win_dpi( HWND hwnd, POINT pt ); extern RECT rect_thread_to_win_dpi( HWND hwnd, RECT rect ); -extern HMONITOR monitor_from_window( HWND hwnd, UINT flags, UINT dpi ); -extern MONITORINFO monitor_info_from_rect( RECT rect, UINT dpi ); +extern HMONITOR monitor_from_window( HWND hwnd, UINT flags, struct ratio dpi ); +extern MONITORINFO monitor_info_from_rect( RECT rect, struct ratio dpi ); extern MONITORINFO monitor_info_from_window( HWND hwnd, UINT flags ); -extern UINT monitor_dpi_from_rect( RECT rect, UINT dpi, UINT *raw_dpi ); +extern struct ratio monitor_dpi_from_rect( RECT rect, struct ratio dpi, struct ratio *raw_dpi ); extern BOOL update_display_cache( BOOL force ); extern void reset_monitor_update_serial(void); extern void user_lock(void); @@ -270,10 +271,10 @@ struct tagWND; extern BOOL client_to_screen( HWND hwnd, POINT *pt ); extern void destroy_thread_windows(void); extern LRESULT destroy_window( HWND hwnd ); -extern BOOL get_client_rect( HWND hwnd, RECT *rect, UINT dpi ); -extern BOOL get_present_rect( HWND hwnd, RECT *rect, UINT dpi ); +extern BOOL get_client_rect( HWND hwnd, RECT *rect, struct ratio dpi ); +extern BOOL get_present_rect( HWND hwnd, RECT *rect, struct ratio dpi ); extern HWND get_desktop_window(void); -extern UINT get_dpi_for_window( HWND hwnd ); +extern struct ratio get_dpi_for_window( HWND hwnd ); extern HWND get_full_window_handle( HWND hwnd ); extern HWND get_parent( HWND hwnd ); extern HWND get_hwnd_message_parent(void); @@ -295,15 +296,15 @@ extern int get_window_pixel_format( HWND hwnd ); extern DWORD get_window_long( HWND hwnd, INT offset ); extern UINT get_window_fnid( HWND hwnd ); extern ULONG_PTR get_window_long_ptr( HWND hwnd, INT offset, BOOL ansi ); -extern BOOL get_window_rect( HWND hwnd, RECT *rect, UINT dpi ); +extern BOOL get_window_rect( HWND hwnd, RECT *rect, struct ratio dpi ); enum coords_relative; -extern BOOL get_window_rect_rel( HWND hwnd, enum coords_relative rel, RECT *rect, UINT dpi ); -extern BOOL get_client_rect_rel( HWND hwnd, enum coords_relative rel, RECT *rect, UINT dpi ); +extern BOOL get_window_rect_rel( HWND hwnd, enum coords_relative rel, RECT *rect, struct ratio dpi ); +extern BOOL get_client_rect_rel( HWND hwnd, enum coords_relative rel, RECT *rect, struct ratio dpi ); extern BOOL get_window_rects( HWND hwnd, enum coords_relative relative, - struct window_rects *rects, UINT dpi ); + struct window_rects *rects, struct ratio dpi ); extern HWND *list_window_children( HWND hwnd ); extern int map_window_points( HWND hwnd_from, HWND hwnd_to, POINT *points, UINT count, - UINT dpi ); + struct ratio dpi ); extern void map_window_region( HWND from, HWND to, HRGN hrgn ); extern BOOL screen_to_client( HWND hwnd, POINT *pt ); extern LONG_PTR set_window_long( HWND hwnd, INT offset, UINT size, LONG_PTR newval, diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 1ecdca6c7d8..947d16322b3 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -37,6 +37,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1) #define USER_HANDLE_FROM_INDEX(index, generation) UlongToHandle( (index << 1) + FIRST_USER_HANDLE + (generation << 16) ) +static const struct ratio no_dpi; + static void *client_objects[MAX_USER_HANDLES]; #define SWP_AGG_NOGEOMETRYCHANGE \ @@ -323,7 +325,7 @@ void detach_client_surfaces( HWND hwnd ) static RECT get_client_surface_rects( HWND toplevel, HWND hwnd, RECT *monitor_rect ) { - UINT dpi = get_dpi_for_window( hwnd ), raw_dpi; + struct ratio dpi = get_dpi_for_window( hwnd ), raw_dpi; struct window_rects rects, monitor_rects; RECT rect = {0}; @@ -684,7 +686,7 @@ HWND WINAPI NtUserSetParent( HWND hwnd, HWND parent ) if (parent && parent != NtUserGetDesktopWindow()) win->has_icons = FALSE; get_window_rect_rel( hwnd, COORDS_PARENT, &window_rect, get_dpi_for_window(hwnd) ); - get_window_rect_rel( hwnd, COORDS_SCREEN, &old_screen_rect, 0 ); + get_window_rect_rel( hwnd, COORDS_SCREEN, &old_screen_rect, no_dpi ); SERVER_START_REQ( set_parent ) { @@ -701,7 +703,7 @@ HWND WINAPI NtUserSetParent( HWND hwnd, HWND parent ) release_win_ptr( win ); if (!ret) return 0; - get_window_rect_rel( hwnd, COORDS_SCREEN, &new_screen_rect, 0 ); + get_window_rect_rel( hwnd, COORDS_SCREEN, &new_screen_rect, no_dpi ); context = set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd )); user_driver->pSetParent( full_handle, parent, old_parent ); @@ -1129,11 +1131,13 @@ UINT get_window_dpi_awareness_context( HWND hwnd ) } /* see GetDpiForWindow */ -UINT get_dpi_for_window( HWND hwnd ) +struct ratio get_dpi_for_window( HWND hwnd ) { - UINT raw_dpi, context = get_window_dpi_awareness_context( hwnd ); + struct ratio dpi = {1, 1}, raw_dpi; + UINT context = get_window_dpi_awareness_context( hwnd ); if (NTUSER_DPI_CONTEXT_IS_MONITOR_AWARE( context )) return get_win_monitor_dpi( hwnd, &raw_dpi ); - return NTUSER_DPI_CONTEXT_GET_DPI( context ); + dpi.num = NTUSER_DPI_CONTEXT_GET_DPI( context ); + return dpi; } /* see GetLastActivePopup */ @@ -1772,7 +1776,7 @@ static void mirror_rect( const RECT *window_rect, RECT *rect ) * * Get the window and client rectangles. */ -BOOL get_window_rects( HWND hwnd, enum coords_relative relative, struct window_rects *rects, UINT dpi ) +BOOL get_window_rects( HWND hwnd, enum coords_relative relative, struct window_rects *rects, struct ratio dpi ) { WND *win = get_win_ptr( hwnd ); BOOL ret = TRUE; @@ -1803,7 +1807,7 @@ BOOL get_window_rects( HWND hwnd, enum coords_relative relative, struct window_r } if (win != WND_OTHER_PROCESS) { - UINT window_dpi = get_dpi_for_window( hwnd ); + struct ratio window_dpi = get_dpi_for_window( hwnd ); *rects = win->rects; switch (relative) @@ -1891,7 +1895,7 @@ other_process: { req->handle = wine_server_user_handle( hwnd ); req->relative = relative; - req->dpi = dpi; + req->dpi = dpi.num; if ((ret = !wine_server_call_err( req ))) { rects->window = wine_server_get_rect( reply->window ); @@ -1903,7 +1907,7 @@ other_process: return ret; } -BOOL get_window_rect_rel( HWND hwnd, enum coords_relative rel, RECT *rect, UINT dpi ) +BOOL get_window_rect_rel( HWND hwnd, enum coords_relative rel, RECT *rect, struct ratio dpi ) { struct window_rects rects; BOOL ret = get_window_rects( hwnd, rel, &rects, dpi ); @@ -1912,12 +1916,12 @@ BOOL get_window_rect_rel( HWND hwnd, enum coords_relative rel, RECT *rect, UINT } /* see GetWindowRect */ -BOOL get_window_rect( HWND hwnd, RECT *rect, UINT dpi ) +BOOL get_window_rect( HWND hwnd, RECT *rect, struct ratio dpi ) { return get_window_rect_rel( hwnd, COORDS_SCREEN, rect, dpi ); } -BOOL get_client_rect_rel( HWND hwnd, enum coords_relative rel, RECT *rect, UINT dpi ) +BOOL get_client_rect_rel( HWND hwnd, enum coords_relative rel, RECT *rect, struct ratio dpi ) { struct window_rects rects; BOOL ret = get_window_rects( hwnd, rel, &rects, dpi ); @@ -1926,7 +1930,7 @@ BOOL get_client_rect_rel( HWND hwnd, enum coords_relative rel, RECT *rect, UINT } /* see GetClientRect */ -BOOL get_client_rect( HWND hwnd, RECT *rect, UINT dpi ) +BOOL get_client_rect( HWND hwnd, RECT *rect, struct ratio dpi ) { return get_client_rect_rel( hwnd, COORDS_CLIENT, rect, dpi ); } @@ -2030,13 +2034,14 @@ done: static RECT get_visible_rect( HWND hwnd, BOOL shaped, UINT style, UINT ex_style, const struct window_rects *rects ) { - UINT dpi = get_dpi_for_window( hwnd ), style_mask, ex_style_mask; + struct ratio dpi = get_dpi_for_window( hwnd ); + UINT style_mask, ex_style_mask; RECT visible_rect, rect = {0}; if (get_present_rect( hwnd, &rect, get_thread_dpi() )) return rect; if (IsRectEmpty( &rects->window ) || EqualRect( &rects->window, &rects->client ) || shaped || !decorated_mode) return rects->window; if (!user_driver->pGetWindowStyleMasks( hwnd, style, ex_style, &style_mask, &ex_style_mask )) return rects->window; - if (!NtUserAdjustWindowRect( &rect, style & style_mask, FALSE, ex_style & ex_style_mask, dpi )) return rects->window; + if (!adjust_window_rect( &rect, style & style_mask, FALSE, ex_style & ex_style_mask, dpi.num )) return rects->window; visible_rect = rects->window; visible_rect.left -= rect.left; @@ -2054,7 +2059,7 @@ static RECT get_visible_rect( HWND hwnd, BOOL shaped, UINT style, UINT ex_style, static BOOL get_surface_rect( const RECT *visible_rect, RECT *surface_rect ) { - RECT virtual_rect = get_virtual_screen_rect( 0, MDT_RAW_DPI ); + RECT virtual_rect = get_virtual_screen_rect( no_dpi, MDT_RAW_DPI ); *surface_rect = *visible_rect; @@ -2109,7 +2114,8 @@ static struct window_surface *get_window_surface( HWND hwnd, UINT swp_flags, BOO HWND parent = NtUserGetAncestor( hwnd, GA_PARENT ); struct window_surface *new_surface; struct window_rects monitor_rects; - UINT raw_dpi, style, ex_style; + struct ratio raw_dpi; + UINT style, ex_style; RECT dummy; HRGN shape; @@ -2208,7 +2214,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru struct window_rects monitor_rects; WND *win; HWND owner_hint, surface_win = 0, toplevel; - UINT raw_dpi, monitor_dpi, dpi = get_thread_dpi(); + struct ratio raw_dpi, monitor_dpi, dpi = get_thread_dpi(); BOOL ret, is_layered, is_child, need_icons = FALSE; struct window_rects old_rects; RECT extra_rects[3]; @@ -2242,7 +2248,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru req->handle = wine_server_user_handle( hwnd ); req->previous = wine_server_user_handle( insert_after ); req->swp_flags = swp_flags; - req->monitor_dpi = monitor_dpi; + req->monitor_dpi = monitor_dpi.num; req->window = wine_server_rectangle( new_rects->window ); req->client = wine_server_rectangle( new_rects->client ); if (!EqualRect( &new_rects->window, &new_rects->visible ) || new_surface || valid_rects) @@ -2404,7 +2410,7 @@ static BOOL expose_window_surface( HWND hwnd, UINT flags, const RECT *rect ) if (rect) { - UINT raw_dpi; + struct ratio raw_dpi; get_win_monitor_dpi( hwnd, &raw_dpi ); exposed_rect = map_dpi_rect( *rect, raw_dpi, get_dpi_for_window( hwnd ) ); } @@ -2503,7 +2509,7 @@ int WINAPI NtUserSetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw ) { UINT swp_flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE; - UINT raw_dpi; + struct ratio raw_dpi; HRGN monitor_hrgn; if (!redraw) swp_flags |= SWP_NOREDRAW; @@ -2695,7 +2701,7 @@ done: * Point is in screen coordinates. * Returned list must be freed by caller. */ -static HWND *list_children_from_point( HWND hwnd, POINT pt, UINT dpi ) +static HWND *list_children_from_point( HWND hwnd, POINT pt, struct ratio dpi ) { int i, size = 128; HWND *list; @@ -2711,7 +2717,7 @@ static HWND *list_children_from_point( HWND hwnd, POINT pt, UINT dpi ) req->parent = wine_server_user_handle( hwnd ); req->x = pt.x; req->y = pt.y; - req->dpi = dpi; + req->dpi = dpi.num; wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) ); if (!wine_server_call( req )) count = reply->count; } @@ -2741,10 +2747,10 @@ HWND window_from_point( HWND hwnd, POINT pt, INT *hittest, BOOL send_nchittest ) int i, res; HWND ret, *list; POINT win_pt; - UINT dpi, raw_dpi; + struct ratio dpi = get_thread_dpi(), raw_dpi; if (!hwnd) hwnd = get_desktop_window(); - if (!(dpi = get_thread_dpi())) dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); + if (!dpi.num) dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); *hittest = HTNOWHERE; @@ -2904,7 +2910,7 @@ static BOOL empty_point( POINT pt ) BOOL WINAPI NtUserGetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *placement ) { WND *win = get_win_ptr( hwnd ); - UINT win_dpi; + struct ratio win_dpi; if (!win) return FALSE; @@ -3270,7 +3276,7 @@ INT WINAPI NtUserInternalGetWindowText( HWND hwnd, WCHAR *text, INT count ) * Calculate the offset between the origin of the two windows. Used * to implement MapWindowPoints. */ -static BOOL get_windows_offset( HWND hwnd_from, HWND hwnd_to, UINT dpi, BOOL *mirrored, POINT *ret_offset ) +static BOOL get_windows_offset( HWND hwnd_from, HWND hwnd_to, struct ratio dpi, BOOL *mirrored, POINT *ret_offset ) { WND *win; POINT offset; @@ -3291,7 +3297,7 @@ static BOOL get_windows_offset( HWND hwnd_from, HWND hwnd_to, UINT dpi, BOOL *mi if (win == WND_OTHER_PROCESS) goto other_process; if (win != WND_DESKTOP) { - UINT raw_dpi, dpi_from = dpi ? dpi : get_win_monitor_dpi( hwnd_from, &raw_dpi ); + struct ratio raw_dpi, dpi_from = dpi.num ? dpi : get_win_monitor_dpi( hwnd_from, &raw_dpi ); if (win->dwExStyle & WS_EX_LAYOUTRTL) { mirror_from = TRUE; @@ -3328,7 +3334,7 @@ static BOOL get_windows_offset( HWND hwnd_from, HWND hwnd_to, UINT dpi, BOOL *mi if (win == WND_OTHER_PROCESS) goto other_process; if (win != WND_DESKTOP) { - UINT raw_dpi, dpi_to = dpi ? dpi : get_win_monitor_dpi( hwnd_to, &raw_dpi ); + struct ratio raw_dpi, dpi_to = dpi.num ? dpi : get_win_monitor_dpi( hwnd_to, &raw_dpi ); POINT pt = { 0, 0 }; if (win->dwExStyle & WS_EX_LAYOUTRTL) { @@ -3367,7 +3373,7 @@ other_process: /* one of the parents may belong to another process, do it the h { req->from = wine_server_user_handle( hwnd_from ); req->to = wine_server_user_handle( hwnd_to ); - req->dpi = dpi; + req->dpi = dpi.num; if ((ret = !wine_server_call_err( req ))) { ret_offset->x = reply->x; @@ -3454,7 +3460,7 @@ void map_window_region( HWND from, HWND to, HRGN hrgn ) } /* see MapWindowPoints */ -int map_window_points( HWND hwnd_from, HWND hwnd_to, POINT *points, UINT count, UINT dpi ) +int map_window_points( HWND hwnd_from, HWND hwnd_to, POINT *points, UINT count, struct ratio dpi ) { BOOL mirrored; POINT offset; @@ -3515,9 +3521,9 @@ static void dump_winpos_flags( UINT flags ) static void map_dpi_winpos( WINDOWPOS *winpos ) { RECT rect = {winpos->x, winpos->y, winpos->x + winpos->cx, winpos->y + winpos->cy}; - UINT raw_dpi, dpi_from = get_thread_dpi(), dpi_to = get_dpi_for_window( winpos->hwnd ); + struct ratio raw_dpi, dpi_from = get_thread_dpi(), dpi_to = get_dpi_for_window( winpos->hwnd ); - if (!dpi_from) dpi_from = get_win_monitor_dpi( winpos->hwnd, &raw_dpi ); + if (!dpi_from.num) dpi_from = get_win_monitor_dpi( winpos->hwnd, &raw_dpi ); rect = map_dpi_rect( rect, dpi_from, dpi_to ); winpos->x = rect.left; winpos->y = rect.top; @@ -5657,15 +5663,15 @@ static void fix_cs_coordinates( CREATESTRUCTW *cs, INT *sw ) /*********************************************************************** * map_dpi_create_struct */ -static void map_dpi_create_struct( CREATESTRUCTW *cs, UINT dpi_to ) +static void map_dpi_create_struct( CREATESTRUCTW *cs, struct ratio dpi_to ) { RECT rect = {cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy}; - UINT dpi_from = get_thread_dpi(); + struct ratio dpi_from = get_thread_dpi(); - if (!dpi_from || !dpi_to) + if (!dpi_from.num || !dpi_to.num) { - UINT raw_dpi, mon_dpi = monitor_dpi_from_rect( rect, get_thread_dpi(), &raw_dpi ); - if (!dpi_from) dpi_from = mon_dpi; + struct ratio raw_dpi, mon_dpi = monitor_dpi_from_rect( rect, get_thread_dpi(), &raw_dpi ); + if (!dpi_from.num) dpi_from = mon_dpi; else dpi_to = mon_dpi; } @@ -5686,7 +5692,7 @@ HWND WINAPI NtUserCreateWindowEx( DWORD ex_style, UNICODE_STRING *class_name, DWORD flags, HINSTANCE instance, const WCHAR *class, BOOL ansi ) { WCHAR base_nameW[MAX_ATOM_LEN + 1]; - UINT win_dpi, context; + struct ratio win_dpi; struct window_surface *surface; struct window_rects new_rects; CBT_CREATEWNDW cbtc; @@ -5694,6 +5700,7 @@ HWND WINAPI NtUserCreateWindowEx( DWORD ex_style, UNICODE_STRING *class_name, CREATESTRUCTW cs; INT sw = SW_SHOW; RECT surface_rect; + UINT context; WND *win; TRACE( "ex_style %#x, class_name %s, version %s, window_name %s, style %#x, x %u, y %u, cx %u, cy %u, " @@ -6042,13 +6049,13 @@ static BOOL set_raw_window_pos( HWND hwnd, RECT rect, UINT flags, BOOL internal return NtUserSetWindowPos( hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags ); } -BOOL get_present_rect( HWND hwnd, RECT *rect, UINT dpi ) +BOOL get_present_rect( HWND hwnd, RECT *rect, struct ratio dpi ) { - UINT dpi_from = get_dpi_for_window( hwnd ); + struct ratio dpi_from = get_dpi_for_window( hwnd ); WND *win; if (!(win = get_win_ptr( hwnd )) || win == WND_OTHER_PROCESS || win == WND_DESKTOP) return FALSE; - if (dpi != -1) *rect = map_dpi_rect( win->present_rect, dpi_from, dpi ); + if (dpi.num != (unsigned short)-1) *rect = map_dpi_rect( win->present_rect, dpi_from, dpi ); else *rect = map_rect_virt_to_raw( win->present_rect, dpi_from ); release_win_ptr( win ); @@ -6070,7 +6077,7 @@ ULONG_PTR WINAPI NtUserCallHwnd( HWND hwnd, DWORD code ) return set_foreground_window( hwnd, FALSE, TRUE ); case NtUserCallHwnd_GetDpiForWindow: - return get_dpi_for_window( hwnd ); + return get_dpi_for_window( hwnd ).num; case NtUserCallHwnd_GetLastActivePopup: return (ULONG_PTR)get_last_active_popup( hwnd ); @@ -6177,17 +6184,20 @@ ULONG_PTR WINAPI NtUserCallHwndParam( HWND hwnd, DWORD_PTR param, DWORD code ) case NtUserCallHwndParam_GetWindowRect: { struct get_window_rects_params *params = (void *)param; - return get_window_rect( hwnd, params->rect, params->dpi ); + struct ratio dpi = {params->dpi, 1}; + return get_window_rect( hwnd, params->rect, dpi ); } case NtUserCallHwndParam_GetClientRect: { struct get_window_rects_params *params = (void *)param; - return get_client_rect( hwnd, params->rect, params->dpi ); + struct ratio dpi = {params->dpi, 1}; + return get_client_rect( hwnd, params->rect, dpi ); } case NtUserCallHwndParam_GetPresentRect: { struct get_window_rects_params *params = (void *)param; - return get_present_rect( hwnd, params->rect, params->dpi ); + struct ratio dpi = {params->dpi, 1}; + return get_present_rect( hwnd, params->rect, dpi ); } case NtUserCallHwndParam_GetWindowRelative: @@ -6203,10 +6213,11 @@ ULONG_PTR WINAPI NtUserCallHwndParam( HWND hwnd, DWORD_PTR param, DWORD code ) return is_child( hwnd, UlongToHandle(param) ); case NtUserCallHwndParam_MapWindowPoints: - { - struct map_window_points_params *params = (void *)param; - return map_window_points( hwnd, params->hwnd_to, params->points, params->count, params->dpi ); - } + { + struct map_window_points_params *params = (void *)param; + struct ratio dpi = {params->dpi, 1}; + return map_window_points( hwnd, params->hwnd_to, params->points, params->count, dpi ); + } case NtUserCallHwndParam_MirrorRgn: return mirror_window_region( hwnd, UlongToHandle(param) ); @@ -6238,8 +6249,8 @@ ULONG_PTR WINAPI NtUserCallHwndParam( HWND hwnd, DWORD_PTR param, DWORD code ) case NtUserCallHwndParam_GetWinMonitorDpi: { - UINT raw_dpi, dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); - return param == MDT_EFFECTIVE_DPI ? dpi : raw_dpi; + struct ratio raw_dpi, dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); + return param == MDT_EFFECTIVE_DPI ? dpi.num : raw_dpi.num; } case NtUserCallHwndParam_SetRawWindowPos: diff --git a/server/protocol.def b/server/protocol.def index 6c2ffc85aab..02f19e711cc 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -267,6 +267,12 @@ struct property_data lparam_t data; /* data stored in property */ }; +struct ratio +{ + unsigned short num; + unsigned short den; +}; + /* structure to specify window rectangles */ struct rectangle { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11301
From: Rémi Bernon <rbernon@codeweavers.com> Based on patches from Paul Gofman. --- dlls/win32u/sysparams.c | 2 +- dlls/win32u/window.c | 8 +++---- server/protocol.def | 12 +++++----- server/region.c | 2 +- server/trace.c | 8 ++++++- server/user.h | 10 ++++----- server/window.c | 49 +++++++++++++++++++++++------------------ tools/make_requests | 1 + 8 files changed, 52 insertions(+), 40 deletions(-) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index e1b04b0317e..fc067c0ab07 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2442,7 +2442,7 @@ static void set_winstation_monitors( BOOL increment ) if (is_monitor_primary( monitor )) info->flags |= MONITOR_FLAG_PRIMARY; if (!is_monitor_active( monitor )) info->flags |= MONITOR_FLAG_INACTIVE; if (monitor->is_clone) info->flags |= MONITOR_FLAG_CLONE; - info->dpi = monitor_get_dpi( monitor, MDT_EFFECTIVE_DPI, &x, &y ).num; + info->dpi = monitor_get_dpi( monitor, MDT_EFFECTIVE_DPI, &x, &y ); info->virt = wine_server_rectangle( monitor_get_rect( monitor, no_dpi, MDT_EFFECTIVE_DPI ) ); info->raw = wine_server_rectangle( monitor_get_rect( monitor, no_dpi, MDT_RAW_DPI ) ); info++; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 947d16322b3..2d3ca556eb2 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1895,7 +1895,7 @@ other_process: { req->handle = wine_server_user_handle( hwnd ); req->relative = relative; - req->dpi = dpi.num; + req->dpi = dpi; if ((ret = !wine_server_call_err( req ))) { rects->window = wine_server_get_rect( reply->window ); @@ -2248,7 +2248,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru req->handle = wine_server_user_handle( hwnd ); req->previous = wine_server_user_handle( insert_after ); req->swp_flags = swp_flags; - req->monitor_dpi = monitor_dpi.num; + req->monitor_dpi = monitor_dpi; req->window = wine_server_rectangle( new_rects->window ); req->client = wine_server_rectangle( new_rects->client ); if (!EqualRect( &new_rects->window, &new_rects->visible ) || new_surface || valid_rects) @@ -2717,7 +2717,7 @@ static HWND *list_children_from_point( HWND hwnd, POINT pt, struct ratio dpi ) req->parent = wine_server_user_handle( hwnd ); req->x = pt.x; req->y = pt.y; - req->dpi = dpi.num; + req->dpi = dpi; wine_server_set_reply( req, list, (size-1) * sizeof(user_handle_t) ); if (!wine_server_call( req )) count = reply->count; } @@ -3373,7 +3373,7 @@ other_process: /* one of the parents may belong to another process, do it the h { req->from = wine_server_user_handle( hwnd_from ); req->to = wine_server_user_handle( hwnd_to ); - req->dpi = dpi.num; + req->dpi = dpi; if ((ret = !wine_server_call_err( req ))) { ret_offset->x = reply->x; diff --git a/server/protocol.def b/server/protocol.def index 02f19e711cc..2ba02303761 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -912,8 +912,8 @@ struct monitor_info { struct rectangle raw; /* host / physical position of the monitor rect */ struct rectangle virt; /* client / virtual position of the monitor rect */ - unsigned int flags; /* MONITOR_FLAG_* flags for the monitor */ - unsigned int dpi; /* physical DPI for the monitor */ + unsigned int flags; /* MONITOR_FLAG_* flags for the monitor */ + struct ratio dpi; /* physical DPI for the monitor */ }; #define MONITOR_FLAG_PRIMARY 0x01 #define MONITOR_FLAG_CLONE 0x02 @@ -2771,7 +2771,7 @@ enum message_type user_handle_t parent; /* parent window */ int x; /* point in parent coordinates */ int y; - int dpi; /* dpi for the point coordinates */ + struct ratio dpi; /* dpi for the point coordinates */ @REPLY int count; /* total count of children */ VARARG(children,user_handles); /* children handles */ @@ -2796,7 +2796,7 @@ enum message_type @REQ(set_window_pos) unsigned short swp_flags; /* SWP_* flags */ unsigned short paint_flags; /* paint flags (see below) */ - unsigned int monitor_dpi; /* DPI of the window's monitor */ + struct ratio monitor_dpi; /* DPI of the window's monitor */ user_handle_t handle; /* handle to the window */ user_handle_t previous; /* previous window in Z order */ struct rectangle window; /* window rectangle (in parent coords) */ @@ -2815,7 +2815,7 @@ enum message_type @REQ(get_window_rectangles) user_handle_t handle; /* handle to the window */ int relative; /* coords relative to (see below) */ - int dpi; /* DPI to map to, or zero for per-monitor DPI */ + struct ratio dpi; /* DPI to map to, or zero for per-monitor DPI */ @REPLY struct rectangle window; /* window rectangle */ struct rectangle client; /* client rectangle */ @@ -2849,7 +2849,7 @@ enum coords_relative @REQ(get_windows_offset) user_handle_t from; /* handle to the first window */ user_handle_t to; /* handle to the second window */ - int dpi; /* DPI to map to, or zero for per-monitor DPI */ + struct ratio dpi; /* DPI to map to, or zero for per-monitor DPI */ @REPLY int x; /* x coordinate offset */ int y; /* y coordinate offset */ diff --git a/server/region.c b/server/region.c index 9b0b1c66402..d77038c161f 100644 --- a/server/region.c +++ b/server/region.c @@ -741,7 +741,7 @@ void mirror_region( const struct rectangle *client_rect, struct region *region ) /* scale a region for a given dpi factor */ -void scale_region( struct region *region, unsigned int dpi_from, unsigned int dpi_to ) +void scale_region( struct region *region, struct ratio dpi_from, struct ratio dpi_to ) { struct rectangle *rect, *end; diff --git a/server/trace.c b/server/trace.c index b02e08fce03..371466293c3 100644 --- a/server/trace.c +++ b/server/trace.c @@ -173,6 +173,11 @@ static void dump_rectangle( const char *prefix, const struct rectangle *rect ) rect->left, rect->top, rect->right, rect->bottom ); } +static void dump_ratio( const char *prefix, const struct ratio *q ) +{ + fprintf( stderr, "%s{%d:%d}", prefix, q->num, q->den ); +} + static void dump_ioctl_code( const char *prefix, const ioctl_code_t *code ) { switch(*code) @@ -1646,7 +1651,8 @@ static void dump_varargs_monitor_infos( const char *prefix, data_size_t size ) { dump_rectangle( "{raw:", &monitor->virt ); dump_rectangle( ",virt:", &monitor->virt ); - fprintf( stderr, ",flags:%#x,dpi:%u", monitor->flags, monitor->dpi ); + fprintf( stderr, ",flags:%#x", monitor->flags ); + dump_ratio( ",dpi:", &monitor->dpi ); fputc( '}', stderr ); if (--len) fputc( ',', stderr ); } diff --git a/server/user.h b/server/user.h index 1997029b0e9..77d8c3591ad 100644 --- a/server/user.h +++ b/server/user.h @@ -152,7 +152,7 @@ extern int is_region_equal( const struct region *region1, const struct region *r extern void get_region_extents( const struct region *region, struct rectangle *rect ); extern void offset_region( struct region *region, int x, int y ); extern void mirror_region( const struct rectangle *client_rect, struct region *region ); -extern void scale_region( struct region *region, unsigned int dpi_from, unsigned int dpi_to ); +extern void scale_region( struct region *region, struct ratio dpi_from, struct ratio dpi_to ); extern struct region *copy_region( struct region *dst, const struct region *src ); extern struct region *intersect_region( struct region *dst, const struct region *src1, const struct region *src2 ); @@ -232,13 +232,13 @@ static inline int point_in_rect( const struct rectangle *rect, int x, int y ) return (x >= rect->left && x < rect->right && y >= rect->top && y < rect->bottom); } -static inline int scale_dpi( int val, unsigned int dpi_from, unsigned int dpi_to ) +static inline int scale_dpi( int val, struct ratio dpi_from, struct ratio dpi_to ) { - if (val >= 0) return (val * dpi_to + (dpi_from / 2)) / dpi_from; - return (val * dpi_to - (dpi_from / 2)) / dpi_from; + if (val >= 0) return (val * dpi_to.num + (dpi_from.num / 2)) / dpi_from.num; + return (val * dpi_to.num - (dpi_from.num / 2)) / dpi_from.num; } -static inline void scale_dpi_rect( struct rectangle *rect, unsigned int dpi_from, unsigned int dpi_to ) +static inline void scale_dpi_rect( struct rectangle *rect, struct ratio dpi_from, struct ratio dpi_to ) { rect->left = scale_dpi( rect->left, dpi_from, dpi_to ); rect->top = scale_dpi( rect->top, dpi_from, dpi_to ); diff --git a/server/window.c b/server/window.c index e6d5a6d377b..37ea9a9dc35 100644 --- a/server/window.c +++ b/server/window.c @@ -36,6 +36,8 @@ #include "user.h" #include "unicode.h" +static const struct ratio no_dpi; + /* a window property */ struct property { @@ -81,7 +83,7 @@ struct window unsigned int color_key; /* color key for a layered window */ unsigned int alpha; /* alpha value for a layered window */ unsigned int layered_flags; /* flags for a layered window */ - unsigned int monitor_dpi; /* DPI of the window monitor */ + struct ratio monitor_dpi; /* DPI of the window monitor */ WCHAR *text; /* window caption text */ data_size_t text_len; /* length of window caption */ unsigned int paint_flags; /* various painting flags */ @@ -319,16 +321,18 @@ static void map_point_raw_to_virt( struct desktop *desktop, int *x, int *y ) } /* get the per-monitor DPI for a window */ -static unsigned int get_monitor_dpi( struct window *win ) +static struct ratio get_monitor_dpi( struct window *win ) { while (win->parent && !is_desktop_window( win->parent )) win = win->parent; return win->monitor_dpi; } -static unsigned int get_window_dpi( struct window *win ) +static struct ratio get_window_dpi( struct window *win ) { + struct ratio dpi = {1, 1}; if (NTUSER_DPI_CONTEXT_IS_MONITOR_AWARE( win->shared->dpi_context )) return get_monitor_dpi( win ); - return NTUSER_DPI_CONTEXT_GET_DPI( win->shared->dpi_context ); + dpi.num = NTUSER_DPI_CONTEXT_GET_DPI( win->shared->dpi_context ); + return dpi; } /* link a window at the right place in the siblings list */ @@ -658,7 +662,8 @@ static struct window *create_window( struct window *parent, struct window *owner win->is_layered = 0; win->is_orphan = 0; win->set_foreground = 0; - win->monitor_dpi = USER_DEFAULT_SCREEN_DPI; + win->monitor_dpi.num = USER_DEFAULT_SCREEN_DPI; + win->monitor_dpi.den = 1; win->text = NULL; win->text_len = 0; win->paint_flags = 0; @@ -815,30 +820,30 @@ static inline void inc_window_paint_count( struct window *win, int incr ) } /* map a point between different DPI scaling levels */ -static void map_dpi_point( struct window *win, int *x, int *y, unsigned int from, unsigned int to ) +static void map_dpi_point( struct window *win, int *x, int *y, struct ratio from, struct ratio to ) { - if (!from) from = get_monitor_dpi( win ); - if (!to) to = get_monitor_dpi( win ); - if (from == to) return; + if (!from.num) from = get_monitor_dpi( win ); + if (!to.num) to = get_monitor_dpi( win ); + if (from.num == to.num) return; *x = scale_dpi( *x, from, to ); *y = scale_dpi( *y, from, to ); } /* map a window rectangle between different DPI scaling levels */ -static void map_dpi_rect( struct window *win, struct rectangle *rect, unsigned int from, unsigned int to ) +static void map_dpi_rect( struct window *win, struct rectangle *rect, struct ratio from, struct ratio to ) { - if (!from) from = get_monitor_dpi( win ); - if (!to) to = get_monitor_dpi( win ); - if (from == to) return; + if (!from.num) from = get_monitor_dpi( win ); + if (!to.num) to = get_monitor_dpi( win ); + if (from.num == to.num) return; scale_dpi_rect( rect, from, to ); } /* map a region between different DPI scaling levels */ -static void map_dpi_region( struct window *win, struct region *region, unsigned int from, unsigned int to ) +static void map_dpi_region( struct window *win, struct region *region, struct ratio from, struct ratio to ) { - if (!from) from = get_monitor_dpi( win ); - if (!to) to = get_monitor_dpi( win ); - if (from == to) return; + if (!from.num) from = get_monitor_dpi( win ); + if (!to.num) to = get_monitor_dpi( win ); + if (from.num == to.num) return; scale_region( region, from, to ); } @@ -853,7 +858,7 @@ static inline void client_to_screen( struct window *win, int *x, int *y ) } /* convert coordinates from screen to client coords and dpi */ -static void screen_to_client( struct window *win, int *x, int *y, unsigned int dpi ) +static void screen_to_client( struct window *win, int *x, int *y, struct ratio dpi ) { int offset_x = 0, offset_y = 0; @@ -909,7 +914,7 @@ static int is_parent_composited( struct window *win ) } /* check if point is inside the window, and map to window dpi */ -static int is_point_in_window( struct window *win, int *x, int *y, unsigned int dpi ) +static int is_point_in_window( struct window *win, int *x, int *y, struct ratio dpi ) { if (!(win->style & WS_VISIBLE)) return 0; /* not visible */ if ((win->style & (WS_POPUP|WS_CHILD|WS_DISABLED)) == (WS_CHILD|WS_DISABLED)) @@ -1038,7 +1043,7 @@ user_handle_t shallow_window_from_point( struct desktop *desktop, int x, int y ) { int x_child = x, y_child = y; - if (!is_point_in_window( ptr, &x_child, &y_child, 0 )) continue; /* skip it */ + if (!is_point_in_window( ptr, &x_child, &y_child, no_dpi )) continue; /* skip it */ return ptr->handle; } return desktop->top_window->handle; @@ -1053,14 +1058,14 @@ struct thread *window_thread_from_point( user_handle_t scope, int x, int y ) map_point_raw_to_virt( win->desktop, &x, &y ); - screen_to_client( win, &x, &y, 0 ); + screen_to_client( win, &x, &y, no_dpi ); win = child_window_from_point( win, x, y ); if (!win->thread) return NULL; return (struct thread *)grab_object( win->thread ); } /* return list of all windows containing point (in absolute coords) */ -static int all_windows_from_point( struct window *top, int x, int y, unsigned int dpi, +static int all_windows_from_point( struct window *top, int x, int y, struct ratio dpi, struct user_handle_array *array ) { if (!is_desktop_window( top ) && !is_desktop_window( top->parent )) diff --git a/tools/make_requests b/tools/make_requests index 7e317647a51..4b8139596a3 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -69,6 +69,7 @@ my %formats = "union udp_endpoint" => [ 32, 4 ], "struct user_apc" => [ 40, 8 ], "struct class_info" => [ 56, 8 ], + "struct ratio" => [ 4, 4 ], ); my $file_header = -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11301
From: Rémi Bernon <rbernon@codeweavers.com> Otherwise virtual display mode conversion results in inaccurate coordinates and introduces artefacting. Based on patches from Paul Gofman. --- dlls/win32u/sysparams.c | 68 ++++++++++++++++++++++++++---------- dlls/win32u/win32u_private.h | 6 ++++ dlls/win32u/window.c | 4 +-- server/user.h | 5 +-- 4 files changed, 60 insertions(+), 23 deletions(-) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index fc067c0ab07..e3a83d484dd 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -303,6 +303,34 @@ static pthread_mutex_t display_dc_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t user_mutex; static unsigned int user_lock_thread, user_lock_rec; +static UINT gcd( UINT a, UINT b ) +{ + UINT r; + + for (;;) + { + if (!a) return b; + if (!b) return a; + r = a % b; + a = b; + b = r; + } +} + +static struct ratio make_ratio( UINT num, UINT den ) +{ + UINT d = gcd( num, den ); + struct ratio r = { num / d, den / d }; + assert( num / d < 65536 ); + assert( den / d < 65536 ); + return r; +} + +static struct ratio min_ratio( struct ratio x, struct ratio y ) +{ + return x.num * y.den <= y.num * x.den ? x : y; +} + void user_lock(void) { pthread_mutex_lock( &user_mutex ); @@ -2307,22 +2335,22 @@ static void monitor_virt_to_raw_ratio( struct monitor *monitor, UINT *num, UINT /* display_lock must be held */ static struct ratio monitor_get_dpi( struct monitor *monitor, MONITOR_DPI_TYPE type, struct ratio *dpi_x, struct ratio *dpi_y ) { + struct ratio scale_x = {1, 1}, scale_y = {1, 1}; struct source *source = monitor->source; - float scale_x = 1.0, scale_y = 1.0; UINT dpi; if (!source || !(dpi = source->dpi)) dpi = system_dpi; if (source && type != MDT_EFFECTIVE_DPI) { - scale_x = source->physical.dmPelsWidth / (float)source->current.dmPelsWidth; - scale_y = source->physical.dmPelsHeight / (float)source->current.dmPelsHeight; + scale_x.num = source->physical.dmPelsWidth; + scale_x.den = source->current.dmPelsWidth; + scale_y.num = source->physical.dmPelsHeight; + scale_y.den = source->current.dmPelsHeight; } - dpi_x->num = round( dpi * scale_x ); - dpi_x->den = 1; - dpi_y->num = round( dpi * scale_y ); - dpi_y->den = 1; - return dpi_x->num < dpi_y->num ? *dpi_x : *dpi_y; + *dpi_x = make_ratio( dpi * scale_x.num, scale_x.den ); + *dpi_y = make_ratio( dpi * scale_y.num, scale_y.den ); + return min_ratio( *dpi_x, *dpi_y ); } /* display_lock must be held */ @@ -2366,11 +2394,11 @@ static RECT map_monitor_rect( struct monitor *monitor, RECT rect, struct ratio d for (int i = 0; i < ARRAY_SIZE(points); i++) { - points[i] *= (double)dpi.num / dpi_from.num; + points[i] *= (double)dpi.num * dpi_from.den / (dpi_from.num * dpi.den); points[i] -= from[i & 1]; points[i] *= (double)num / den; points[i] += to[i & 1]; - points[i] *= (double)dpi_to.num / dpi.num; + points[i] *= (double)dpi_to.num * dpi.den / (dpi.num * dpi_to.den); points[i] = roundf( points[i] ); points[i] = min( INT_MAX, max( INT_MIN, (INT64)points[i] )); } @@ -3240,7 +3268,7 @@ UINT set_thread_dpi_awareness_context( UINT context ) static BOOL needs_dpi_mapping( struct ratio dpi_from, struct ratio dpi_to ) { - return dpi_from.num && dpi_to.num && dpi_from.num != dpi_to.num; + return dpi_from.num && dpi_to.num && memcmp( &dpi_from, &dpi_to, sizeof(struct ratio) ); } /********************************************************************** @@ -3250,10 +3278,11 @@ RECT map_dpi_rect( RECT rect, struct ratio dpi_from, struct ratio dpi_to ) { if (needs_dpi_mapping( dpi_from, dpi_to )) { - rect.left = muldiv( rect.left, dpi_to.num, dpi_from.num ); - rect.top = muldiv( rect.top, dpi_to.num, dpi_from.num ); - rect.right = muldiv( rect.right, dpi_to.num, dpi_from.num ); - rect.bottom = muldiv( rect.bottom, dpi_to.num, dpi_from.num ); + unsigned int num = dpi_to.num * dpi_from.den, den = dpi_from.num * dpi_to.den; + rect.left = muldiv( rect.left, num, den ); + rect.top = muldiv( rect.top, num, den ); + rect.right = muldiv( rect.right, num, den ); + rect.bottom = muldiv( rect.bottom, num, den ); } return rect; } @@ -3305,8 +3334,9 @@ POINT map_dpi_point( POINT pt, struct ratio dpi_from, struct ratio dpi_to ) { if (needs_dpi_mapping( dpi_from, dpi_to )) { - pt.x = muldiv( pt.x, dpi_to.num, dpi_from.num ); - pt.y = muldiv( pt.y, dpi_to.num, dpi_from.num ); + unsigned int num = dpi_to.num * dpi_from.den, den = dpi_from.num * dpi_to.den; + pt.x = muldiv( pt.x, num, den ); + pt.y = muldiv( pt.y, num, den ); } return pt; } @@ -4824,8 +4854,8 @@ BOOL WINAPI NtUserGetDpiForMonitor( HMONITOR monitor, UINT type, UINT *x, UINT * { struct ratio dpi_x, dpi_y; get_monitor_dpi( monitor, type, &dpi_x, &dpi_y ); - *x = dpi_x.num; - *y = dpi_y.num; + *x = round_dpi( dpi_x ); + *y = round_dpi( dpi_y ); break; } } diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 3a7769b5588..6d0483311bb 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -449,4 +449,10 @@ static inline BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 return !IsRectEmpty( dst ); } +static inline UINT round_dpi( struct ratio dpi ) +{ + if (!dpi.den) return 0; + return (dpi.num + dpi.den / 2) / dpi.den; +} + #endif /* __WINE_WIN32U_PRIVATE */ diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 2d3ca556eb2..e5fe70409f0 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2041,7 +2041,7 @@ static RECT get_visible_rect( HWND hwnd, BOOL shaped, UINT style, UINT ex_style, if (get_present_rect( hwnd, &rect, get_thread_dpi() )) return rect; if (IsRectEmpty( &rects->window ) || EqualRect( &rects->window, &rects->client ) || shaped || !decorated_mode) return rects->window; if (!user_driver->pGetWindowStyleMasks( hwnd, style, ex_style, &style_mask, &ex_style_mask )) return rects->window; - if (!adjust_window_rect( &rect, style & style_mask, FALSE, ex_style & ex_style_mask, dpi.num )) return rects->window; + if (!adjust_window_rect( &rect, style & style_mask, FALSE, ex_style & ex_style_mask, round_dpi( dpi ) )) return rects->window; visible_rect = rects->window; visible_rect.left -= rect.left; @@ -6250,7 +6250,7 @@ ULONG_PTR WINAPI NtUserCallHwndParam( HWND hwnd, DWORD_PTR param, DWORD code ) case NtUserCallHwndParam_GetWinMonitorDpi: { struct ratio raw_dpi, dpi = get_win_monitor_dpi( hwnd, &raw_dpi ); - return param == MDT_EFFECTIVE_DPI ? dpi.num : raw_dpi.num; + return param == MDT_EFFECTIVE_DPI ? round_dpi( dpi ) : round_dpi( raw_dpi ); } case NtUserCallHwndParam_SetRawWindowPos: diff --git a/server/user.h b/server/user.h index 77d8c3591ad..d146d0cf8cf 100644 --- a/server/user.h +++ b/server/user.h @@ -234,8 +234,9 @@ static inline int point_in_rect( const struct rectangle *rect, int x, int y ) static inline int scale_dpi( int val, struct ratio dpi_from, struct ratio dpi_to ) { - if (val >= 0) return (val * dpi_to.num + (dpi_from.num / 2)) / dpi_from.num; - return (val * dpi_to.num - (dpi_from.num / 2)) / dpi_from.num; + unsigned int num = dpi_to.num * dpi_from.den, den = dpi_from.num * dpi_to.den; + if (val >= 0) return (val * num + (den / 2)) / den; + return (val * num - (den / 2)) / den; } static inline void scale_dpi_rect( struct rectangle *rect, struct ratio dpi_from, struct ratio dpi_to ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11301
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/win32u/sysparams.c | 40 ++++-------------------------------- dlls/win32u/win32u_private.h | 5 +++++ dlls/win32u/window.c | 28 +++++++++++++++++++++---- server/protocol.def | 6 ++++-- server/window.c | 37 +++++++++++++++++++++++---------- 5 files changed, 63 insertions(+), 53 deletions(-) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index e3a83d484dd..af73a6e65f8 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2465,14 +2465,18 @@ static void set_winstation_monitors( BOOL increment ) if (!(count = list_count( &monitors ))) return; if (!(info = infos = calloc( count, sizeof(*infos) ))) return; + TRACE( "increment %u\n", increment ); LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry ) { if (is_monitor_primary( monitor )) info->flags |= MONITOR_FLAG_PRIMARY; if (!is_monitor_active( monitor )) info->flags |= MONITOR_FLAG_INACTIVE; if (monitor->is_clone) info->flags |= MONITOR_FLAG_CLONE; info->dpi = monitor_get_dpi( monitor, MDT_EFFECTIVE_DPI, &x, &y ); + info->raw_dpi = monitor_get_dpi( monitor, MDT_RAW_DPI, &x, &y ); info->virt = wine_server_rectangle( monitor_get_rect( monitor, no_dpi, MDT_EFFECTIVE_DPI ) ); info->raw = wine_server_rectangle( monitor_get_rect( monitor, no_dpi, MDT_RAW_DPI ) ); + TRACE( " flags %#x virt %s dpi %s raw %s raw_dpi %s\n", info->flags, wine_dbgstr_rect( (RECT *)&info->virt ), + debugstr_ratio( info->dpi ), wine_dbgstr_rect( (RECT *)&info->raw ), debugstr_ratio( info->raw_dpi ) ); info++; } @@ -3140,42 +3144,6 @@ static struct ratio get_monitor_dpi( HMONITOR handle, UINT type, struct ratio *x return dpi; } -/********************************************************************** - * get_win_monitor_dpi - */ -struct ratio get_win_monitor_dpi( HWND hwnd, struct ratio *raw_dpi ) -{ - struct ratio dpi = {NTUSER_DPI_CONTEXT_GET_DPI( get_window_dpi_awareness_context( hwnd ) ), 1}; - HWND parent = get_parent( hwnd ); - RECT rect = {0}; - WND *win; - - if (!(win = get_win_ptr( hwnd ))) - { - RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE ); - return no_dpi; - } - - if (win == WND_DESKTOP) return monitor_dpi_from_rect( rect, get_thread_dpi(), raw_dpi ); - if (win == WND_OTHER_PROCESS) - { - if (!get_window_rect( hwnd, &rect, dpi )) return no_dpi; - } - /* avoid recursive calls from get_window_rects for the process windows */ - else if ((parent = win->parent) && parent != get_desktop_window()) - { - release_win_ptr( win ); - return get_win_monitor_dpi( parent, raw_dpi ); - } - else - { - rect = is_iconic( hwnd ) ? win->normal_rect : win->rects.window; - release_win_ptr( win ); - } - - return monitor_dpi_from_rect( rect, dpi, raw_dpi ); -} - /* keep in sync with user32 */ static BOOL is_valid_dpi_awareness_context( UINT context, UINT dpi ) { diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 6d0483311bb..b7a40367506 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -455,4 +455,9 @@ static inline UINT round_dpi( struct ratio dpi ) return (dpi.num + dpi.den / 2) / dpi.den; } +static inline const char *debugstr_ratio( struct ratio q ) +{ + return wine_dbg_sprintf( "%d:%d", q.num, q.den ); +} + #endif /* __WINE_WIN32U_PRIVATE */ diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index e5fe70409f0..a0efc9e10d5 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1112,6 +1112,27 @@ BOOL is_window_enabled( HWND hwnd ) return !(ret & WS_DISABLED); } +struct ratio get_win_monitor_dpi( HWND hwnd, struct ratio *raw_dpi ) +{ + struct object_lock lock = OBJECT_LOCK_INIT; + const window_shm_t *window_shm; + struct ratio dpi = no_dpi; + NTSTATUS status; + + while ((status = get_shared_window( hwnd, &lock, &window_shm )) == STATUS_PENDING) + { + *raw_dpi = window_shm->raw_dpi; + dpi = window_shm->dpi; + } + if (status) + { + RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE ); + return no_dpi; + } + + return dpi; +} + /* see GetWindowDpiAwarenessContext */ UINT get_window_dpi_awareness_context( HWND hwnd ) { @@ -2214,7 +2235,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru struct window_rects monitor_rects; WND *win; HWND owner_hint, surface_win = 0, toplevel; - struct ratio raw_dpi, monitor_dpi, dpi = get_thread_dpi(); + struct ratio raw_dpi, dpi = get_thread_dpi(); BOOL ret, is_layered, is_child, need_icons = FALSE; struct window_rects old_rects; RECT extra_rects[3]; @@ -2226,8 +2247,8 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru is_layered = new_surface && new_surface->alpha_mask; is_child = toplevel && toplevel != hwnd; - if (is_child) monitor_dpi = get_win_monitor_dpi( toplevel, &raw_dpi ); - else monitor_dpi = monitor_dpi_from_rect( new_rects->window, dpi, &raw_dpi ); + if (is_child) get_win_monitor_dpi( toplevel, &raw_dpi ); + else monitor_dpi_from_rect( new_rects->window, dpi, &raw_dpi ); get_window_rects( hwnd, COORDS_PARENT, &old_rects, dpi ); if (IsRectEmpty( &valid_rects[0] ) || is_layered) valid_rects = NULL; @@ -2248,7 +2269,6 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru req->handle = wine_server_user_handle( hwnd ); req->previous = wine_server_user_handle( insert_after ); req->swp_flags = swp_flags; - req->monitor_dpi = monitor_dpi; req->window = wine_server_rectangle( new_rects->window ); req->client = wine_server_rectangle( new_rects->client ); if (!EqualRect( &new_rects->window, &new_rects->visible ) || new_surface || valid_rects) diff --git a/server/protocol.def b/server/protocol.def index 2ba02303761..191f1deeffc 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -913,7 +913,8 @@ struct monitor_info struct rectangle raw; /* host / physical position of the monitor rect */ struct rectangle virt; /* client / virtual position of the monitor rect */ unsigned int flags; /* MONITOR_FLAG_* flags for the monitor */ - struct ratio dpi; /* physical DPI for the monitor */ + struct ratio dpi; /* effective DPI for the monitor */ + struct ratio raw_dpi; /* raw DPI for the monitor */ }; #define MONITOR_FLAG_PRIMARY 0x01 #define MONITOR_FLAG_CLONE 0x02 @@ -1084,6 +1085,8 @@ typedef volatile struct unsigned int fnid; /* builtin class FNID, or 0 */ unsigned int ansi; /* window wndproc is ansi */ int __pad; + struct ratio dpi; /* effective DPI of the window monitor */ + struct ratio raw_dpi; /* raw DPI of the window monitor */ data_size_t private_size; /* length of private extra bytes range */ data_size_t extra_size; /* size of the extra info */ struct window_info info; /* window info (GWLP_*) */ @@ -2796,7 +2799,6 @@ enum message_type @REQ(set_window_pos) unsigned short swp_flags; /* SWP_* flags */ unsigned short paint_flags; /* paint flags (see below) */ - struct ratio monitor_dpi; /* DPI of the window's monitor */ user_handle_t handle; /* handle to the window */ user_handle_t previous; /* previous window in Z order */ struct rectangle window; /* window rectangle (in parent coords) */ diff --git a/server/window.c b/server/window.c index 37ea9a9dc35..77f71f0f65a 100644 --- a/server/window.c +++ b/server/window.c @@ -83,7 +83,6 @@ struct window unsigned int color_key; /* color key for a layered window */ unsigned int alpha; /* alpha value for a layered window */ unsigned int layered_flags; /* flags for a layered window */ - struct ratio monitor_dpi; /* DPI of the window monitor */ WCHAR *text; /* window caption text */ data_size_t text_len; /* length of window caption */ unsigned int paint_flags; /* various painting flags */ @@ -324,7 +323,7 @@ static void map_point_raw_to_virt( struct desktop *desktop, int *x, int *y ) static struct ratio get_monitor_dpi( struct window *win ) { while (win->parent && !is_desktop_window( win->parent )) win = win->parent; - return win->monitor_dpi; + return win->shared->dpi; } static struct ratio get_window_dpi( struct window *win ) @@ -394,6 +393,20 @@ static int link_window( struct window *win, struct window *previous ) return old_prev != win->entry.prev; } +static void set_window_monitor_dpi( struct window *win ) +{ + struct monitor_info *info; + + if (!(info = get_monitor_from_rect( win->desktop->winstation, &win->window_rect, 0 ))) return; + + SHARED_WRITE_BEGIN( win->shared, window_shm_t ) + { + shared->dpi = info->dpi; + shared->raw_dpi = info->raw_dpi; + } + SHARED_WRITE_END; +} + /* change the parent of a window (or unlink the window if the new parent is NULL) */ static int set_parent_window( struct window *win, struct window *parent ) { @@ -415,14 +428,12 @@ static int set_parent_window( struct window *win, struct window *parent ) win->parent = (struct window *)grab_object( parent ); link_window( win, WINPTR_TOP ); - if (!is_desktop_window( parent )) + if (is_desktop_window( parent )) set_window_monitor_dpi( win ); + else SHARED_WRITE_BEGIN( win->shared, window_shm_t ) { - SHARED_WRITE_BEGIN( win->shared, window_shm_t ) - { - shared->dpi_context = parent->shared->dpi_context; - } - SHARED_WRITE_END; + shared->dpi_context = parent->shared->dpi_context; } + SHARED_WRITE_END; /* if parent belongs to a different thread and the window isn't */ /* top-level, attach the two threads */ @@ -662,8 +673,6 @@ static struct window *create_window( struct window *parent, struct window *owner win->is_layered = 0; win->is_orphan = 0; win->set_foreground = 0; - win->monitor_dpi.num = USER_DEFAULT_SCREEN_DPI; - win->monitor_dpi.den = 1; win->text = NULL; win->text_len = 0; win->paint_flags = 0; @@ -682,6 +691,10 @@ static struct window *create_window( struct window *parent, struct window *owner shared->dpi_context = NTUSER_DPI_PER_MONITOR_AWARE; shared->fnid = fnid; shared->private_size = private_size; + shared->dpi.num = USER_DEFAULT_SCREEN_DPI; + shared->dpi.den = 1; + shared->raw_dpi.num = USER_DEFAULT_SCREEN_DPI; + shared->raw_dpi.den = 1; shared->extra_size = extra_size; memset( (void *)&shared->info, 0, sizeof(shared->info) ); memset( (void *)shared->extra, 0, extra_size ); @@ -1951,6 +1964,9 @@ static void set_window_pos( struct window *win, struct window *previous, if (swp_flags & SWP_SHOWWINDOW) win->style |= WS_VISIBLE; else if (swp_flags & SWP_HIDEWINDOW) win->style &= ~WS_VISIBLE; + /* update window monitor dpi for toplevel windows */ + if (!win->parent || is_desktop_window( win->parent )) set_window_monitor_dpi( win ); + /* keep children at the same position relative to top right corner when the parent is mirrored */ if (win->ex_style & WS_EX_LAYOUTRTL) { @@ -2737,7 +2753,6 @@ DECL_HANDLER(set_window_pos) win->paint_flags = (win->paint_flags & ~PAINT_CLIENT_FLAGS) | (req->paint_flags & PAINT_CLIENT_FLAGS); if (win->paint_flags & PAINT_HAS_PIXEL_FORMAT) update_pixel_format_flags( win ); - win->monitor_dpi = req->monitor_dpi; old_style = win->style; old_window = win->window_rect; old_client = win->client_rect; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11301
Actually even better use the window rect, like apply_window_pos was doing. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11301#note_144794
participants (2)
-
Rémi Bernon -
Rémi Bernon (@rbernon)