Test that DisplayConfigSetDeviceInfo() can be used for getting and setting display DPI.
Signed-off-by: Zhiyi Zhang zzhang@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