 
             
            From: Conor McCarthy cmccarthy@codeweavers.com
Requires display mode emulation for failures to manifest. --- dlls/user32/tests/monitor.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index 206d9505705..7ad3970a646 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -3611,6 +3611,8 @@ static void test_monitor_dpi(void) DPI_AWARENESS_CONTEXT old_ctx; float scale_x, scale_y; BOOL ret, is_virtual; + INT x, y; + POINT pt;
if (!pGetDpiForMonitorInternal || !pSetThreadDpiAwarenessContext) { @@ -3722,6 +3724,19 @@ static void test_monitor_dpi(void) ok( fabs( dpi_y - system_dpi * scale_y ) < system_dpi * 0.05, "got MDT_RAW_DPI y %u\n", dpi_y ); }
+ /* Test for cursor position rounding errors. To be meaninful, this requires display + * mode emulation. To enable it, run 'wine control desk.cpl' and set the checkbox. */ + for (x = infos[i].rect.left; x < infos[i].rect.left + 64; ++x) + { + y = x - infos[i].rect.left + infos[i].rect.top; + SetCursorPos(x, y); + GetCursorPos(&pt); + todo_wine_if(pt.x != x) + ok(pt.x == x, "got x %ld, expected %d.\n", pt.x, x); + todo_wine_if(pt.y != y) + ok(pt.y == y, "got y %ld, expected %d.\n", pt.y, y); + } + pSetThreadDpiAwarenessContext( old_ctx ); } }
 
            From: Rémi Bernon rbernon@codeweavers.com
Avoiding rounding errors caused by dpi_from and dpi * 2 denominators. It's possible to tweak the operations to move the division up to the end but it increases the risk of overflows. Let's just use floats for this.
Based on a patch from Conor McCarthy. --- dlls/user32/tests/monitor.c | 2 -- dlls/win32u/sysparams.c | 34 ++++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index 7ad3970a646..f76971c1b53 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -3731,9 +3731,7 @@ static void test_monitor_dpi(void) y = x - infos[i].rect.left + infos[i].rect.top; SetCursorPos(x, y); GetCursorPos(&pt); - todo_wine_if(pt.x != x) ok(pt.x == x, "got x %ld, expected %d.\n", pt.x, x); - todo_wine_if(pt.y != y) ok(pt.y == y, "got y %ld, expected %d.\n", pt.y, y); }
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 17432ef867d..d6ee5d643e2 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1923,10 +1923,12 @@ static RECT map_monitor_rect( struct monitor *monitor, RECT rect, UINT dpi_from,
if (monitor->source) { - DEVMODEW current_mode = {.dmSize = sizeof(DEVMODEW)}, *mode_from, *mode_to; + float 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;
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; @@ -1935,23 +1937,31 @@ static RECT map_monitor_rect( struct monitor *monitor, RECT rect, UINT dpi_from, if (type_from == MDT_RAW_DPI) { monitor_virt_to_raw_ratio( monitor, &den, &num ); - mode_from = &monitor->source->physical; - mode_to = ¤t_mode; + from[0] = physical_mode.dmPosition.x + physical_mode.dmPelsWidth / 2.0; + from[1] = physical_mode.dmPosition.y + physical_mode.dmPelsHeight / 2.0; + to[0] = current_mode.dmPosition.x + current_mode.dmPelsWidth / 2.0; + to[1] = current_mode.dmPosition.y + current_mode.dmPelsHeight / 2.0; } else { monitor_virt_to_raw_ratio( monitor, &num, &den ); - mode_from = ¤t_mode; - mode_to = &monitor->source->physical; + from[0] = current_mode.dmPosition.x + current_mode.dmPelsWidth / 2.0; + from[1] = current_mode.dmPosition.y + current_mode.dmPelsHeight / 2.0; + to[0] = physical_mode.dmPosition.x + physical_mode.dmPelsWidth / 2.0; + to[1] = physical_mode.dmPosition.y + physical_mode.dmPelsHeight / 2.0; }
- rect = map_dpi_rect( rect, dpi_from, dpi * 2 ); - OffsetRect( &rect, -mode_from->dmPosition.x * 2 - mode_from->dmPelsWidth, - -mode_from->dmPosition.y * 2 - mode_from->dmPelsHeight ); - rect = map_dpi_rect( rect, den, num ); - OffsetRect( &rect, mode_to->dmPosition.x * 2 + mode_to->dmPelsWidth, - mode_to->dmPosition.y * 2 + mode_to->dmPelsHeight ); - return map_dpi_rect( rect, dpi * 2, dpi_to ); + for (int i = 0; i < ARRAY_SIZE(points); i++) + { + points[i] *= (float)dpi / dpi_from; + points[i] -= from[i & 1]; + points[i] *= (float)num / den; + points[i] += to[i & 1]; + points[i] *= (float)dpi_to / dpi; + } + + SetRect( &rect, round( points[0] ), round( points[1] ), round( points[2] ), round( points[3] ) ); + return rect; }
if (!dpi_from) dpi_from = monitor_get_dpi( monitor, type_from, &x, &y );
 
            This merge request was approved by Rémi Bernon.


