diff --git a/src/common/include/displaydevice/types.h b/src/common/include/displaydevice/types.h index f7bdd86..90c50fd 100644 --- a/src/common/include/displaydevice/types.h +++ b/src/common/include/displaydevice/types.h @@ -13,15 +13,42 @@ namespace display_device { * @brief Display's resolution. */ struct Resolution { - unsigned int m_width; - unsigned int m_height; + unsigned int m_width {}; + unsigned int m_height {}; }; /** - * @brief Floating point stored in a "numerator/denominator" form. + * @brief An arbitrary point object. */ - struct Rational { - unsigned int m_numerator; - unsigned int m_denominator; + struct Point { + int m_x {}; + int m_y {}; }; + + /** + * @brief Enumerated display device information. + */ + struct EnumeratedDevice { + /** + * @brief Available information for the active display only. + */ + struct Info { + Resolution m_resolution {}; /**< Resolution of an active device. */ + float m_resolution_scale {}; /**< Resolution scaling of an active device. */ + float m_refresh_rate {}; /**< Refresh rate of an active device. */ + bool m_primary {}; /**< Indicates whether the device is a primary display. */ + Point m_origin_point {}; /**< A starting point of the display. */ + std::optional m_hdr_state {}; /**< HDR of an active device. */ + }; + + std::string m_device_id {}; /**< A unique device ID used by this API to identify the device. */ + std::string m_display_name {}; /**< A logical name representing given by the OS for a display. */ + std::string m_friendly_name {}; /**< A human-readable name for the device. */ + std::optional m_info {}; /**< Additional information about an active display device. */ + }; + + /** + * @brief A list of EnumeratedDevice objects. + */ + using EnumeratedDeviceList = std::vector; } // namespace display_device diff --git a/src/windows/CMakeLists.txt b/src/windows/CMakeLists.txt index 98ea0b9..d85abc7 100644 --- a/src/windows/CMakeLists.txt +++ b/src/windows/CMakeLists.txt @@ -11,6 +11,12 @@ add_library(${MODULE} ${HEADER_LIST} ${SOURCE_LIST}) # Provide the includes together with this library target_include_directories(${MODULE} PUBLIC include) +# Library requires newer WinAPI, therefore it is set to the Windows 10+ version +target_compile_definitions(${MODULE} PRIVATE + _WIN32_WINNT=0x0A00 + WINVER=0x0A00 +) + # Additional external libraries include(Boost_DD) diff --git a/src/windows/include/displaydevice/windows/types.h b/src/windows/include/displaydevice/windows/types.h index 6bb376e..2b53e3e 100644 --- a/src/windows/include/displaydevice/windows/types.h +++ b/src/windows/include/displaydevice/windows/types.h @@ -25,8 +25,8 @@ namespace display_device { * @brief Contains currently available paths and associated modes. */ struct PathAndModeData { - std::vector m_paths; /**< Available display paths. */ - std::vector m_modes; /**< Display modes for ACTIVE displays. */ + std::vector m_paths {}; /**< Available display paths. */ + std::vector m_modes {}; /**< Display modes for ACTIVE displays. */ }; /** @@ -43,17 +43,17 @@ namespace display_device { * @see WinApiLayerInterface::getDeviceId for how we make the device id. */ struct ValidatedDeviceInfo { - std::string m_device_path; /**< Unique device path string. */ - std::string m_device_id; /**< A device id (made up by us) that is identifies the device. */ + std::string m_device_path {}; /**< Unique device path string. */ + std::string m_device_id {}; /**< A device id (made up by us) that is identifies the device. */ }; /** * @brief Contains information about sources with identical adapter ids from matching paths. */ struct PathSourceIndexData { - std::map m_source_id_to_path_index; /**< Maps source ids to its index in the path list. */ + std::map m_source_id_to_path_index {}; /**< Maps source ids to its index in the path list. */ LUID m_adapter_id {}; /**< Adapter id shared by all source ids. */ - std::optional m_active_source; /**< Currently active source id. */ + std::optional m_active_source {}; /**< Currently active source id. */ }; /** @@ -78,12 +78,20 @@ namespace display_device { */ using ActiveTopology = std::vector>; + /** + * @brief Floating point stored in a "numerator/denominator" form. + */ + struct Rational { + unsigned int m_numerator {}; + unsigned int m_denominator {}; + }; + /** * @brief Display's mode (resolution + refresh rate). */ struct DisplayMode { - Resolution m_resolution; - Rational m_refresh_rate; + Resolution m_resolution {}; + Rational m_refresh_rate {}; }; /** diff --git a/src/windows/include/displaydevice/windows/winapilayer.h b/src/windows/include/displaydevice/windows/winapilayer.h index 58e9b10..ae3b9be 100644 --- a/src/windows/include/displaydevice/windows/winapilayer.h +++ b/src/windows/include/displaydevice/windows/winapilayer.h @@ -44,5 +44,9 @@ namespace display_device { /** For details @see WinApiLayerInterface::setHdrState */ [[nodiscard]] bool setHdrState(const DISPLAYCONFIG_PATH_INFO &path, HdrState state) override; + + /** For details @see WinApiLayerInterface::getDisplayScale */ + [[nodiscard]] std::optional + getDisplayScale(const std::string &display_name, const DISPLAYCONFIG_SOURCE_MODE &source_mode) const override; }; } // namespace display_device diff --git a/src/windows/include/displaydevice/windows/winapilayerinterface.h b/src/windows/include/displaydevice/windows/winapilayerinterface.h index a40fe0f..797ace5 100644 --- a/src/windows/include/displaydevice/windows/winapilayerinterface.h +++ b/src/windows/include/displaydevice/windows/winapilayerinterface.h @@ -197,5 +197,22 @@ namespace display_device { */ [[nodiscard]] virtual bool setHdrState(const DISPLAYCONFIG_PATH_INFO &path, HdrState state) = 0; + + /** + * @brief Get the scaling value for the display. + * @param display_name Display 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: + * ```cpp + * DISPLAYCONFIG_PATH_INFO path; + * DISPLAYCONFIG_SOURCE_MODE source_mode; + * const WinApiLayerInterface* iface = getIface(...); + * const auto scale = iface->getDisplayScale(iface->getDisplayName(path), source_mode); + * ``` + */ + [[nodiscard]] virtual std::optional + getDisplayScale(const std::string &display_name, const DISPLAYCONFIG_SOURCE_MODE &source_mode) const = 0; }; } // namespace display_device diff --git a/src/windows/include/displaydevice/windows/windisplaydevice.h b/src/windows/include/displaydevice/windows/windisplaydevice.h index dd2a034..88b15ac 100644 --- a/src/windows/include/displaydevice/windows/windisplaydevice.h +++ b/src/windows/include/displaydevice/windows/windisplaydevice.h @@ -23,6 +23,10 @@ namespace display_device { [[nodiscard]] bool isApiAccessAvailable() const override; + /** For details @see WinDisplayDeviceInterface::enumAvailableDevices */ + [[nodiscard]] EnumeratedDeviceList + enumAvailableDevices() const override; + /** For details @see WinDisplayDeviceInterface::getDisplayName */ [[nodiscard]] std::string getDisplayName(const std::string &device_id) const override; diff --git a/src/windows/include/displaydevice/windows/windisplaydeviceinterface.h b/src/windows/include/displaydevice/windows/windisplaydeviceinterface.h index eb4a3fe..959fdbb 100644 --- a/src/windows/include/displaydevice/windows/windisplaydeviceinterface.h +++ b/src/windows/include/displaydevice/windows/windisplaydeviceinterface.h @@ -30,6 +30,19 @@ namespace display_device { [[nodiscard]] virtual bool isApiAccessAvailable() const = 0; + /** + * @brief Enumerate the available (active and inactive) devices. + * @returns A list of available devices. + * Empty list can also be returned if an error has occurred. + * + * EXAMPLES: + * ```cpp + * const auto devices { enumAvailableDevices() }; + * ``` + */ + [[nodiscard]] virtual EnumeratedDeviceList + enumAvailableDevices() const = 0; + /** * @brief Get display name associated with the device. * @param device_id A device to get display name for. diff --git a/src/windows/winapilayer.cpp b/src/windows/winapilayer.cpp index eb0c3d3..8fef080 100644 --- a/src/windows/winapilayer.cpp +++ b/src/windows/winapilayer.cpp @@ -574,4 +574,49 @@ namespace display_device { return true; } + + std::optional + WinApiLayer::getDisplayScale(const std::string &display_name, const DISPLAYCONFIG_SOURCE_MODE &source_mode) const { + // Note: implementation based on https://stackoverflow.com/a/74046173 + struct EnumData { + std::string m_display_name; + std::optional m_width; + }; + + EnumData enum_data { display_name, std::nullopt }; + EnumDisplayMonitors( + nullptr, nullptr, [](HMONITOR monitor, HDC, LPRECT, LPARAM user_data) -> BOOL { + auto *data = reinterpret_cast(user_data); + if (data == nullptr) + { + // Sanity check + DD_LOG(error) << "EnumData is a nullptr!"; + return FALSE; + } + + MONITORINFOEXA monitor_info{ sizeof(MONITORINFOEXA ) }; + if (GetMonitorInfoA(monitor, &monitor_info)) + { + if (data->m_display_name == monitor_info.szDevice) + { + data->m_width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left; + return FALSE; + } + } + + return TRUE; }, reinterpret_cast(&enum_data)); + + if (!enum_data.m_width) { + DD_LOG(error) << "Failed to get monitor info for " << display_name << "!"; + return std::nullopt; + } + + if (*enum_data.m_width * source_mode.width == 0) { + DD_LOG(error) << "Cannot get display scale for " << display_name << " from a width of 0!"; + return std::nullopt; + } + + const auto width { static_cast(*enum_data.m_width) / static_cast(source_mode.width) }; + return static_cast(GetDpiForSystem()) / 96.0f / width; + } } // namespace display_device diff --git a/src/windows/windisplaydevicegeneral.cpp b/src/windows/windisplaydevicegeneral.cpp index 6e766c7..7d4c230 100644 --- a/src/windows/windisplaydevicegeneral.cpp +++ b/src/windows/windisplaydevicegeneral.cpp @@ -34,6 +34,64 @@ namespace display_device { return result == ERROR_SUCCESS; } + EnumeratedDeviceList + WinDisplayDevice::enumAvailableDevices() const { + const auto display_data { m_w_api->queryDisplayConfig(QueryType::All) }; + if (!display_data) { + // Error already logged + return {}; + } + + EnumeratedDeviceList available_devices; + const auto source_data { win_utils::collectSourceDataForMatchingPaths(*m_w_api, display_data->m_paths) }; + if (source_data.empty()) { + // Error already logged + return {}; + } + + for (const auto &[device_id, data] : source_data) { + const auto source_id_index { data.m_active_source.value_or(0) }; + const auto &best_path { display_data->m_paths.at(data.m_source_id_to_path_index.at(source_id_index)) }; + const auto friendly_name { m_w_api->getFriendlyName(best_path) }; + + if (win_utils::isActive(best_path)) { + const auto source_mode { win_utils::getSourceMode(win_utils::getSourceIndex(best_path, display_data->m_modes), display_data->m_modes) }; + if (!source_mode) { + // Error already logged + return {}; + } + + const auto display_name { m_w_api->getDisplayName(best_path) }; + const float refresh_rate { best_path.targetInfo.refreshRate.Denominator > 0 ? + static_cast(best_path.targetInfo.refreshRate.Numerator) / static_cast(best_path.targetInfo.refreshRate.Denominator) : + 0.f }; + const EnumeratedDevice::Info info { + { source_mode->width, source_mode->height }, + m_w_api->getDisplayScale(display_name, *source_mode).value_or(0.f), + refresh_rate, + win_utils::isPrimary(*source_mode), + { source_mode->position.x, source_mode->position.y }, + m_w_api->getHdrState(best_path) + }; + + available_devices.push_back( + { device_id, + display_name, + friendly_name, + info }); + } + else { + available_devices.push_back( + { device_id, + std::string {}, // Inactive devices can have multiple display names, so it's just meaningless use any + friendly_name, + std::nullopt }); + } + } + + return available_devices; + } + std::string WinDisplayDevice::getDisplayName(const std::string &device_id) const { if (device_id.empty()) { diff --git a/tests/unit/windows/test_winapilayer.cpp b/tests/unit/windows/test_winapilayer.cpp index e31920d..b0e77c4 100644 --- a/tests/unit/windows/test_winapilayer.cpp +++ b/tests/unit/windows/test_winapilayer.cpp @@ -212,3 +212,38 @@ TEST_F_S(GetHdrState, InvalidPath) { TEST_F_S(SetHdrState, InvalidPath) { EXPECT_FALSE(m_layer.setHdrState(INVALID_PATH, display_device::HdrState::Enabled)); } + +TEST_F_S(GetDisplayScale) { + const auto active_devices { m_layer.queryDisplayConfig(display_device::QueryType::Active) }; + ASSERT_TRUE(active_devices); + + for (const auto &path : active_devices->m_paths) { + const auto source_mode_index = path.sourceInfo.sourceModeInfoIdx; + + if (source_mode_index != DISPLAYCONFIG_PATH_SOURCE_MODE_IDX_INVALID) { + ASSERT_TRUE(source_mode_index < active_devices->m_modes.size()); + ASSERT_EQ(active_devices->m_modes[source_mode_index].infoType, DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE); + + // Valid case + { + const auto scale { m_layer.getDisplayScale(m_layer.getDisplayName(path), active_devices->m_modes[source_mode_index].sourceMode) }; + EXPECT_TRUE(scale.has_value()); // Can't really compare against anything... + } + + // Invalid display name case + { + const auto scale { m_layer.getDisplayScale("FAKE", active_devices->m_modes[source_mode_index].sourceMode) }; + EXPECT_FALSE(scale.has_value()); + } + + // Zero width case + { + auto mode { active_devices->m_modes[source_mode_index].sourceMode }; + mode.width = 0; + + const auto scale { m_layer.getDisplayScale(m_layer.getDisplayName(path), mode) }; + EXPECT_FALSE(scale.has_value()); + } + } + } +} diff --git a/tests/unit/windows/test_windisplaydevicegeneral.cpp b/tests/unit/windows/test_windisplaydevicegeneral.cpp index b5a3e34..5ba3d26 100644 --- a/tests/unit/windows/test_windisplaydevicegeneral.cpp +++ b/tests/unit/windows/test_windisplaydevicegeneral.cpp @@ -4,12 +4,14 @@ #include "displaydevice/windows/windisplaydevice.h" #include "fixtures.h" #include "utils/comparison.h" +#include "utils/helpers.h" #include "utils/mockwinapilayer.h" namespace { // Convenience keywords for GMock using ::testing::_; using ::testing::HasSubstr; + using ::testing::InSequence; using ::testing::Return; using ::testing::StrictMock; @@ -80,6 +82,164 @@ TEST_F_S_MOCKED(IsApiAccessAvailable, FailedToSetDisplayConfig) { EXPECT_FALSE(m_win_dd.isApiAccessAvailable()); } +TEST_F_S(EnumAvailableDevices) { + // Note: we can't verify live data precisely, so just basic check + // is performed regarding active vs. inactive devices + + const auto available_devices { getAvailableDevices(*m_layer, false) }; + ASSERT_TRUE(available_devices); + + const auto enum_devices { m_win_dd.enumAvailableDevices() }; + ASSERT_EQ(available_devices->size(), enum_devices.size()); + + const auto topology { flattenTopology(m_win_dd.getCurrentTopology()) }; + for (const auto &device_id : *available_devices) { + auto enum_it { std::find_if(std::begin(enum_devices), std::end(enum_devices), [&device_id](const auto &entry) { + return entry.m_device_id == device_id; + }) }; + + ASSERT_TRUE(enum_it != std::end(enum_devices)); + EXPECT_EQ(enum_it->m_info.has_value(), topology.contains(device_id)); + } +} + +TEST_F_S_MOCKED(EnumAvailableDevices) { + const auto pam_active_and_inactive { []() { + auto pam { ut_consts::PAM_3_ACTIVE }; + pam->m_paths.at(0).targetInfo.refreshRate.Denominator = 0; + pam->m_paths.at(2).flags &= ~DISPLAYCONFIG_PATH_ACTIVE; + return pam; + }() }; + + InSequence sequence; + EXPECT_CALL(*m_layer, queryDisplayConfig(display_device::QueryType::All)) + .Times(1) + .WillOnce(Return(pam_active_and_inactive)) + .RetiresOnSaturation(); + + for (int i = 1; i <= 3; ++i) { + EXPECT_CALL(*m_layer, getMonitorDevicePath(_)) + .Times(1) + .WillOnce(Return("Path" + std::to_string(i))) + .RetiresOnSaturation(); + EXPECT_CALL(*m_layer, getDeviceId(_)) + .Times(1) + .WillOnce(Return("DeviceId" + std::to_string(i))) + .RetiresOnSaturation(); + EXPECT_CALL(*m_layer, getDisplayName(_)) + .Times(1) + .WillOnce(Return("DisplayName" + std::to_string(i))) + .RetiresOnSaturation(); + } + + EXPECT_CALL(*m_layer, getFriendlyName(_)) + .Times(1) + .WillOnce(Return("FriendlyName1")) + .RetiresOnSaturation(); + EXPECT_CALL(*m_layer, getDisplayName(_)) + .Times(1) + .WillOnce(Return("DisplayName1")) + .RetiresOnSaturation(); + EXPECT_CALL(*m_layer, getDisplayScale(_, _)) + .Times(1) + .WillOnce(Return(std::nullopt)) + .RetiresOnSaturation(); + EXPECT_CALL(*m_layer, getHdrState(_)) + .Times(1) + .WillOnce(Return(std::nullopt)) + .RetiresOnSaturation(); + + EXPECT_CALL(*m_layer, getFriendlyName(_)) + .Times(1) + .WillOnce(Return("FriendlyName2")) + .RetiresOnSaturation(); + EXPECT_CALL(*m_layer, getDisplayName(_)) + .Times(1) + .WillOnce(Return("DisplayName2")) + .RetiresOnSaturation(); + EXPECT_CALL(*m_layer, getDisplayScale(_, _)) + .Times(1) + .WillOnce(Return(1.75f)) + .RetiresOnSaturation(); + EXPECT_CALL(*m_layer, getHdrState(_)) + .Times(1) + .WillOnce(Return(display_device::HdrState::Enabled)) + .RetiresOnSaturation(); + + EXPECT_CALL(*m_layer, getFriendlyName(_)) + .Times(1) + .WillOnce(Return("FriendlyName3")) + .RetiresOnSaturation(); + + const display_device::EnumeratedDeviceList expected_list { + { "DeviceId1", + "DisplayName1", + "FriendlyName1", + display_device::EnumeratedDevice::Info { + { 1920, 1080 }, + 0.f, + 0.f, + true, + { 0, 0 }, + std::nullopt } }, + { "DeviceId2", + "DisplayName2", + "FriendlyName2", + display_device::EnumeratedDevice::Info { + { 1920, 2160 }, + 1.75f, + 119.995f, + false, + { 1921, 0 }, + display_device::HdrState::Enabled } }, + { "DeviceId3", + "", + "FriendlyName3", + std::nullopt } + }; + EXPECT_EQ(m_win_dd.enumAvailableDevices(), expected_list); +} + +TEST_F_S_MOCKED(EnumAvailableDevices, FailedToGetDisplayData) { + EXPECT_CALL(*m_layer, queryDisplayConfig(display_device::QueryType::All)) + .Times(1) + .WillOnce(Return(ut_consts::PAM_NULL)); + + EXPECT_EQ(m_win_dd.enumAvailableDevices(), display_device::EnumeratedDeviceList {}); +} + +TEST_F_S_MOCKED(EnumAvailableDevices, FailedToCollectSourceData) { + EXPECT_CALL(*m_layer, queryDisplayConfig(display_device::QueryType::All)) + .Times(1) + .WillOnce(Return(ut_consts::PAM_EMPTY)); + + EXPECT_EQ(m_win_dd.enumAvailableDevices(), display_device::EnumeratedDeviceList {}); +} + +TEST_F_S_MOCKED(EnumAvailableDevices, NoDisplayModes) { + auto pam_no_modes { ut_consts::PAM_3_ACTIVE }; + pam_no_modes->m_paths.resize(1); + pam_no_modes->m_modes.clear(); + + EXPECT_CALL(*m_layer, queryDisplayConfig(display_device::QueryType::All)) + .Times(1) + .WillOnce(Return(pam_no_modes)); + EXPECT_CALL(*m_layer, getMonitorDevicePath(_)) + .Times(1) + .WillOnce(Return("Path1")); + EXPECT_CALL(*m_layer, getDeviceId(_)) + .Times(1) + .WillOnce(Return("DeviceId1")); + EXPECT_CALL(*m_layer, getDisplayName(_)) + .Times(1) + .WillOnce(Return("DisplayName1")); + EXPECT_CALL(*m_layer, getFriendlyName(_)) + .Times(1) + .WillOnce(Return("FriendlyName1")); + + EXPECT_EQ(m_win_dd.enumAvailableDevices(), display_device::EnumeratedDeviceList {}); +} + TEST_F_S(GetDisplayName) { const auto all_devices { m_layer->queryDisplayConfig(display_device::QueryType::All) }; ASSERT_TRUE(all_devices); diff --git a/tests/unit/windows/utils/comparison.cpp b/tests/unit/windows/utils/comparison.cpp index e8af83e..ee99460 100644 --- a/tests/unit/windows/utils/comparison.cpp +++ b/tests/unit/windows/utils/comparison.cpp @@ -106,12 +106,22 @@ operator==(const DISPLAYCONFIG_MODE_INFO &lhs, const DISPLAYCONFIG_MODE_INFO &rh return false; } +bool +fuzzyCompare(float lhs, float rhs) { + return std::abs(lhs - rhs) * 100000.f <= std::min(std::abs(lhs), std::abs(rhs)); +} + namespace display_device { bool operator==(const PathSourceIndexData &lhs, const PathSourceIndexData &rhs) { return lhs.m_source_id_to_path_index == rhs.m_source_id_to_path_index && lhs.m_adapter_id == rhs.m_adapter_id && lhs.m_active_source == rhs.m_active_source; } + bool + operator==(const Point &lhs, const Point &rhs) { + return lhs.m_x == rhs.m_x && lhs.m_y == rhs.m_y; + } + bool operator==(const Rational &lhs, const Rational &rhs) { return lhs.m_numerator == rhs.m_numerator && lhs.m_denominator == rhs.m_denominator; @@ -126,4 +136,16 @@ namespace display_device { operator==(const DisplayMode &lhs, const DisplayMode &rhs) { return lhs.m_refresh_rate == rhs.m_refresh_rate && lhs.m_resolution == rhs.m_resolution; } + + bool + operator==(const EnumeratedDevice::Info &lhs, const EnumeratedDevice::Info &rhs) { + return lhs.m_resolution == rhs.m_resolution && fuzzyCompare(lhs.m_resolution_scale, rhs.m_resolution_scale) && + fuzzyCompare(lhs.m_refresh_rate, rhs.m_refresh_rate) && lhs.m_primary == rhs.m_primary && + lhs.m_origin_point == rhs.m_origin_point && lhs.m_hdr_state == rhs.m_hdr_state; + } + + bool + operator==(const EnumeratedDevice &lhs, const EnumeratedDevice &rhs) { + return lhs.m_device_id == rhs.m_device_id && lhs.m_display_name == rhs.m_display_name && lhs.m_friendly_name == rhs.m_friendly_name && lhs.m_info == rhs.m_info; + } } // namespace display_device diff --git a/tests/unit/windows/utils/comparison.h b/tests/unit/windows/utils/comparison.h index e31cd44..3a5841d 100644 --- a/tests/unit/windows/utils/comparison.h +++ b/tests/unit/windows/utils/comparison.h @@ -43,10 +43,16 @@ operator==(const DISPLAYCONFIG_DESKTOP_IMAGE_INFO &lhs, const DISPLAYCONFIG_DESK bool operator==(const DISPLAYCONFIG_MODE_INFO &lhs, const DISPLAYCONFIG_MODE_INFO &rhs); +bool +fuzzyCompare(float lhs, float rhs); + namespace display_device { bool operator==(const PathSourceIndexData &lhs, const PathSourceIndexData &rhs); + bool + operator==(const Point &lhs, const Point &rhs); + bool operator==(const Rational &lhs, const Rational &rhs); @@ -55,4 +61,10 @@ namespace display_device { bool operator==(const DisplayMode &lhs, const DisplayMode &rhs); + + bool + operator==(const EnumeratedDevice::Info &lhs, const EnumeratedDevice::Info &rhs); + + bool + operator==(const EnumeratedDevice &lhs, const EnumeratedDevice &rhs); } // namespace display_device diff --git a/tests/unit/windows/utils/mockwinapilayer.h b/tests/unit/windows/utils/mockwinapilayer.h index 51541a1..9a15035 100644 --- a/tests/unit/windows/utils/mockwinapilayer.h +++ b/tests/unit/windows/utils/mockwinapilayer.h @@ -18,6 +18,7 @@ namespace display_device { MOCK_METHOD(LONG, setDisplayConfig, (std::vector, std::vector, UINT32), (override)); MOCK_METHOD(std::optional, getHdrState, (const DISPLAYCONFIG_PATH_INFO &), (const, override)); MOCK_METHOD(bool, setHdrState, (const DISPLAYCONFIG_PATH_INFO &, HdrState), (override)); + MOCK_METHOD(std::optional, getDisplayScale, (const std::string &, const DISPLAYCONFIG_SOURCE_MODE &), (const, override)); }; } // namespace display_device