9#include "os_settings_intf.hpp"
10#include "../win32/win32.hpp"
11#include "../telemetry/telemetry.hpp"
12#include "../utility/utility.hpp"
13#include "../path/path.hpp"
14#include "../macros.hpp"
16hi_export_module(hikogui.settings.os_settings : impl);
18namespace hi {
inline namespace v1 {
25 if (actual_policy == hi::policy::unspecified) {
26 actual_policy = performance_policy;
28 if (actual_policy == hi::policy::unspecified) {
31 hilet actual_policy_ = actual_policy == hi::policy::low_power ? DXGI_GPU_PREFERENCE_MINIMUM_POWER :
32 actual_policy == hi::policy::high_performance ? DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE :
33 DXGI_GPU_PREFERENCE_UNSPECIFIED;
35 IDXGIFactory *factory =
nullptr;
36 if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), (
void **)&factory))) {
40 hi_assert_not_null(factory);
41 hilet d1 = defer([&] {
45 IDXGIFactory6 *factory6 =
nullptr;
46 if (FAILED(factory->QueryInterface(__uuidof(IDXGIFactory6), (
void **)&factory6))) {
50 hi_assert_not_null(factory6);
51 hilet d2 = defer([&] {
55 IDXGIAdapter1 *adapter =
nullptr;
57 SUCCEEDED(factory6->EnumAdapterByGpuPreference(i, actual_policy_, __uuidof(IDXGIAdapter1), (
void **)&adapter));
59 hilet d3 = defer([&] {
63 DXGI_ADAPTER_DESC1 description;
64 if (FAILED(adapter->GetDesc1(&description))) {
69 static_assert(
sizeof(description.AdapterLuid) <=
sizeof(uuid));
96 HKEY_CURRENT_USER,
"Control Panel\\International\\User Profile",
"Languages")) {
97 r.reserve(languages->size());
98 for (hilet& language : *languages) {
99 r.push_back(language_tag{language});
102 hi_log_error(
"Could not read languages: {}", std::error_code{languages.error()}.message());
109[[nodiscard]]
inline std::expected<std::locale, std::error_code> os_settings::gather_locale() noexcept
111 if (
auto name = win32_GetUserDefaultLocaleName()) {
112 return std::locale(*name);
119[[nodiscard]]
inline hi::theme_mode os_settings::gather_theme_mode()
121 if (hilet result = win32_RegGetValue<uint32_t>(
123 "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
124 "AppsUseLightTheme")) {
125 return *result ? theme_mode::light : theme_mode::dark;
128 hi_log_error(
"Could not read theme mode: {}", std::error_code{result.error()}.message());
129 return theme_mode::light;
133[[nodiscard]]
inline hi::subpixel_orientation os_settings::gather_subpixel_orientation()
136 BOOL has_font_smoothing;
137 if (not SystemParametersInfoW(SPI_GETFONTSMOOTHING, 0, &has_font_smoothing, 0)) {
141 if (has_font_smoothing == FALSE) {
143 return hi::subpixel_orientation::unknown;
148 UINT font_smooth_type;
149 if (not SystemParametersInfoW(SPI_GETFONTSMOOTHINGTYPE, 0, &font_smooth_type, 0)) {
153 if (font_smooth_type != FE_FONTSMOOTHINGCLEARTYPE) {
155 return hi::subpixel_orientation::unknown;
161 if (not SystemParametersInfoW(SPI_GETCLEARTYPE, 0, &has_clear_type, 0)) {
165 if (has_clear_type == FALSE) {
167 return hi::subpixel_orientation::unknown;
172 UINT font_smooth_orientation;
173 if (not SystemParametersInfoW(SPI_GETFONTSMOOTHINGORIENTATION, 0, &font_smooth_orientation, 0)) {
175 std::format(
"Could not get system parameter SPI_GETFONTSMOOTHINGORIENTATION: {}",
get_last_error_message()));
178 if (font_smooth_orientation == FE_FONTSMOOTHINGORIENTATIONBGR) {
180 return hi::subpixel_orientation::horizontal_bgr;
181 }
else if (font_smooth_orientation == FE_FONTSMOOTHINGORIENTATIONRGB) {
183 return hi::subpixel_orientation::horizontal_rgb;
185 throw os_error(std::format(
"Unknown result from SPI_GETFONTSMOOTHINGORIENTATION: {}", font_smooth_orientation));
190[[nodiscard]]
inline bool os_settings::gather_uniform_HDR()
197[[nodiscard]]
inline std::chrono::milliseconds os_settings::gather_double_click_interval()
199 return std::chrono::milliseconds{GetDoubleClickTime()};
202[[nodiscard]]
inline float os_settings::gather_double_click_distance()
204 hilet width = GetSystemMetrics(SM_CXDOUBLECLK);
206 throw os_error(
"Could not retrieve SM_CXDOUBLECLK");
209 hilet height = GetSystemMetrics(SM_CYDOUBLECLK);
211 throw os_error(
"Could not retrieve SM_CYDOUBLECLK");
214 hilet diameter =
std::max(width, height);
215 return diameter * 0.5f;
218[[nodiscard]]
inline std::chrono::milliseconds os_settings::gather_keyboard_repeat_delay()
220 using namespace std::literals::chrono_literals;
223 if (not SystemParametersInfoW(SPI_GETKEYBOARDDELAY, 0, &r, 0)) {
228 constexpr auto bias = 250ms;
229 constexpr auto gain = 250ms;
231 return bias + r * gain;
234[[nodiscard]]
inline std::chrono::milliseconds os_settings::gather_keyboard_repeat_interval()
236 using namespace std::literals::chrono_literals;
239 if (not SystemParametersInfoW(SPI_GETKEYBOARDSPEED, 0, &r, 0)) {
244 constexpr auto bias = 2.5f;
245 constexpr auto gain = 0.887f;
246 hilet rate = bias + r * gain;
250[[nodiscard]]
inline std::chrono::milliseconds os_settings::gather_cursor_blink_interval()
252 using namespace std::literals::chrono_literals;
254 hilet r = GetCaretBlinkTime();
258 }
else if (r == INFINITE) {
263 return std::chrono::milliseconds{r} * 2;
267[[nodiscard]]
inline std::chrono::milliseconds os_settings::gather_cursor_blink_delay()
270 return std::max(gather_keyboard_repeat_delay(), gather_keyboard_repeat_interval());
273[[nodiscard]]
inline float os_settings::gather_minimum_window_width()
275 hilet width = GetSystemMetrics(SM_CXMINTRACK);
277 throw os_error(
"Could not retrieve SM_CXMINTRACK");
282[[nodiscard]]
inline float os_settings::gather_minimum_window_height()
284 hilet height = GetSystemMetrics(SM_CYMINTRACK);
286 throw os_error(
"Could not retrieve SM_CYMINTRACK");
292[[nodiscard]]
inline float os_settings::gather_maximum_window_width()
294 hilet width = GetSystemMetrics(SM_CXMAXTRACK);
296 throw os_error(
"Could not retrieve SM_CXMAXTRACK");
301[[nodiscard]]
inline float os_settings::gather_maximum_window_height()
303 hilet height = GetSystemMetrics(SM_CYMAXTRACK);
305 throw os_error(
"Could not retrieve SM_CYMAXTRACK");
311[[nodiscard]]
inline uintptr_t os_settings::gather_primary_monitor_id()
313 hilet origin = POINT{0, 0};
314 hilet monitor = MonitorFromPoint(origin, MONITOR_DEFAULTTOPRIMARY);
315 return std::bit_cast<uintptr_t>(monitor);
318[[nodiscard]]
inline aarectangle os_settings::gather_primary_monitor_rectangle()
320 hilet width = GetSystemMetrics(SM_CXSCREEN);
322 throw os_error(
"Could not retrieve SM_CXSCREEN");
325 hilet height = GetSystemMetrics(SM_CYSCREEN);
327 throw os_error(
"Could not retrieve SM_CYSCREEN");
334[[nodiscard]]
inline aarectangle os_settings::gather_desktop_rectangle()
336 hilet primary_monitor_height = GetSystemMetrics(SM_CYSCREEN);
337 if (primary_monitor_height == 0) {
338 throw os_error(
"Could not retrieve SM_CYSCREEN");
341 hilet
left = GetSystemMetrics(SM_XVIRTUALSCREEN);
342 hilet
top = GetSystemMetrics(SM_YVIRTUALSCREEN);
344 hilet width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
346 throw os_error(
"Could not retrieve SM_CXVIRTUALSCREEN");
349 hilet height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
351 throw os_error(
"Could not retrieve SM_CYVIRTUALSCREEN");
357 hilet inv_bottom = primary_monitor_height -
bottom;
362[[nodiscard]]
inline policy os_settings::gather_gpu_policy()
364 using namespace std::literals;
367 hilet user_gpu_preferences_key =
"Software\\Microsoft\\DirectX\\UserGpuPreferences";
369 if (hilet result = win32_RegGetValue<std::string>(HKEY_CURRENT_USER, user_gpu_preferences_key, executable_path)) {
370 for (
auto entry : std::views::split(std::string_view{*result},
";"sv)) {
371 auto entry_sv = std::string_view{entry};
372 if (entry_sv.starts_with(
"GpuPreference=")) {
373 if (entry_sv.ends_with(
"=0")) {
374 return policy::unspecified;
375 }
else if (entry_sv.ends_with(
"=1")) {
376 return policy::low_power;
377 }
else if (entry_sv.ends_with(
"=2")) {
378 return policy::high_performance;
380 hi_log_error(
"Unexpected GpuPreference value \"{}\".", entry_sv);
381 return policy::unspecified;
386 hi_log_error(
"Could not find GpuPreference entry.");
387 return policy::unspecified;
389 }
else if (result.error() == win32_error::file_not_found) {
390 return policy::unspecified;
393 hi_log_error(
"Could not read gpu profile policy: {}", std::error_code{result.error()}.message());
394 return policy::unspecified;
Rules for working with win32 headers.
std::filesystem::path get_path(path_location location)
Get the single and only path.
Definition path_location_intf.hpp:112
@ executable_file
A single file where the current running executable is located.
Definition path_location_intf.hpp:31
@ bottom
Align to the bottom.
Definition alignment.hpp:37
@ top
Align to the top.
Definition alignment.hpp:29
@ left
Align the text to the left side.
Definition alignment.hpp:119
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
The HikoGUI API version 1.
Definition lookahead_iterator.hpp:6
std::string get_last_error_message()
Get the OS error message from the last error received on this thread.
Definition exception_win32_impl.hpp:31
policy
The performance policy to use.
Definition policy.hpp:18
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:29
A high-level geometric extent.
Definition extent2.hpp:29
The IETF BCP 47 language tag.
Definition language_tag_intf.hpp:28
static hi::policy gpu_policy() noexcept
Get the policy for selecting a GPU.
Definition os_settings_intf.hpp:236
static std::vector< uuid > preferred_gpus(hi::policy performance_policy) noexcept
Get a list of GPUs ordered best to worst.
Definition os_settings_win32_impl.hpp:20
Exception thrown during an operating system call.
Definition exception_intf.hpp:183
T duration_cast(T... args)