user32: Implement QueryDisplayConfig().
Signed-off-by: Brendan Shanks <bshanks@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
2e1c48f351
commit
5fba152eea
|
@ -40,6 +40,7 @@
|
|||
#include "winerror.h"
|
||||
|
||||
#include "initguid.h"
|
||||
#include "d3dkmdt.h"
|
||||
#include "devguid.h"
|
||||
#include "setupapi.h"
|
||||
#include "controls.h"
|
||||
|
@ -249,6 +250,10 @@ static const WCHAR CSu[] = {'%','u',0};
|
|||
static const WCHAR CSd[] = {'%','d',0};
|
||||
static const WCHAR CSrgb[] = {'%','u',' ','%','u',' ','%','u',0};
|
||||
|
||||
DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2);
|
||||
DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_GPU_LUID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 1);
|
||||
DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_OUTPUT_ID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 2);
|
||||
|
||||
/* Wine specific monitor properties */
|
||||
DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_STATEFLAGS, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2);
|
||||
DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCMONITOR, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 3);
|
||||
|
@ -4556,6 +4561,129 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static DISPLAYCONFIG_ROTATION get_dc_rotation(const DEVMODEW *devmode)
|
||||
{
|
||||
if (devmode->dmFields & DM_DISPLAYORIENTATION)
|
||||
return devmode->u1.s2.dmDisplayOrientation + 1;
|
||||
else
|
||||
return DISPLAYCONFIG_ROTATION_IDENTITY;
|
||||
}
|
||||
|
||||
static DISPLAYCONFIG_SCANLINE_ORDERING get_dc_scanline_ordering(const DEVMODEW *devmode)
|
||||
{
|
||||
if (!(devmode->dmFields & DM_DISPLAYFLAGS))
|
||||
return DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED;
|
||||
else if (devmode->u2.dmDisplayFlags & DM_INTERLACED)
|
||||
return DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED;
|
||||
else
|
||||
return DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;
|
||||
}
|
||||
|
||||
static DISPLAYCONFIG_PIXELFORMAT get_dc_pixelformat(DWORD dmBitsPerPel)
|
||||
{
|
||||
if ((dmBitsPerPel == 8) || (dmBitsPerPel == 16) ||
|
||||
(dmBitsPerPel == 24) || (dmBitsPerPel == 32))
|
||||
return dmBitsPerPel / 8;
|
||||
else
|
||||
return DISPLAYCONFIG_PIXELFORMAT_NONGDI;
|
||||
}
|
||||
|
||||
static void set_mode_target_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid, UINT32 target_id,
|
||||
UINT32 flags, const DEVMODEW *devmode)
|
||||
{
|
||||
DISPLAYCONFIG_TARGET_MODE *mode = &(info->u.targetMode);
|
||||
|
||||
info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_TARGET;
|
||||
info->adapterId = *gpu_luid;
|
||||
info->id = target_id;
|
||||
|
||||
/* FIXME: Populate pixelRate/hSyncFreq/totalSize with real data */
|
||||
mode->targetVideoSignalInfo.pixelRate = devmode->dmDisplayFrequency * devmode->dmPelsWidth * devmode->dmPelsHeight;
|
||||
mode->targetVideoSignalInfo.hSyncFreq.Numerator = devmode->dmDisplayFrequency * devmode->dmPelsWidth;
|
||||
mode->targetVideoSignalInfo.hSyncFreq.Denominator = 1;
|
||||
mode->targetVideoSignalInfo.vSyncFreq.Numerator = devmode->dmDisplayFrequency;
|
||||
mode->targetVideoSignalInfo.vSyncFreq.Denominator = 1;
|
||||
mode->targetVideoSignalInfo.activeSize.cx = devmode->dmPelsWidth;
|
||||
mode->targetVideoSignalInfo.activeSize.cy = devmode->dmPelsHeight;
|
||||
if (flags & QDC_DATABASE_CURRENT)
|
||||
{
|
||||
mode->targetVideoSignalInfo.totalSize.cx = 0;
|
||||
mode->targetVideoSignalInfo.totalSize.cy = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mode->targetVideoSignalInfo.totalSize.cx = devmode->dmPelsWidth;
|
||||
mode->targetVideoSignalInfo.totalSize.cy = devmode->dmPelsHeight;
|
||||
}
|
||||
mode->targetVideoSignalInfo.u.videoStandard = D3DKMDT_VSS_OTHER;
|
||||
mode->targetVideoSignalInfo.scanLineOrdering = get_dc_scanline_ordering(devmode);
|
||||
}
|
||||
|
||||
static void set_path_target_info(DISPLAYCONFIG_PATH_TARGET_INFO *info, const LUID *gpu_luid,
|
||||
UINT32 target_id, UINT32 mode_index, const DEVMODEW *devmode)
|
||||
{
|
||||
info->adapterId = *gpu_luid;
|
||||
info->id = target_id;
|
||||
info->u.modeInfoIdx = mode_index;
|
||||
info->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL;
|
||||
info->rotation = get_dc_rotation(devmode);
|
||||
info->scaling = DISPLAYCONFIG_SCALING_IDENTITY;
|
||||
info->refreshRate.Numerator = devmode->dmDisplayFrequency;
|
||||
info->refreshRate.Denominator = 1;
|
||||
info->scanLineOrdering = get_dc_scanline_ordering(devmode);
|
||||
info->targetAvailable = TRUE;
|
||||
info->statusFlags = DISPLAYCONFIG_TARGET_IN_USE;
|
||||
}
|
||||
|
||||
static void set_mode_source_info(DISPLAYCONFIG_MODE_INFO *info, const LUID *gpu_luid,
|
||||
UINT32 source_id, const DEVMODEW *devmode)
|
||||
{
|
||||
DISPLAYCONFIG_SOURCE_MODE *mode = &(info->u.sourceMode);
|
||||
|
||||
info->infoType = DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE;
|
||||
info->adapterId = *gpu_luid;
|
||||
info->id = source_id;
|
||||
|
||||
mode->width = devmode->dmPelsWidth;
|
||||
mode->height = devmode->dmPelsHeight;
|
||||
mode->pixelFormat = get_dc_pixelformat(devmode->dmBitsPerPel);
|
||||
if (devmode->dmFields & DM_POSITION)
|
||||
{
|
||||
mode->position = devmode->u1.s2.dmPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
mode->position.x = 0;
|
||||
mode->position.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_path_source_info(DISPLAYCONFIG_PATH_SOURCE_INFO *info, const LUID *gpu_luid,
|
||||
UINT32 source_id, UINT32 mode_index)
|
||||
{
|
||||
info->adapterId = *gpu_luid;
|
||||
info->id = source_id;
|
||||
info->u.modeInfoIdx = mode_index;
|
||||
info->statusFlags = DISPLAYCONFIG_SOURCE_IN_USE;
|
||||
}
|
||||
|
||||
static BOOL source_mode_exists(const DISPLAYCONFIG_MODE_INFO *modeinfo, UINT32 num_modes,
|
||||
UINT32 source_id, UINT32 *found_mode_index)
|
||||
{
|
||||
UINT32 i;
|
||||
|
||||
for (i = 0; i < num_modes; i++)
|
||||
{
|
||||
if (modeinfo[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE &&
|
||||
modeinfo[i].id == source_id)
|
||||
{
|
||||
*found_mode_index = i;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* QueryDisplayConfig (USER32.@)
|
||||
*/
|
||||
|
@ -4563,7 +4691,17 @@ LONG WINAPI QueryDisplayConfig(UINT32 flags, UINT32 *numpathelements, DISPLAYCON
|
|||
UINT32 *numinfoelements, DISPLAYCONFIG_MODE_INFO *modeinfo,
|
||||
DISPLAYCONFIG_TOPOLOGY_ID *topologyid)
|
||||
{
|
||||
FIXME("(%08x %p %p %p %p %p)\n", flags, numpathelements, pathinfo, numinfoelements, modeinfo, topologyid);
|
||||
LONG adapter_index, ret;
|
||||
HANDLE mutex;
|
||||
HDEVINFO devinfo;
|
||||
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
|
||||
DWORD monitor_index = 0, state_flags, type;
|
||||
UINT32 output_id, source_mode_index, path_index = 0, mode_index = 0;
|
||||
LUID gpu_luid;
|
||||
WCHAR device_name[CCHDEVICENAME];
|
||||
DEVMODEW devmode;
|
||||
|
||||
FIXME("(%08x %p %p %p %p %p): semi-stub\n", flags, numpathelements, pathinfo, numinfoelements, modeinfo, topologyid);
|
||||
|
||||
if (!numpathelements || !numinfoelements)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
@ -4571,10 +4709,105 @@ LONG WINAPI QueryDisplayConfig(UINT32 flags, UINT32 *numpathelements, DISPLAYCON
|
|||
if (!*numpathelements || !*numinfoelements)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (!flags)
|
||||
if (flags != QDC_ALL_PATHS &&
|
||||
flags != QDC_ONLY_ACTIVE_PATHS &&
|
||||
flags != QDC_DATABASE_CURRENT)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
if (((flags == QDC_DATABASE_CURRENT) && !topologyid) ||
|
||||
((flags != QDC_DATABASE_CURRENT) && topologyid))
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (flags != QDC_ONLY_ACTIVE_PATHS)
|
||||
FIXME("only returning active paths\n");
|
||||
|
||||
if (topologyid)
|
||||
{
|
||||
FIXME("setting toplogyid to DISPLAYCONFIG_TOPOLOGY_INTERNAL\n");
|
||||
*topologyid = DISPLAYCONFIG_TOPOLOGY_INTERNAL;
|
||||
}
|
||||
|
||||
wait_graphics_driver_ready();
|
||||
mutex = get_display_device_init_mutex();
|
||||
|
||||
/* Iterate through "targets"/monitors.
|
||||
* Each target corresponds to a path, and each path corresponds to one or two unique modes.
|
||||
*/
|
||||
devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, DISPLAY, NULL, DIGCF_PRESENT);
|
||||
if (devinfo == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ret = ERROR_GEN_FAILURE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = ERROR_GEN_FAILURE;
|
||||
while (SetupDiEnumDeviceInfo(devinfo, monitor_index++, &device_data))
|
||||
{
|
||||
/* Only count active monitors */
|
||||
if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS,
|
||||
&type, (BYTE *)&state_flags, sizeof(state_flags), NULL, 0))
|
||||
goto done;
|
||||
if (!(state_flags & DISPLAY_DEVICE_ACTIVE))
|
||||
continue;
|
||||
|
||||
if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_GPU_LUID,
|
||||
&type, (BYTE *)&gpu_luid, sizeof(gpu_luid), NULL, 0))
|
||||
goto done;
|
||||
|
||||
if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_MONITOR_OUTPUT_ID,
|
||||
&type, (BYTE *)&output_id, sizeof(output_id), NULL, 0))
|
||||
goto done;
|
||||
|
||||
if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME,
|
||||
&type, (BYTE *)device_name, sizeof(device_name), NULL, 0))
|
||||
goto done;
|
||||
|
||||
devmode.dmSize = sizeof(devmode);
|
||||
if (!EnumDisplaySettingsW(device_name, ENUM_CURRENT_SETTINGS, &devmode))
|
||||
goto done;
|
||||
|
||||
/* Extract the adapter index from device_name to use as the source ID */
|
||||
adapter_index = strtolW(device_name + ARRAY_SIZE(ADAPTER_PREFIX), NULL, 10);
|
||||
adapter_index--;
|
||||
|
||||
if (path_index == *numpathelements || mode_index == *numinfoelements)
|
||||
{
|
||||
ret = ERROR_INSUFFICIENT_BUFFER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
pathinfo[path_index].flags = DISPLAYCONFIG_PATH_ACTIVE;
|
||||
set_mode_target_info(&modeinfo[mode_index], &gpu_luid, output_id, flags, &devmode);
|
||||
set_path_target_info(&(pathinfo[path_index].targetInfo), &gpu_luid, output_id, mode_index, &devmode);
|
||||
|
||||
mode_index++;
|
||||
if (mode_index == *numinfoelements)
|
||||
{
|
||||
ret = ERROR_INSUFFICIENT_BUFFER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Multiple targets can be driven by the same source, ensure a mode
|
||||
* hasn't already been added for this source.
|
||||
*/
|
||||
if (!source_mode_exists(modeinfo, mode_index, adapter_index, &source_mode_index))
|
||||
{
|
||||
set_mode_source_info(&modeinfo[mode_index], &gpu_luid, adapter_index, &devmode);
|
||||
source_mode_index = mode_index;
|
||||
mode_index++;
|
||||
}
|
||||
set_path_source_info(&(pathinfo[path_index].sourceInfo), &gpu_luid, adapter_index, source_mode_index);
|
||||
path_index++;
|
||||
}
|
||||
|
||||
*numpathelements = path_index;
|
||||
*numinfoelements = mode_index;
|
||||
ret = ERROR_SUCCESS;
|
||||
|
||||
done:
|
||||
SetupDiDestroyDeviceInfoList(devinfo);
|
||||
release_display_device_init_mutex(mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -1299,6 +1299,7 @@ static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PAT
|
|||
|
||||
for (i = 0; i < paths; i++)
|
||||
{
|
||||
todo_wine {
|
||||
source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
|
||||
source_name.header.size = sizeof(source_name);
|
||||
source_name.header.adapterId = pi[i].sourceInfo.adapterId;
|
||||
|
@ -1307,7 +1308,9 @@ static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PAT
|
|||
ret = pDisplayConfigGetDeviceInfo(&source_name.header);
|
||||
ok(!ret, "Expected 0, got %d\n", ret);
|
||||
ok(source_name.viewGdiDeviceName[0] != '\0', "Expected GDI device name, got empty string\n");
|
||||
}
|
||||
|
||||
todo_wine {
|
||||
target_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
|
||||
target_name.header.size = sizeof(target_name);
|
||||
target_name.header.adapterId = pi[i].targetInfo.adapterId;
|
||||
|
@ -1316,7 +1319,9 @@ static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PAT
|
|||
ret = pDisplayConfigGetDeviceInfo(&target_name.header);
|
||||
ok(!ret, "Expected 0, got %d\n", ret);
|
||||
ok(target_name.monitorDevicePath[0] != '\0', "Expected monitor device path, got empty string\n");
|
||||
}
|
||||
|
||||
todo_wine {
|
||||
preferred_mode.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE;
|
||||
preferred_mode.header.size = sizeof(preferred_mode);
|
||||
preferred_mode.header.adapterId = pi[i].targetInfo.adapterId;
|
||||
|
@ -1326,7 +1331,9 @@ static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PAT
|
|||
ok(!ret, "Expected 0, got %d\n", ret);
|
||||
ok(preferred_mode.width > 0 && preferred_mode.height > 0, "Expected non-zero height/width, got %ux%u\n",
|
||||
preferred_mode.width, preferred_mode.height);
|
||||
}
|
||||
|
||||
todo_wine {
|
||||
adapter_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME;
|
||||
adapter_name.header.size = sizeof(adapter_name);
|
||||
adapter_name.header.adapterId = pi[i].sourceInfo.adapterId;
|
||||
|
@ -1334,6 +1341,7 @@ static void test_QueryDisplayConfig_result(UINT32 paths, const DISPLAYCONFIG_PAT
|
|||
ret = pDisplayConfigGetDeviceInfo(&adapter_name.header);
|
||||
ok(!ret, "Expected 0, got %d\n", ret);
|
||||
ok(adapter_name.adapterDevicePath[0] != '\0', "Expected adapter device path, got empty string\n");
|
||||
}
|
||||
|
||||
/* Check corresponding modes */
|
||||
if (pi[i].sourceInfo.modeInfoIdx == DISPLAYCONFIG_PATH_MODE_IDX_INVALID)
|
||||
|
|
Loading…
Reference in New Issue