libdisplaydevice master
C++ library to modify display devices.
display_device::WinApiLayer Class Reference

Default implementation for the WinApiLayerInterface. More...

#include <src/windows/include/display_device/windows/win_api_layer.h>

Inheritance diagram for display_device::WinApiLayer:
[legend]
Collaboration diagram for display_device::WinApiLayer:
[legend]

Public Member Functions

std::string getDeviceId (const DISPLAYCONFIG_PATH_INFO &path) const override
 Get a stable and persistent device id for the path.
 
std::string getDisplayName (const DISPLAYCONFIG_PATH_INFO &path) const override
 Get the logical display name for the path.
 
std::optional< RationalgetDisplayScale (std::string_view display_name, const DISPLAYCONFIG_SOURCE_MODE &source_mode) const override
 Get the scaling value for the display.
 
std::vector< std::byte > getEdid (const DISPLAYCONFIG_PATH_INFO &path) const override
 Get EDID byte array for the path.
 
std::string getErrorString (LONG error_code) const override
 Stringify the error code from Windows API.
 
std::string getFriendlyName (const DISPLAYCONFIG_PATH_INFO &path) const override
 Get the user-friendly name for the path.
 
std::optional< HdrStategetHdrState (const DISPLAYCONFIG_PATH_INFO &path) const override
 Get the HDR state the path.
 
std::string getMonitorDevicePath (const DISPLAYCONFIG_PATH_INFO &path) const override
 Get a string that represents a path from the adapter to the display target.
 
bool keepDisplayAwake () override
 Request that Windows keep the current thread's display awake.
 
std::optional< PathAndModeDataqueryDisplayConfig (QueryType type) const override
 Query Windows for the device paths and associated modes.
 
bool restorePowerRequest () override
 Clear the current thread's display keep-awake request.
 
LONG setDisplayConfig (std::vector< DISPLAYCONFIG_PATH_INFO > paths, std::vector< DISPLAYCONFIG_MODE_INFO > modes, UINT32 flags) override
 Direct wrapper around the SetDisplayConfig WinAPI.
 
bool setHdrState (const DISPLAYCONFIG_PATH_INFO &path, HdrState state) override
 Set the HDR state for the path.
 
bool wakeDisplay (std::chrono::milliseconds timeout) override
 Ask Windows to wake the display and wait before retrying detection.
 
- Public Member Functions inherited from display_device::WinApiLayerInterface
virtual ~WinApiLayerInterface ()=default
 Default virtual destructor.
 

Detailed Description

Default implementation for the WinApiLayerInterface.

Member Function Documentation

◆ getDeviceId()

std::string display_device::WinApiLayer::getDeviceId ( const DISPLAYCONFIG_PATH_INFO & path) const
nodiscardoverridevirtual

Get a stable and persistent device id for the path.

This function tries to generate a unique id for the path that is persistent between driver re-installs and physical unplugging and replugging of the device.

The best candidate for it could have been a "ContainerID" from the registry, however it was found to be unstable for the virtual display (probably because it uses the EDID for the id generation and the current virtual displays have incomplete EDID information). The "ContainerID" also does not change if the physical device is plugged into a different port (which does not satisfy the "device id for the path" part) and is unstable for virtual displays, therefore other solution was used.

The accepted solution was to use the "InstanceID" and EDID (just to be on the safe side). "InstanceID" is semi-stable, it has some parts that change between driver re-installs, and it has a part that changes based on the GPU port that the display is connected to. It is most likely to be unique, but since the MS documentation is lacking we are also hashing EDID information (contains serial ids, timestamps, etc. that should guarantee that identical displays are differentiated like with the "ContainerID"). Most importantly this information is stable for the virtual displays.

After we remove the unstable parts from the "InstanceID" and hash everything together, we get an id that changes only when you connect the display to a different GPU port which seems to be acceptable.

As a fallback we are using a hashed device path, in case the "InstanceID" or EDID is not available. At least if you don't do driver re-installs often and change the GPU ports, it will be stable for a while.

Parameters
pathPath to get the device id for.
Returns
Device id, or an empty string if it could not be generated.
See also
queryDisplayConfig on how to get paths from the system.

*Examples**

DISPLAYCONFIG_PATH_INFO path;
const WinApiLayerInterface* iface = getIface(...);
const std::string device_path = iface->getDeviceId(path);
Lowest level Windows API wrapper for easy mocking.
Definition win_api_layer_interface.h:17
virtual std::string getDeviceId(const DISPLAYCONFIG_PATH_INFO &path) const =0
Get a stable and persistent device id for the path.

Implements display_device::WinApiLayerInterface.

◆ getDisplayName()

std::string display_device::WinApiLayer::getDisplayName ( const DISPLAYCONFIG_PATH_INFO & path) const
nodiscardoverridevirtual

Get the logical display name for the path.

These are the "\\\\.\\DISPLAY1", "\\\\.\\DISPLAY2" and etc. display names that can change whenever Windows wants to change them.

Parameters
pathPath to get user display name for.
Returns
Display name for the path if available, empty string otherwise.
See also
queryDisplayConfig on how to get paths from the system.
Note
Inactive paths can have these names already assigned to them, even though they are not even in use! There can also be duplicates.

*Examples**

DISPLAYCONFIG_PATH_INFO path;
const WinApiLayerInterface* iface = getIface(...);
const std::string display_name = iface->getDisplayName(path);
virtual std::string getDisplayName(const DISPLAYCONFIG_PATH_INFO &path) const =0
Get the logical display name for the path.

Implements display_device::WinApiLayerInterface.

◆ getDisplayScale()

std::optional< Rational > display_device::WinApiLayer::getDisplayScale ( std::string_view display_name,
const DISPLAYCONFIG_SOURCE_MODE & source_mode ) const
nodiscardoverridevirtual

Get the scaling value for the display.

Parameters
display_nameDisplay to get the scaling for.
source_modeSource mode to get the scaling for.
Returns
Current display scale value or null optional in case of error or if the value could not be retrieved.

*Examples**

DISPLAYCONFIG_PATH_INFO path;
DISPLAYCONFIG_SOURCE_MODE source_mode;
const WinApiLayerInterface* iface = getIface(...);
const auto scale = iface->getDisplayScale(iface->getDisplayName(path), source_mode);
virtual std::optional< Rational > getDisplayScale(std::string_view display_name, const DISPLAYCONFIG_SOURCE_MODE &source_mode) const =0
Get the scaling value for the display.

Implements display_device::WinApiLayerInterface.

◆ getEdid()

std::vector< std::byte > display_device::WinApiLayer::getEdid ( const DISPLAYCONFIG_PATH_INFO & path) const
nodiscardoverridevirtual

Get EDID byte array for the path.

Parameters
pathPath to get the EDID for.
Returns
EDID byte array, or an empty array if error has occurred.

Implements display_device::WinApiLayerInterface.

◆ getErrorString()

std::string display_device::WinApiLayer::getErrorString ( LONG error_code) const
nodiscardoverridevirtual

Stringify the error code from Windows API.

Parameters
error_codeError code to stringify.
Returns
String containing the error code in a readable format + a system message describing the code.

*Examples**

const WinApiLayerInterface* iface = getIface(...);
const std::string error_message = iface->getErrorString(ERROR_NOT_SUPPORTED);
virtual std::string getErrorString(LONG error_code) const =0
Stringify the error code from Windows API.

Implements display_device::WinApiLayerInterface.

◆ getFriendlyName()

std::string display_device::WinApiLayer::getFriendlyName ( const DISPLAYCONFIG_PATH_INFO & path) const
nodiscardoverridevirtual

Get the user-friendly name for the path.

Parameters
pathPath to get user-friendly name for.
Returns
User-friendly name for the path if available, empty string otherwise.
See also
queryDisplayConfig on how to get paths from the system.
Note
This is usually a monitor name (like "ROG PG279Q") and is most likely taken from EDID.

*Examples**

DISPLAYCONFIG_PATH_INFO path;
const WinApiLayerInterface* iface = getIface(...);
const std::string friendly_name = iface->getFriendlyName(path);
virtual std::string getFriendlyName(const DISPLAYCONFIG_PATH_INFO &path) const =0
Get the user-friendly name for the path.

Implements display_device::WinApiLayerInterface.

◆ getHdrState()

std::optional< HdrState > display_device::WinApiLayer::getHdrState ( const DISPLAYCONFIG_PATH_INFO & path) const
nodiscardoverridevirtual

Get the HDR state the path.

Parameters
pathPath to get HDR state for.
Returns
std::nullopt if the state could not be retrieved, or other enum values describing the state otherwise.

*Examples**

DISPLAYCONFIG_PATH_INFO path;
const WinApiLayerInterface* iface = getIface(...);
const auto hdr_state = iface->getHdrState(path);
virtual std::optional< HdrState > getHdrState(const DISPLAYCONFIG_PATH_INFO &path) const =0
Get the HDR state the path.

Implements display_device::WinApiLayerInterface.

◆ getMonitorDevicePath()

std::string display_device::WinApiLayer::getMonitorDevicePath ( const DISPLAYCONFIG_PATH_INFO & path) const
nodiscardoverridevirtual

Get a string that represents a path from the adapter to the display target.

Parameters
pathPath to get the string for.
Returns
String representation, or an empty string if it's not available.
See also
queryDisplayConfig on how to get paths from the system.
Note
In the rest of the code we refer to this string representation simply as the "device path". It is used as a simple way of grouping related path objects together and removing "bad" paths that don't have such string representation.

*Examples**

DISPLAYCONFIG_PATH_INFO path;
const WinApiLayerInterface* iface = getIface(...);
const std::string device_path = iface->getMonitorDevicePath(path);
virtual std::string getMonitorDevicePath(const DISPLAYCONFIG_PATH_INFO &path) const =0
Get a string that represents a path from the adapter to the display target.

Implements display_device::WinApiLayerInterface.

◆ keepDisplayAwake()

bool display_device::WinApiLayer::keepDisplayAwake ( )
nodiscardoverridevirtual

Request that Windows keep the current thread's display awake.

Returns
True if Windows accepted the keep-awake request, false otherwise.

Implements display_device::WinApiLayerInterface.

◆ queryDisplayConfig()

std::optional< PathAndModeData > display_device::WinApiLayer::queryDisplayConfig ( QueryType type) const
nodiscardoverridevirtual

Query Windows for the device paths and associated modes.

Parameters
typeSpecify device type to query for.
Returns
Data containing paths and modes, empty optional if we have failed to query.

*Examples**

const WinApiLayerInterface* iface = getIface(...);
const auto display_data = iface->queryDisplayConfig(QueryType::Active);
virtual std::optional< PathAndModeData > queryDisplayConfig(QueryType type) const =0
Query Windows for the device paths and associated modes.

Implements display_device::WinApiLayerInterface.

◆ restorePowerRequest()

bool display_device::WinApiLayer::restorePowerRequest ( )
nodiscardoverridevirtual

Clear the current thread's display keep-awake request.

Returns
True if Windows accepted the restore request, false otherwise.

Implements display_device::WinApiLayerInterface.

◆ setDisplayConfig()

LONG display_device::WinApiLayer::setDisplayConfig ( std::vector< DISPLAYCONFIG_PATH_INFO > paths,
std::vector< DISPLAYCONFIG_MODE_INFO > modes,
UINT32 flags )
nodiscardoverridevirtual

Direct wrapper around the SetDisplayConfig WinAPI.

It implements no additional logic, just a direct pass-trough.

Parameters
pathsList of paths to pass.
modesList of modes to pass.
flagsFlags to pass.
Returns
The return error code of the API.

*Examples**

std::vector<DISPLAYCONFIG_PATH_INFO> paths;
WinApiLayerInterface* iface = getIface(...);
const auto result = iface->setDisplayConfig(paths, {}, 0);
virtual LONG setDisplayConfig(std::vector< DISPLAYCONFIG_PATH_INFO > paths, std::vector< DISPLAYCONFIG_MODE_INFO > modes, UINT32 flags)=0
Direct wrapper around the SetDisplayConfig WinAPI.

Implements display_device::WinApiLayerInterface.

◆ setHdrState()

bool display_device::WinApiLayer::setHdrState ( const DISPLAYCONFIG_PATH_INFO & path,
HdrState state )
nodiscardoverridevirtual

Set the HDR state for the path.

Parameters
pathPath to set HDR state for.
stateSpecify new HDR state.
Returns
True if the device is in the new state, false otherwise.

*Examples**

DISPLAYCONFIG_PATH_INFO path;
WinApiLayerInterface* iface = getIface(...);
const bool success = iface->setHdrState(path, HdrState::Enabled);
virtual bool setHdrState(const DISPLAYCONFIG_PATH_INFO &path, HdrState state)=0
Set the HDR state for the path.

Implements display_device::WinApiLayerInterface.

◆ wakeDisplay()

bool display_device::WinApiLayer::wakeDisplay ( std::chrono::milliseconds timeout)
nodiscardoverridevirtual

Ask Windows to wake the display and wait before retrying detection.

Windows accepts a display-required execution-state request, but this low-level call does not prove that a specific output is active afterward.

Parameters
timeoutMaximum time to wait after issuing the wake request.
Returns
True if Windows accepted the wake request, false otherwise.

Implements display_device::WinApiLayerInterface.


The documentation for this class was generated from the following files: