winex11.drv: Support automatic display position adjustment.
Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
00b64430e8
commit
4a24816313
|
@ -283,29 +283,9 @@ struct device_info
|
||||||
DEVMODEA original_mode;
|
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)
|
#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)
|
static void _expect_dm(INT line, DEVMODEA expected, const CHAR *device, DWORD test)
|
||||||
{
|
{
|
||||||
CHAR primary_adapter[CCHDEVICENAME];
|
|
||||||
BOOL is_primary;
|
|
||||||
DEVMODEA dm;
|
DEVMODEA dm;
|
||||||
BOOL ret;
|
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);
|
ret = EnumDisplaySettingsA(device, ENUM_CURRENT_SETTINGS, &dm);
|
||||||
ok_(__FILE__, line)(ret, "Device %s test %d EnumDisplaySettingsA failed, error %#x\n", device, test, GetLastError());
|
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,
|
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);
|
"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 */
|
/* Wine doesn't support changing color depth yet */
|
||||||
todo_wine_if(expected.dmBitsPerPel != 32 && expected.dmBitsPerPel != 24)
|
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",
|
ok_(__FILE__, line)(dm.dmBitsPerPel == expected.dmBitsPerPel, "Device %s test %d expect dmBitsPerPel %d, got %d\n",
|
||||||
device, test, expected.dmBitsPerPel, dm.dmBitsPerPel);
|
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",
|
ok_(__FILE__, line)(dm.dmPelsWidth == expected.dmPelsWidth, "Device %s test %d expect dmPelsWidth %d, got %d\n",
|
||||||
device, test, expected.dmPelsWidth, dm.dmPelsWidth);
|
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",
|
ok_(__FILE__, line)(dm.dmPelsHeight == expected.dmPelsHeight, "Device %s test %d expect dmPelsHeight %d, got %d\n",
|
||||||
device, test, expected.dmPelsHeight, dm.dmPelsHeight);
|
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",
|
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);
|
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",
|
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);
|
device, test, expected.dmPosition.y, dm.dmPosition.y);
|
||||||
todo_wine_if(!is_primary && dm.dmDisplayFrequency != expected.dmDisplayFrequency)
|
|
||||||
ok_(__FILE__, line)(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,
|
"Device %s test %d expect dmDisplayFrequency %d, got %d\n", device, test, expected.dmDisplayFrequency,
|
||||||
dm.dmDisplayFrequency);
|
dm.dmDisplayFrequency);
|
||||||
todo_wine_if(!is_primary && dm.dmDisplayOrientation != expected.dmDisplayOrientation)
|
|
||||||
ok_(__FILE__, line)(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,
|
"Device %s test %d expect dmDisplayOrientation %d, got %d\n", device, test, expected.dmDisplayOrientation,
|
||||||
dm.dmDisplayOrientation);
|
dm.dmDisplayOrientation);
|
||||||
|
@ -778,7 +748,7 @@ static void test_ChangeDisplaySettingsEx(void)
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
/* The secondary adapter should be to the right of the primary adapter */
|
/* 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,
|
"Expected dm2.dmPosition.x %d, got %d.\n", dm.dmPosition.x + dm.dmPelsWidth,
|
||||||
dm2.dmPosition.x);
|
dm2.dmPosition.x);
|
||||||
ok(dm2.dmPosition.y == dm.dmPosition.y, "Expected dm2.dmPosition.y %d, got %d.\n",
|
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);
|
dm2.dmSize = sizeof(dm2);
|
||||||
res = EnumDisplaySettingsA(devices[1].name, ENUM_CURRENT_SETTINGS, &dm2);
|
res = EnumDisplaySettingsA(devices[1].name, ENUM_CURRENT_SETTINGS, &dm2);
|
||||||
ok(res, "EnumDisplaySettingsA %s failed, error %#x\n", devices[1].name, GetLastError());
|
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,
|
"Expected dmPosition.x %d, got %d.\n", dm.dmPosition.x - dm2.dmPelsWidth,
|
||||||
dm2.dmPosition.x);
|
dm2.dmPosition.x);
|
||||||
|
|
||||||
|
@ -889,7 +859,7 @@ static void test_ChangeDisplaySettingsEx(void)
|
||||||
dm2.dmSize = sizeof(dm2);
|
dm2.dmSize = sizeof(dm2);
|
||||||
res = EnumDisplaySettingsA(devices[1].name, ENUM_CURRENT_SETTINGS, &dm2);
|
res = EnumDisplaySettingsA(devices[1].name, ENUM_CURRENT_SETTINGS, &dm2);
|
||||||
ok(res, "EnumDisplaySettingsA %s failed, error %#x\n", devices[1].name, GetLastError());
|
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);
|
dm.dmPelsWidth, dm2.dmPosition.x);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -36,6 +36,15 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(x11settings);
|
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 struct x11drv_mode_info *dd_modes = NULL;
|
||||||
static unsigned int dd_mode_count = 0;
|
static unsigned int dd_mode_count = 0;
|
||||||
static unsigned int dd_max_modes = 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;
|
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, ®istry_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, ¤t_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, ¤t_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.@)
|
* 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,
|
LONG CDECL X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
|
||||||
HWND hwnd, DWORD flags, LPVOID lpvoid )
|
HWND hwnd, DWORD flags, LPVOID lpvoid )
|
||||||
{
|
{
|
||||||
|
struct x11drv_display_setting *displays;
|
||||||
WCHAR primary_adapter[CCHDEVICENAME];
|
WCHAR primary_adapter[CCHDEVICENAME];
|
||||||
char bpp_buffer[16], freq_buffer[18];
|
char bpp_buffer[16], freq_buffer[18];
|
||||||
DEVMODEW default_mode, *full_mode;
|
INT display_idx, display_count;
|
||||||
ULONG_PTR id;
|
DEVMODEW default_mode;
|
||||||
LONG ret;
|
LONG ret;
|
||||||
DWORD i;
|
DWORD i;
|
||||||
|
|
||||||
|
@ -552,70 +861,39 @@ LONG CDECL X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
|
||||||
if (!handler.name)
|
if (!handler.name)
|
||||||
goto old_interface;
|
goto old_interface;
|
||||||
|
|
||||||
if (!get_primary_adapter(primary_adapter))
|
ret = get_display_settings(&displays, &display_count, devname, devmode);
|
||||||
return DISP_CHANGE_FAILED;
|
if (ret != DISP_CHANGE_SUCCESSFUL)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (!devname && !devmode)
|
if (flags & CDS_UPDATEREGISTRY && devname && devmode)
|
||||||
{
|
{
|
||||||
default_mode.dmSize = sizeof(default_mode);
|
for (display_idx = 0; display_idx < display_count; ++display_idx)
|
||||||
if (!EnumDisplaySettingsExW(primary_adapter, ENUM_REGISTRY_SETTINGS, &default_mode, 0))
|
|
||||||
{
|
{
|
||||||
ERR("Default mode not found for %s!\n", wine_dbgstr_w(primary_adapter));
|
if (!lstrcmpiW(displays[display_idx].desired_mode.dmDeviceName, devname))
|
||||||
return DISP_CHANGE_BADMODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
devname = primary_adapter;
|
|
||||||
devmode = &default_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!handler.get_id(devname, &id))
|
|
||||||
{
|
{
|
||||||
ERR("Failed to get %s device id.\n", wine_dbgstr_w(devname));
|
if (!write_registry_settings(devname, &displays[display_idx].desired_mode))
|
||||||
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));
|
ERR("Failed to write %s display settings to registry.\n", wine_dbgstr_w(devname));
|
||||||
heap_free(full_mode);
|
heap_free(displays);
|
||||||
return DISP_CHANGE_NOTUPDATED;
|
return DISP_CHANGE_NOTUPDATED;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
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))
|
if (flags & (CDS_TEST | CDS_NORESET))
|
||||||
{
|
{
|
||||||
heap_free(full_mode);
|
heap_free(displays);
|
||||||
return DISP_CHANGE_SUCCESSFUL;
|
return DISP_CHANGE_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("handler:%s device:%s position:(%d,%d) resolution:%ux%u frequency:%uHz depth:%ubits "
|
place_all_displays(displays, display_count);
|
||||||
"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);
|
|
||||||
|
|
||||||
ret = handler.set_current_mode(id, full_mode);
|
ret = apply_display_settings(displays, display_count);
|
||||||
if (ret == DISP_CHANGE_SUCCESSFUL)
|
if (ret == DISP_CHANGE_SUCCESSFUL)
|
||||||
X11DRV_DisplayDevices_Update(TRUE);
|
X11DRV_DisplayDevices_Update(TRUE);
|
||||||
heap_free(full_mode);
|
heap_free(displays);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
old_interface:
|
old_interface:
|
||||||
|
|
|
@ -1367,12 +1367,13 @@ static LONG xrandr14_set_current_mode( ULONG_PTR id, DEVMODEW *mode )
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
get_screen_size( screen_resources, &screen_width, &screen_height );
|
get_screen_size( screen_resources, &screen_width, &screen_height );
|
||||||
screen_width = max( screen_width, crtc_info->x + mode->dmPelsWidth );
|
screen_width = max( screen_width, mode->u1.s2.dmPosition.x + mode->dmPelsWidth );
|
||||||
screen_height = max( screen_height, crtc_info->y + mode->dmPelsHeight );
|
screen_height = max( screen_height, mode->u1.s2.dmPosition.y + mode->dmPelsHeight );
|
||||||
set_screen_size( screen_width, screen_height );
|
set_screen_size( screen_width, screen_height );
|
||||||
|
|
||||||
status = pXRRSetCrtcConfig( gdi_display, screen_resources, crtc, CurrentTime,
|
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)
|
if (status == RRSetConfigSuccess)
|
||||||
ret = DISP_CHANGE_SUCCESSFUL;
|
ret = DISP_CHANGE_SUCCESSFUL;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue