[PATCH 1/7] user32/tests: Add DisplayConfigSetDeviceInfo() tests.
Zhiyi Zhang
zzhang at codeweavers.com
Wed Sep 1 01:37:21 CDT 2021
Test that DisplayConfigSetDeviceInfo() can be used for getting and setting display DPI.
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
dlls/user32/tests/monitor.c | 132 +++++++++++++++++++++++++++++++++---
include/wingdi.h | 51 ++++++++++----
2 files changed, 161 insertions(+), 22 deletions(-)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index dfb57d3e2c2..cee7b629cd7 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -19,34 +19,49 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+
#include "wine/test.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winreg.h"
+#include "winternl.h"
+#include "ddk/d3dkmthk.h"
#include "wine/heap.h"
#include <stdio.h>
-static HMODULE hdll;
static LONG (WINAPI *pGetDisplayConfigBufferSizes)(UINT32,UINT32*,UINT32*);
+static BOOL (WINAPI *pGetDpiForMonitorInternal)(HMONITOR,UINT,UINT*,UINT*);
static LONG (WINAPI *pQueryDisplayConfig)(UINT32,UINT32*,DISPLAYCONFIG_PATH_INFO*,UINT32*,
DISPLAYCONFIG_MODE_INFO*,DISPLAYCONFIG_TOPOLOGY_ID*);
static LONG (WINAPI *pDisplayConfigGetDeviceInfo)(DISPLAYCONFIG_DEVICE_INFO_HEADER*);
+static LONG (WINAPI *pDisplayConfigSetDeviceInfo)(DISPLAYCONFIG_DEVICE_INFO_HEADER*);
static DPI_AWARENESS_CONTEXT (WINAPI *pSetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
+static NTSTATUS (WINAPI *pD3DKMTCloseAdapter)(const D3DKMT_CLOSEADAPTER*);
+static NTSTATUS (WINAPI *pD3DKMTOpenAdapterFromGdiDisplayName)(D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME*);
+
static void init_function_pointers(void)
{
- hdll = GetModuleHandleA("user32.dll");
+ HMODULE user32 = GetModuleHandleA("user32.dll");
+ HMODULE gdi32 = GetModuleHandleA("gdi32.dll");
-#define GET_PROC(func) \
- p ## func = (void*)GetProcAddress(hdll, #func); \
- if(!p ## func) \
- trace("GetProcAddress(%s) failed\n", #func);
+#define GET_PROC(module, func) \
+ p##func = (void *)GetProcAddress(module, #func); \
+ if (!p##func) \
+ trace("GetProcAddress(%s, %s) failed.\n", #module, #func);
- GET_PROC(GetDisplayConfigBufferSizes)
- GET_PROC(QueryDisplayConfig)
- GET_PROC(DisplayConfigGetDeviceInfo)
- GET_PROC(SetThreadDpiAwarenessContext)
+ GET_PROC(user32, GetDisplayConfigBufferSizes)
+ GET_PROC(user32, GetDpiForMonitorInternal)
+ GET_PROC(user32, QueryDisplayConfig)
+ GET_PROC(user32, DisplayConfigGetDeviceInfo)
+ GET_PROC(user32, DisplayConfigSetDeviceInfo)
+ GET_PROC(user32, SetThreadDpiAwarenessContext)
+
+ GET_PROC(gdi32, D3DKMTCloseAdapter)
+ GET_PROC(gdi32, D3DKMTOpenAdapterFromGdiDisplayName)
#undef GET_PROC
}
@@ -68,6 +83,23 @@ static void flush_events(void)
}
}
+static unsigned int get_primary_dpi(void)
+{
+ DPI_AWARENESS_CONTEXT old_context;
+ UINT dpi_x = 0, dpi_y = 0;
+ POINT point = {0, 0};
+ HMONITOR monitor;
+
+ if (!pSetThreadDpiAwarenessContext || !pGetDpiForMonitorInternal)
+ return 0;
+
+ old_context = pSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
+ monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);
+ pGetDpiForMonitorInternal(monitor, 0, &dpi_x, &dpi_y);
+ pSetThreadDpiAwarenessContext(old_context);
+ return dpi_y;
+}
+
static int get_bitmap_stride(int width, int bpp)
{
return ((width * bpp + 15) >> 3) & ~1;
@@ -1959,6 +1991,85 @@ static void test_display_config(void)
test_DisplayConfigGetDeviceInfo();
}
+static void test_DisplayConfigSetDeviceInfo(void)
+{
+ static const unsigned int scales[] = {100, 125, 150, 175, 200, 225, 250, 300, 350, 400, 450, 500};
+ int current_scale, current_scale_idx, recommended_scale_idx, step, dpi, old_dpi;
+ D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME open_adapter_gdi_desc;
+ DISPLAYCONFIG_GET_SOURCE_DPI_SCALE get_scale_req;
+ DISPLAYCONFIG_SET_SOURCE_DPI_SCALE set_scale_req;
+ D3DKMT_CLOSEADAPTER close_adapter_desc;
+ NTSTATUS status;
+ LONG ret;
+
+#define CHECK_FUNC(func) \
+ if (!p##func) \
+ { \
+ skip("%s() is unavailable.\n", #func); \
+ return; \
+ }
+
+ CHECK_FUNC(D3DKMTCloseAdapter)
+ CHECK_FUNC(D3DKMTOpenAdapterFromGdiDisplayName)
+ CHECK_FUNC(DisplayConfigGetDeviceInfo)
+ CHECK_FUNC(DisplayConfigSetDeviceInfo)
+ CHECK_FUNC(GetDpiForMonitorInternal)
+ CHECK_FUNC(SetThreadDpiAwarenessContext)
+
+#undef CHECK_FUNC
+
+ lstrcpyW(open_adapter_gdi_desc.DeviceName, L"\\\\.\\DISPLAY1");
+ status = pD3DKMTOpenAdapterFromGdiDisplayName(&open_adapter_gdi_desc);
+ ok(status == STATUS_SUCCESS, "D3DKMTOpenAdapterFromGdiDisplayName failed, status %#x.\n", status);
+
+ get_scale_req.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_DPI_SCALE;
+ get_scale_req.header.size = sizeof(get_scale_req);
+ get_scale_req.header.adapterId = open_adapter_gdi_desc.AdapterLuid;
+ get_scale_req.header.id = open_adapter_gdi_desc.VidPnSourceId;
+ ret = pDisplayConfigGetDeviceInfo(&get_scale_req.header);
+ if (ret != NO_ERROR)
+ {
+ skip("DisplayConfigGetDeviceInfo failed, returned %d.\n", ret);
+ goto failed;
+ }
+
+ dpi = get_primary_dpi();
+ old_dpi = dpi;
+ current_scale = dpi * 100 / 96;
+ for (current_scale_idx = 0; current_scale_idx < ARRAY_SIZE(scales); ++current_scale_idx)
+ {
+ if (scales[current_scale_idx] == current_scale)
+ break;
+ }
+ ok(scales[current_scale_idx] == current_scale, "Failed to find current scale.\n");
+ recommended_scale_idx = current_scale_idx - get_scale_req.curRelativeScaleStep;
+
+ set_scale_req.header.type = DISPLAYCONFIG_DEVICE_INFO_SET_SOURCE_DPI_SCALE;
+ set_scale_req.header.size = sizeof(set_scale_req);
+ set_scale_req.header.adapterId = open_adapter_gdi_desc.AdapterLuid;
+ set_scale_req.header.id = open_adapter_gdi_desc.VidPnSourceId;
+ for (step = get_scale_req.minRelativeScaleStep; step <= get_scale_req.maxRelativeScaleStep; ++step)
+ {
+ set_scale_req.relativeScaleStep = step;
+ ret = pDisplayConfigSetDeviceInfo(&set_scale_req.header);
+ ok(ret == NO_ERROR, "DisplayConfigSetDeviceInfo failed, returned %d.\n", ret);
+
+ dpi = scales[step + recommended_scale_idx] * 96 / 100;
+ ok(dpi == get_primary_dpi(), "Expected %d, got %d.\n", get_primary_dpi(), dpi);
+ }
+
+ /* Restore to the original scale */
+ set_scale_req.relativeScaleStep = get_scale_req.curRelativeScaleStep;
+ ret = pDisplayConfigSetDeviceInfo(&set_scale_req.header);
+ ok(ret == NO_ERROR, "DisplayConfigSetDeviceInfo failed, returned %d.\n", ret);
+ ok(old_dpi == get_primary_dpi(), "Expected %d, got %d.\n", get_primary_dpi(), old_dpi);
+
+failed:
+ close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter;
+ status = pD3DKMTCloseAdapter(&close_adapter_desc);
+ ok(status == STATUS_SUCCESS, "Got unexpected return code %#x.\n", status);
+}
+
static BOOL CALLBACK test_handle_proc(HMONITOR full_monitor, HDC hdc, LPRECT rect, LPARAM lparam)
{
MONITORINFO monitor_info = {sizeof(monitor_info)};
@@ -2283,6 +2394,7 @@ START_TEST(monitor)
init_function_pointers();
test_enumdisplaydevices();
test_ChangeDisplaySettingsEx();
+ test_DisplayConfigSetDeviceInfo();
test_EnumDisplayMonitors();
test_monitors();
test_work_area();
diff --git a/include/wingdi.h b/include/wingdi.h
index c10d7518337..7220aff089b 100644
--- a/include/wingdi.h
+++ b/include/wingdi.h
@@ -3286,18 +3286,20 @@ typedef struct _RGNDATA {
typedef BOOL (CALLBACK *ABORTPROC)(HDC, INT);
typedef enum {
- DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
- DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
- DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
- DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
- DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
- DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
- DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
- DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
- DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9,
- DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10,
- DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11,
- DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xffffffff
+ DISPLAYCONFIG_DEVICE_INFO_SET_SOURCE_DPI_SCALE = (int)-4,
+ DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_DPI_SCALE = (int)-3,
+ DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = (int)1,
+ DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = (int)2,
+ DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = (int)3,
+ DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = (int)4,
+ DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = (int)5,
+ DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = (int)6,
+ DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = (int)7,
+ DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = (int)8,
+ DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = (int)9,
+ DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = (int)10,
+ DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = (int)11,
+ DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = (int)0xffffffff
} DISPLAYCONFIG_DEVICE_INFO_TYPE;
typedef struct DISPLAYCONFIG_DEVICE_INFO_HEADER {
@@ -3638,6 +3640,31 @@ typedef struct DISPLAYCONFIG_SDR_WHITE_LEVEL {
ULONG SDRWhiteLevel;
} DISPLAYCONFIG_SDR_WHITE_LEVEL;
+/* Scale steps are relative to the recommended scale. For example:
+ * Scale : 100% 125% 150% 175% 200% 225% 250% 300% 350% 400% 450% 500%
+ * DPI : 96 120 144 168 192 216 240 288 336 384 432 480
+ * ^ ^ ^ ^
+ * | | Recommended scale, step is 0. |
+ * | Current scale, step is -2. Max scale step is 6.
+ * Minimum scale, step is -4.
+ *
+ * The scale values can be found in the display settings drop-down. The algorithm to calculate the
+ * recommended scale is unclear.
+ */
+typedef struct DISPLAYCONFIG_GET_SOURCE_DPI_SCALE
+{
+ DISPLAYCONFIG_DEVICE_INFO_HEADER header;
+ int minRelativeScaleStep; /* Minimum scale step relative to the recommended scale */
+ int curRelativeScaleStep; /* Current scale step relative to the recommended scale */
+ int maxRelativeScaleStep; /* Maximum scale step relative to the recommended scale */
+} DISPLAYCONFIG_GET_SOURCE_DPI_SCALE;
+
+typedef struct DISPLAYCONFIG_SET_SOURCE_DPI_SCALE
+{
+ DISPLAYCONFIG_DEVICE_INFO_HEADER header;
+ int relativeScaleStep; /* Target scale step relative to the recommended scale */
+} DISPLAYCONFIG_SET_SOURCE_DPI_SCALE;
+
#define DISPLAYCONFIG_PATH_MODE_IDX_INVALID 0xffffffff
#define DISPLAYCONFIG_PATH_TARGET_MODE_IDX_INVALID 0xffff
#define DISPLAYCONFIG_PATH_DESKTOP_IMAGE_IDX_INVALID 0xffff
--
2.30.2
More information about the wine-devel
mailing list