Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/user32/tests/monitor.c | 4 +-- dlls/winex11.drv/settings.c | 56 ++++++++++++++++++++++++++++--------- dlls/winex11.drv/xrandr.c | 21 ++++++++++++++ 3 files changed, 66 insertions(+), 15 deletions(-)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index 0d32dbfeef9..85fb2f080a7 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -612,10 +612,10 @@ static void test_ChangeDisplaySettingsEx(void) dd.cb = sizeof(dd); res = EnumDisplayDevicesA(NULL, devices[device].index, &dd, 0); ok(res, "EnumDisplayDevicesA %s failed, error %#x\n", devices[device].name, GetLastError()); - todo_wine ok(!(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP), "Expect device %s detached.\n", devices[device].name); + ok(!(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP), "Expect device %s detached.\n", devices[device].name);
count = GetSystemMetrics(SM_CMONITORS); - todo_wine ok(count == old_count - 1, "Expect monitor count %d, got %d\n", old_count - 1, count); + ok(count == old_count - 1, "Expect monitor count %d, got %d\n", old_count - 1, count); }
/* Test changing each adapter to every available mode */ diff --git a/dlls/winex11.drv/settings.c b/dlls/winex11.drv/settings.c index 56f55e78b42..7c7d9507187 100644 --- a/dlls/winex11.drv/settings.c +++ b/dlls/winex11.drv/settings.c @@ -805,27 +805,33 @@ static void place_all_displays(struct x11drv_display_setting *displays, INT disp } }
-static LONG apply_display_settings(struct x11drv_display_setting *displays, INT display_count) +static LONG apply_display_settings(struct x11drv_display_setting *displays, INT display_count, BOOL do_attach) { DEVMODEW *full_mode; + BOOL attached_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)); + attached_mode = !is_detached_mode(&displays[display_idx].desired_mode); + if ((attached_mode && !do_attach) || (!attached_mode && do_attach)) continue; + + if (attached_mode) + { + 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; + } + else + { + full_mode = &displays[display_idx].desired_mode; }
- 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), @@ -834,7 +840,8 @@ static LONG apply_display_settings(struct x11drv_display_setting *displays, INT full_mode->u1.s2.dmDisplayOrientation);
ret = handler.set_current_mode(displays[display_idx].id, full_mode); - heap_free(full_mode); + if (attached_mode) + heap_free(full_mode); if (ret != DISP_CHANGE_SUCCESSFUL) return ret; } @@ -842,6 +849,19 @@ static LONG apply_display_settings(struct x11drv_display_setting *displays, INT return DISP_CHANGE_SUCCESSFUL; }
+static BOOL all_detached_settings(const struct x11drv_display_setting *displays, INT display_count) +{ + INT display_idx; + + for (display_idx = 0; display_idx < display_count; ++display_idx) + { + if (!is_detached_mode(&displays[display_idx].desired_mode)) + return FALSE; + } + + return TRUE; +} + /*********************************************************************** * ChangeDisplaySettingsEx (X11DRV.@) * @@ -888,9 +908,19 @@ LONG CDECL X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode, return DISP_CHANGE_SUCCESSFUL; }
+ if (all_detached_settings(displays, display_count)) + { + WARN("Detaching all displays is not permitted.\n"); + heap_free(displays); + return DISP_CHANGE_SUCCESSFUL; + } + place_all_displays(displays, display_count);
- ret = apply_display_settings(displays, display_count); + /* Detach displays first to free up CRTCs */ + ret = apply_display_settings(displays, display_count, FALSE); + if (ret == DISP_CHANGE_SUCCESSFUL) + ret = apply_display_settings(displays, display_count, TRUE); if (ret == DISP_CHANGE_SUCCESSFUL) X11DRV_DisplayDevices_Update(TRUE); heap_free(displays); diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c index 4fbb2e540dc..67fd2851825 100644 --- a/dlls/winex11.drv/xrandr.c +++ b/dlls/winex11.drv/xrandr.c @@ -1306,6 +1306,27 @@ static LONG xrandr14_set_current_mode( ULONG_PTR id, DEVMODEW *mode ) if (!output_info || output_info->connection != RR_Connected) goto done;
+ if (is_detached_mode(mode)) + { + /* Already detached */ + if (!output_info->crtc) + { + ret = DISP_CHANGE_SUCCESSFUL; + goto done; + } + + /* Execute detach operation */ + status = pXRRSetCrtcConfig( gdi_display, screen_resources, output_info->crtc, + CurrentTime, 0, 0, None, RR_Rotate_0, NULL, 0 ); + if (status == RRSetConfigSuccess) + { + get_screen_size( screen_resources, &screen_width, &screen_height ); + set_screen_size( screen_width, screen_height ); + ret = DISP_CHANGE_SUCCESSFUL; + } + goto done; + } + /* Attached */ if (output_info->crtc) {