winex11.drv: Support detaching adapters.

Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zhiyi Zhang 2020-07-27 16:01:04 +08:00 committed by Alexandre Julliard
parent 4a24816313
commit d13b61b738
3 changed files with 66 additions and 15 deletions

View File

@ -612,10 +612,10 @@ static void test_ChangeDisplaySettingsEx(void)
dd.cb = sizeof(dd); dd.cb = sizeof(dd);
res = EnumDisplayDevicesA(NULL, devices[device].index, &dd, 0); res = EnumDisplayDevicesA(NULL, devices[device].index, &dd, 0);
ok(res, "EnumDisplayDevicesA %s failed, error %#x\n", devices[device].name, GetLastError()); 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); 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 */ /* Test changing each adapter to every available mode */

View File

@ -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; DEVMODEW *full_mode;
BOOL attached_mode;
INT display_idx; INT display_idx;
LONG ret; LONG ret;
for (display_idx = 0; display_idx < display_count; ++display_idx) for (display_idx = 0; display_idx < display_count; ++display_idx)
{ {
if (is_detached_mode(&displays[display_idx].desired_mode)) attached_mode = !is_detached_mode(&displays[display_idx].desired_mode);
{ if ((attached_mode && !do_attach) || (!attached_mode && do_attach))
FIXME("Detaching %s is currently unsupported.\n",
wine_dbgstr_w(displays[display_idx].desired_mode.dmDeviceName));
continue; continue;
}
if (attached_mode)
{
full_mode = get_full_mode(displays[display_idx].id, &displays[display_idx].desired_mode); full_mode = get_full_mode(displays[display_idx].id, &displays[display_idx].desired_mode);
if (!full_mode) if (!full_mode)
return DISP_CHANGE_BADMODE; return DISP_CHANGE_BADMODE;
full_mode->dmFields |= DM_POSITION; full_mode->dmFields |= DM_POSITION;
full_mode->u1.s2.dmPosition = displays[display_idx].desired_mode.u1.s2.dmPosition; full_mode->u1.s2.dmPosition = displays[display_idx].desired_mode.u1.s2.dmPosition;
}
else
{
full_mode = &displays[display_idx].desired_mode;
}
TRACE("handler:%s changing %s to position:(%d,%d) resolution:%ux%u frequency:%uHz " TRACE("handler:%s changing %s to position:(%d,%d) resolution:%ux%u frequency:%uHz "
"depth:%ubits orientation:%#x.\n", handler.name, "depth:%ubits orientation:%#x.\n", handler.name,
wine_dbgstr_w(displays[display_idx].desired_mode.dmDeviceName), wine_dbgstr_w(displays[display_idx].desired_mode.dmDeviceName),
@ -834,6 +840,7 @@ static LONG apply_display_settings(struct x11drv_display_setting *displays, INT
full_mode->u1.s2.dmDisplayOrientation); full_mode->u1.s2.dmDisplayOrientation);
ret = handler.set_current_mode(displays[display_idx].id, full_mode); ret = handler.set_current_mode(displays[display_idx].id, full_mode);
if (attached_mode)
heap_free(full_mode); heap_free(full_mode);
if (ret != DISP_CHANGE_SUCCESSFUL) if (ret != DISP_CHANGE_SUCCESSFUL)
return ret; return ret;
@ -842,6 +849,19 @@ static LONG apply_display_settings(struct x11drv_display_setting *displays, INT
return DISP_CHANGE_SUCCESSFUL; 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.@) * ChangeDisplaySettingsEx (X11DRV.@)
* *
@ -888,9 +908,19 @@ LONG CDECL X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
return DISP_CHANGE_SUCCESSFUL; 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); 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) if (ret == DISP_CHANGE_SUCCESSFUL)
X11DRV_DisplayDevices_Update(TRUE); X11DRV_DisplayDevices_Update(TRUE);
heap_free(displays); heap_free(displays);

View File

@ -1306,6 +1306,27 @@ static LONG xrandr14_set_current_mode( ULONG_PTR id, DEVMODEW *mode )
if (!output_info || output_info->connection != RR_Connected) if (!output_info || output_info->connection != RR_Connected)
goto done; 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 */ /* Attached */
if (output_info->crtc) if (output_info->crtc)
{ {