[PATCH 1/6] winex11.drv: Support automatic display position adjustment.

Zhiyi Zhang zzhang at codeweavers.com
Mon Jul 27 03:00:43 CDT 2020


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/user32/tests/monitor.c |  36 +---
 dlls/winex11.drv/settings.c | 382 +++++++++++++++++++++++++++++++-----
 dlls/winex11.drv/xrandr.c   |   7 +-
 3 files changed, 337 insertions(+), 88 deletions(-)

diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index 005627f28b0..0d32dbfeef9 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -283,29 +283,9 @@ struct device_info
     DEVMODEA original_mode;
 };
 
-static BOOL get_primary_adapter(CHAR *name)
-{
-    DISPLAY_DEVICEA dd;
-    DWORD i;
-
-    dd.cb = sizeof(dd);
-    for (i = 0; EnumDisplayDevicesA(NULL, i, &dd, 0); ++i)
-    {
-        if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
-        {
-            lstrcpyA(name, dd.DeviceName);
-            return TRUE;
-        }
-    }
-
-    return FALSE;
-}
-
 #define expect_dm(a, b, c) _expect_dm(__LINE__, a, b, c)
 static void _expect_dm(INT line, DEVMODEA expected, const CHAR *device, DWORD test)
 {
-    CHAR primary_adapter[CCHDEVICENAME];
-    BOOL is_primary;
     DEVMODEA dm;
     BOOL ret;
 
@@ -315,33 +295,23 @@ static void _expect_dm(INT line, DEVMODEA expected, const CHAR *device, DWORD te
     ret = EnumDisplaySettingsA(device, ENUM_CURRENT_SETTINGS, &dm);
     ok_(__FILE__, line)(ret, "Device %s test %d EnumDisplaySettingsA failed, error %#x\n", device, test, GetLastError());
 
-    ok(get_primary_adapter(primary_adapter), "Failed to get primary adapter name.\n");
-    is_primary = !lstrcmpA(primary_adapter, device);
-
     ok_(__FILE__, line)((dm.dmFields & expected.dmFields) == expected.dmFields,
             "Device %s test %d expect dmFields to contain %#x, got %#x\n", device, test, expected.dmFields, dm.dmFields);
     /* Wine doesn't support changing color depth yet */
     todo_wine_if(expected.dmBitsPerPel != 32 && expected.dmBitsPerPel != 24)
     ok_(__FILE__, line)(dm.dmBitsPerPel == expected.dmBitsPerPel, "Device %s test %d expect dmBitsPerPel %d, got %d\n",
             device, test, expected.dmBitsPerPel, dm.dmBitsPerPel);
-    /* Wine currently reports primary monitor settings for non-primary monitors */
-    todo_wine_if(!is_primary && dm.dmPelsWidth != expected.dmPelsWidth)
     ok_(__FILE__, line)(dm.dmPelsWidth == expected.dmPelsWidth, "Device %s test %d expect dmPelsWidth %d, got %d\n",
             device, test, expected.dmPelsWidth, dm.dmPelsWidth);
-    todo_wine_if(!is_primary && dm.dmPelsHeight != expected.dmPelsHeight)
     ok_(__FILE__, line)(dm.dmPelsHeight == expected.dmPelsHeight, "Device %s test %d expect dmPelsHeight %d, got %d\n",
             device, test, expected.dmPelsHeight, dm.dmPelsHeight);
-    todo_wine_if(!is_primary && dm.dmPosition.x != expected.dmPosition.x)
     ok_(__FILE__, line)(dm.dmPosition.x == expected.dmPosition.x, "Device %s test %d expect dmPosition.x %d, got %d\n",
             device, test, expected.dmPosition.x, dm.dmPosition.x);
-    todo_wine_if(!is_primary && dm.dmPosition.y != expected.dmPosition.y)
     ok_(__FILE__, line)(dm.dmPosition.y == expected.dmPosition.y, "Device %s test %d expect dmPosition.y %d, got %d\n",
             device, test, expected.dmPosition.y, dm.dmPosition.y);
-    todo_wine_if(!is_primary && dm.dmDisplayFrequency != expected.dmDisplayFrequency)
     ok_(__FILE__, line)(dm.dmDisplayFrequency == expected.dmDisplayFrequency,
             "Device %s test %d expect dmDisplayFrequency %d, got %d\n", device, test, expected.dmDisplayFrequency,
             dm.dmDisplayFrequency);
-    todo_wine_if(!is_primary && dm.dmDisplayOrientation != expected.dmDisplayOrientation)
     ok_(__FILE__, line)(dm.dmDisplayOrientation == expected.dmDisplayOrientation,
             "Device %s test %d expect dmDisplayOrientation %d, got %d\n", device, test, expected.dmDisplayOrientation,
             dm.dmDisplayOrientation);
@@ -778,7 +748,7 @@ static void test_ChangeDisplaySettingsEx(void)
         if (res)
         {
             /* The secondary adapter should be to the right of the primary adapter */
-            todo_wine ok(dm2.dmPosition.x == dm.dmPosition.x + dm.dmPelsWidth,
+            ok(dm2.dmPosition.x == dm.dmPosition.x + dm.dmPelsWidth,
                "Expected dm2.dmPosition.x %d, got %d.\n", dm.dmPosition.x + dm.dmPelsWidth,
                dm2.dmPosition.x);
             ok(dm2.dmPosition.y == dm.dmPosition.y, "Expected dm2.dmPosition.y %d, got %d.\n",
@@ -795,7 +765,7 @@ static void test_ChangeDisplaySettingsEx(void)
             dm2.dmSize = sizeof(dm2);
             res = EnumDisplaySettingsA(devices[1].name, ENUM_CURRENT_SETTINGS, &dm2);
             ok(res, "EnumDisplaySettingsA %s failed, error %#x\n", devices[1].name, GetLastError());
-            todo_wine ok((dm2.dmPosition.x == dm.dmPosition.x - dm2.dmPelsWidth),
+            ok(dm2.dmPosition.x == dm.dmPosition.x - dm2.dmPelsWidth,
                "Expected dmPosition.x %d, got %d.\n", dm.dmPosition.x - dm2.dmPelsWidth,
                dm2.dmPosition.x);
 
@@ -889,7 +859,7 @@ static void test_ChangeDisplaySettingsEx(void)
             dm2.dmSize = sizeof(dm2);
             res = EnumDisplaySettingsA(devices[1].name, ENUM_CURRENT_SETTINGS, &dm2);
             ok(res, "EnumDisplaySettingsA %s failed, error %#x\n", devices[1].name, GetLastError());
-            todo_wine ok(dm2.dmPosition.x == dm.dmPelsWidth, "Expect dmPosition.x %d, got %d\n",
+            ok(dm2.dmPosition.x == dm.dmPelsWidth, "Expect dmPosition.x %d, got %d\n",
                     dm.dmPelsWidth, dm2.dmPosition.x);
         }
         else
diff --git a/dlls/winex11.drv/settings.c b/dlls/winex11.drv/settings.c
index 02495756179..56f55e78b42 100644
--- a/dlls/winex11.drv/settings.c
+++ b/dlls/winex11.drv/settings.c
@@ -36,6 +36,15 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(x11settings);
 
+struct x11drv_display_setting
+{
+    ULONG_PTR id;
+    BOOL placed;
+    RECT new_rect;
+    RECT desired_rect;
+    DEVMODEW desired_mode;
+};
+
 static struct x11drv_mode_info *dd_modes = NULL;
 static unsigned int dd_mode_count = 0;
 static unsigned int dd_max_modes = 0;
@@ -534,6 +543,305 @@ static DEVMODEW *get_full_mode(ULONG_PTR id, const DEVMODEW *dev_mode)
     return full_mode;
 }
 
+static LONG get_display_settings(struct x11drv_display_setting **new_displays,
+        INT *new_display_count, const WCHAR *dev_name, DEVMODEW *dev_mode)
+{
+    struct x11drv_display_setting *displays;
+    DEVMODEW registry_mode, current_mode;
+    INT display_idx, display_count = 0;
+    DISPLAY_DEVICEW display_device;
+    LONG ret = DISP_CHANGE_FAILED;
+
+    display_device.cb = sizeof(display_device);
+    for (display_idx = 0; EnumDisplayDevicesW(NULL, display_idx, &display_device, 0); ++display_idx)
+        ++display_count;
+
+    displays = heap_calloc(display_count, sizeof(*displays));
+    if (!displays)
+        goto done;
+
+    for (display_idx = 0; display_idx < display_count; ++display_idx)
+    {
+        if (!EnumDisplayDevicesW(NULL, display_idx, &display_device, 0))
+            goto done;
+
+        if (!handler.get_id(display_device.DeviceName, &displays[display_idx].id))
+        {
+            ret = DISP_CHANGE_BADPARAM;
+            goto done;
+        }
+
+        if (!dev_mode)
+        {
+            registry_mode.dmSize = sizeof(registry_mode);
+            if (!EnumDisplaySettingsExW(display_device.DeviceName, ENUM_REGISTRY_SETTINGS, &registry_mode, 0))
+                goto done;
+
+            displays[display_idx].desired_mode = registry_mode;
+        }
+        else if (!lstrcmpiW(dev_name, display_device.DeviceName))
+        {
+            displays[display_idx].desired_mode = *dev_mode;
+            if (!(dev_mode->dmFields & DM_POSITION))
+            {
+                current_mode.dmSize = sizeof(current_mode);
+                if (!EnumDisplaySettingsExW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &current_mode, 0))
+                    goto done;
+
+                displays[display_idx].desired_mode.dmFields |= DM_POSITION;
+                displays[display_idx].desired_mode.u1.s2.dmPosition = current_mode.u1.s2.dmPosition;
+            }
+        }
+        else
+        {
+            current_mode.dmSize = sizeof(current_mode);
+            if (!EnumDisplaySettingsExW(display_device.DeviceName, ENUM_CURRENT_SETTINGS, &current_mode, 0))
+                goto done;
+
+            displays[display_idx].desired_mode = current_mode;
+        }
+
+        SetRect(&displays[display_idx].desired_rect,
+                displays[display_idx].desired_mode.u1.s2.dmPosition.x,
+                displays[display_idx].desired_mode.u1.s2.dmPosition.y,
+                displays[display_idx].desired_mode.u1.s2.dmPosition.x + displays[display_idx].desired_mode.dmPelsWidth,
+                displays[display_idx].desired_mode.u1.s2.dmPosition.y + displays[display_idx].desired_mode.dmPelsHeight);
+        lstrcpyW(displays[display_idx].desired_mode.dmDeviceName, display_device.DeviceName);
+    }
+
+    *new_displays = displays;
+    *new_display_count = display_count;
+    return DISP_CHANGE_SUCCESSFUL;
+
+done:
+    heap_free(displays);
+    return ret;
+}
+
+static INT offset_length(POINT offset)
+{
+    return offset.x * offset.x + offset.y * offset.y;
+}
+
+/* Check if a rect overlaps with placed display rects */
+static BOOL overlap_placed_displays(const RECT *rect, const struct x11drv_display_setting *displays, INT display_count)
+{
+    INT display_idx;
+    RECT intersect;
+
+    for (display_idx = 0; display_idx < display_count; ++display_idx)
+    {
+        if (displays[display_idx].placed &&
+            IntersectRect(&intersect, &displays[display_idx].new_rect, rect))
+            return TRUE;
+    }
+    return FALSE;
+}
+
+/* Get the offset with minimum length to place a display next to the placed displays with no spacing and overlaps */
+static POINT get_placement_offset(const struct x11drv_display_setting *displays, INT display_count, INT placing_idx)
+{
+    POINT points[8], left_top, offset, min_offset = {0, 0};
+    INT display_idx, point_idx, point_count, vertex_idx;
+    BOOL has_placed = FALSE, first = TRUE;
+    INT width, height;
+    RECT rect;
+
+    /* If the display to be placed is detached, no offset is needed to place it */
+    if (IsRectEmpty(&displays[placing_idx].desired_rect))
+        return min_offset;
+
+    /* If there is no placed and attached display, place this display as it is */
+    for (display_idx = 0; display_idx < display_count; ++display_idx)
+    {
+        if (displays[display_idx].placed && !IsRectEmpty(&displays[display_idx].new_rect))
+        {
+            has_placed = TRUE;
+            break;
+        }
+    }
+
+    if (!has_placed)
+        return min_offset;
+
+    /* Try to place this display with each of its four vertices at every vertex of the placed
+     * displays and see which combination has the minimum offset length */
+    width = displays[placing_idx].desired_rect.right - displays[placing_idx].desired_rect.left;
+    height = displays[placing_idx].desired_rect.bottom - displays[placing_idx].desired_rect.top;
+
+    for (display_idx = 0; display_idx < display_count; ++display_idx)
+    {
+        if (!displays[display_idx].placed || IsRectEmpty(&displays[display_idx].new_rect))
+            continue;
+
+        /* Get four vertices of the placed display rectangle */
+        points[0].x = displays[display_idx].new_rect.left;
+        points[0].y = displays[display_idx].new_rect.top;
+        points[1].x = displays[display_idx].new_rect.left;
+        points[1].y = displays[display_idx].new_rect.bottom;
+        points[2].x = displays[display_idx].new_rect.right;
+        points[2].y = displays[display_idx].new_rect.top;
+        points[3].x = displays[display_idx].new_rect.right;
+        points[3].y = displays[display_idx].new_rect.bottom;
+        point_count = 4;
+
+        /* Intersected points when moving the display to be placed horizontally */
+        if (displays[placing_idx].desired_rect.bottom >= displays[display_idx].new_rect.top &&
+            displays[placing_idx].desired_rect.top <= displays[display_idx].new_rect.bottom)
+        {
+            points[point_count].x = displays[display_idx].new_rect.left;
+            points[point_count++].y = displays[placing_idx].desired_rect.top;
+            points[point_count].x = displays[display_idx].new_rect.right;
+            points[point_count++].y = displays[placing_idx].desired_rect.top;
+        }
+        /* Intersected points when moving the display to be placed vertically */
+        if (displays[placing_idx].desired_rect.left <= displays[display_idx].new_rect.right &&
+            displays[placing_idx].desired_rect.right >= displays[display_idx].new_rect.left)
+        {
+            points[point_count].x = displays[placing_idx].desired_rect.left;
+            points[point_count++].y = displays[display_idx].new_rect.top;
+            points[point_count].x = displays[placing_idx].desired_rect.left;
+            points[point_count++].y = displays[display_idx].new_rect.bottom;
+        }
+
+        /* Try moving each vertex of the display rectangle to each points */
+        for (point_idx = 0; point_idx < point_count; ++point_idx)
+        {
+            for (vertex_idx = 0; vertex_idx < 4; ++vertex_idx)
+            {
+                switch (vertex_idx)
+                {
+                /* Move the bottom right vertex to the point */
+                case 0:
+                    left_top.x = points[point_idx].x - width;
+                    left_top.y = points[point_idx].y - height;
+                    break;
+                /* Move the bottom left vertex to the point */
+                case 1:
+                    left_top.x = points[point_idx].x;
+                    left_top.y = points[point_idx].y - height;
+                    break;
+                /* Move the top right vertex to the point */
+                case 2:
+                    left_top.x = points[point_idx].x - width;
+                    left_top.y = points[point_idx].y;
+                    break;
+                /* Move the top left vertex to the point */
+                case 3:
+                    left_top.x = points[point_idx].x;
+                    left_top.y = points[point_idx].y;
+                    break;
+                }
+
+                offset.x = left_top.x - displays[placing_idx].desired_rect.left;
+                offset.y = left_top.y - displays[placing_idx].desired_rect.top;
+                rect = displays[placing_idx].desired_rect;
+                OffsetRect(&rect, offset.x, offset.y);
+                if (!overlap_placed_displays(&rect, displays, display_count))
+                {
+                    if (first)
+                    {
+                        min_offset = offset;
+                        first = FALSE;
+                        continue;
+                    }
+
+                    if (offset_length(offset) < offset_length(min_offset))
+                        min_offset = offset;
+                }
+            }
+        }
+    }
+
+    return min_offset;
+}
+
+static void place_all_displays(struct x11drv_display_setting *displays, INT display_count)
+{
+    INT left_most = INT_MAX, top_most = INT_MAX;
+    INT placing_idx, display_idx;
+    POINT min_offset, offset;
+
+    /* Place all displays with no extra space between them and no overlapping */
+    while (1)
+    {
+        /* Place the unplaced display with the minimum offset length first */
+        placing_idx = -1;
+        for (display_idx = 0; display_idx < display_count; ++display_idx)
+        {
+            if (displays[display_idx].placed)
+                continue;
+
+            offset = get_placement_offset(displays, display_count, display_idx);
+            if (placing_idx == -1 || offset_length(offset) < offset_length(min_offset))
+            {
+                min_offset = offset;
+                placing_idx = display_idx;
+            }
+        }
+
+        /* If all displays are placed */
+        if (placing_idx == -1)
+            break;
+
+        displays[placing_idx].new_rect = displays[placing_idx].desired_rect;
+        OffsetRect(&displays[placing_idx].new_rect, min_offset.x, min_offset.y);
+        displays[placing_idx].placed = TRUE;
+    }
+
+    for (display_idx = 0; display_idx < display_count; ++display_idx)
+    {
+        displays[display_idx].desired_mode.u1.s2.dmPosition.x = displays[display_idx].new_rect.left;
+        displays[display_idx].desired_mode.u1.s2.dmPosition.y = displays[display_idx].new_rect.top;
+        left_most = min(left_most, displays[display_idx].new_rect.left);
+        top_most = min(top_most, displays[display_idx].new_rect.top);
+    }
+
+    /* Convert virtual screen coordinates to root coordinates */
+    for (display_idx = 0; display_idx < display_count; ++display_idx)
+    {
+        displays[display_idx].desired_mode.u1.s2.dmPosition.x -= left_most;
+        displays[display_idx].desired_mode.u1.s2.dmPosition.y -= top_most;
+    }
+}
+
+static LONG apply_display_settings(struct x11drv_display_setting *displays, INT display_count)
+{
+    DEVMODEW *full_mode;
+    INT display_idx;
+    LONG ret;
+
+    for (display_idx = 0; display_idx < display_count; ++display_idx)
+    {
+        if (is_detached_mode(&displays[display_idx].desired_mode))
+        {
+            FIXME("Detaching %s is currently unsupported.\n",
+                  wine_dbgstr_w(displays[display_idx].desired_mode.dmDeviceName));
+            continue;
+        }
+
+        full_mode = get_full_mode(displays[display_idx].id, &displays[display_idx].desired_mode);
+        if (!full_mode)
+            return DISP_CHANGE_BADMODE;
+
+        full_mode->dmFields |= DM_POSITION;
+        full_mode->u1.s2.dmPosition = displays[display_idx].desired_mode.u1.s2.dmPosition;
+        TRACE("handler:%s changing %s to position:(%d,%d) resolution:%ux%u frequency:%uHz "
+              "depth:%ubits orientation:%#x.\n", handler.name,
+              wine_dbgstr_w(displays[display_idx].desired_mode.dmDeviceName),
+              full_mode->u1.s2.dmPosition.x, full_mode->u1.s2.dmPosition.y, full_mode->dmPelsWidth,
+              full_mode->dmPelsHeight, full_mode->dmDisplayFrequency, full_mode->dmBitsPerPel,
+              full_mode->u1.s2.dmDisplayOrientation);
+
+        ret = handler.set_current_mode(displays[display_idx].id, full_mode);
+        heap_free(full_mode);
+        if (ret != DISP_CHANGE_SUCCESSFUL)
+            return ret;
+    }
+
+    return DISP_CHANGE_SUCCESSFUL;
+}
+
 /***********************************************************************
  *		ChangeDisplaySettingsEx  (X11DRV.@)
  *
@@ -541,10 +849,11 @@ static DEVMODEW *get_full_mode(ULONG_PTR id, const DEVMODEW *dev_mode)
 LONG CDECL X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
                                            HWND hwnd, DWORD flags, LPVOID lpvoid )
 {
+    struct x11drv_display_setting *displays;
     WCHAR primary_adapter[CCHDEVICENAME];
     char bpp_buffer[16], freq_buffer[18];
-    DEVMODEW default_mode, *full_mode;
-    ULONG_PTR id;
+    INT display_idx, display_count;
+    DEVMODEW default_mode;
     LONG ret;
     DWORD i;
 
@@ -552,70 +861,39 @@ LONG CDECL X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
     if (!handler.name)
         goto old_interface;
 
-    if (!get_primary_adapter(primary_adapter))
-        return DISP_CHANGE_FAILED;
+    ret = get_display_settings(&displays, &display_count, devname, devmode);
+    if (ret != DISP_CHANGE_SUCCESSFUL)
+        return ret;
 
-    if (!devname && !devmode)
+    if (flags & CDS_UPDATEREGISTRY && devname && devmode)
     {
-        default_mode.dmSize = sizeof(default_mode);
-        if (!EnumDisplaySettingsExW(primary_adapter, ENUM_REGISTRY_SETTINGS, &default_mode, 0))
+        for (display_idx = 0; display_idx < display_count; ++display_idx)
         {
-            ERR("Default mode not found for %s!\n", wine_dbgstr_w(primary_adapter));
-            return DISP_CHANGE_BADMODE;
+            if (!lstrcmpiW(displays[display_idx].desired_mode.dmDeviceName, devname))
+            {
+                if (!write_registry_settings(devname, &displays[display_idx].desired_mode))
+                {
+                    ERR("Failed to write %s display settings to registry.\n", wine_dbgstr_w(devname));
+                    heap_free(displays);
+                    return DISP_CHANGE_NOTUPDATED;
+                }
+                break;
+            }
         }
-
-        devname = primary_adapter;
-        devmode = &default_mode;
-    }
-
-    if (!handler.get_id(devname, &id))
-    {
-        ERR("Failed to get %s device id.\n", wine_dbgstr_w(devname));
-        return DISP_CHANGE_BADPARAM;
-    }
-
-    if (is_detached_mode(devmode))
-    {
-        FIXME("Detaching adapters is currently unsupported.\n");
-        return DISP_CHANGE_SUCCESSFUL;
-    }
-
-    if (!(full_mode = get_full_mode(id, devmode)))
-    {
-        ERR("Failed to find a valid mode.\n");
-        return DISP_CHANGE_BADMODE;
-    }
-
-    if (flags & CDS_UPDATEREGISTRY && !write_registry_settings(devname, full_mode))
-    {
-        ERR("Failed to write %s display settings to registry.\n", wine_dbgstr_w(devname));
-        heap_free(full_mode);
-        return DISP_CHANGE_NOTUPDATED;
-    }
-
-    if (lstrcmpiW(primary_adapter, devname))
-    {
-        FIXME("Changing non-primary adapter %s settings is currently unsupported.\n",
-              wine_dbgstr_w(devname));
-        heap_free(full_mode);
-        return DISP_CHANGE_SUCCESSFUL;
     }
 
     if (flags & (CDS_TEST | CDS_NORESET))
     {
-        heap_free(full_mode);
+        heap_free(displays);
         return DISP_CHANGE_SUCCESSFUL;
     }
 
-    TRACE("handler:%s device:%s position:(%d,%d) resolution:%ux%u frequency:%uHz depth:%ubits "
-          "orientation:%#x.\n", handler.name, wine_dbgstr_w(devname), full_mode->u1.s2.dmPosition.x,
-          full_mode->u1.s2.dmPosition.y, full_mode->dmPelsWidth, full_mode->dmPelsHeight,
-          full_mode->dmDisplayFrequency, full_mode->dmBitsPerPel, full_mode->u1.s2.dmDisplayOrientation);
+    place_all_displays(displays, display_count);
 
-    ret = handler.set_current_mode(id, full_mode);
+    ret = apply_display_settings(displays, display_count);
     if (ret == DISP_CHANGE_SUCCESSFUL)
         X11DRV_DisplayDevices_Update(TRUE);
-    heap_free(full_mode);
+    heap_free(displays);
     return ret;
 
 old_interface:
diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c
index d111b960fa6..4fbb2e540dc 100644
--- a/dlls/winex11.drv/xrandr.c
+++ b/dlls/winex11.drv/xrandr.c
@@ -1367,12 +1367,13 @@ static LONG xrandr14_set_current_mode( ULONG_PTR id, DEVMODEW *mode )
         goto done;
 
     get_screen_size( screen_resources, &screen_width, &screen_height );
-    screen_width = max( screen_width, crtc_info->x + mode->dmPelsWidth );
-    screen_height = max( screen_height, crtc_info->y + mode->dmPelsHeight );
+    screen_width = max( screen_width, mode->u1.s2.dmPosition.x + mode->dmPelsWidth );
+    screen_height = max( screen_height, mode->u1.s2.dmPosition.y + mode->dmPelsHeight );
     set_screen_size( screen_width, screen_height );
 
     status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime,
-                                crtc_info->x, crtc_info->y, rrmode, rotation, outputs, output_count );
+                                mode->u1.s2.dmPosition.x, mode->u1.s2.dmPosition.y, rrmode,
+                                rotation, outputs, output_count );
     if (status == RRSetConfigSuccess)
         ret = DISP_CHANGE_SUCCESSFUL;
 
-- 
2.25.1




More information about the wine-devel mailing list