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);
18hi_export
namespace hi {
inline namespace v1 {
20[[nodiscard]]
inline std::expected<device_type, std::error_code> os_settings::gather_device_type() noexcept
22 auto const is_tablet =
static_cast<bool>(GetSystemMetrics(SM_TABLETPC));
24 return device_type::tablet;
26 return device_type::desktop;
34 auto actual_policy = os_settings::gpu_policy();
35 if (actual_policy == hi::policy::unspecified) {
36 actual_policy = performance_policy;
38 if (actual_policy == hi::policy::unspecified) {
41 auto const actual_policy_ = actual_policy == hi::policy::low_power ? DXGI_GPU_PREFERENCE_MINIMUM_POWER :
42 actual_policy == hi::policy::high_performance ? DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE :
43 DXGI_GPU_PREFERENCE_UNSPECIFIED;
45 IDXGIFactory *factory =
nullptr;
46 if (FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), (
void **)&factory))) {
50 hi_assert_not_null(factory);
51 auto const d1 = defer([&] {
55 IDXGIFactory6 *factory6 =
nullptr;
56 if (FAILED(factory->QueryInterface(__uuidof(IDXGIFactory6), (
void **)&factory6))) {
60 hi_assert_not_null(factory6);
61 auto const d2 = defer([&] {
65 IDXGIAdapter1 *adapter =
nullptr;
67 SUCCEEDED(factory6->EnumAdapterByGpuPreference(i, actual_policy_, __uuidof(IDXGIAdapter1), (
void **)&adapter));
69 auto const d3 = defer([&] {
73 DXGI_ADAPTER_DESC1 description;
74 if (FAILED(adapter->GetDesc1(&description))) {
79 static_assert(
sizeof(description.AdapterLuid) <=
sizeof(
uuid));
106 HKEY_CURRENT_USER,
"Control Panel\\International\\User Profile",
"Languages")) {
108 for (
auto const& language : *languages) {
109 r.push_back(language_tag{language});
113 r.push_back(language_tag{
"en"});
119[[nodiscard]]
inline std::expected<std::locale, std::error_code> os_settings::gather_locale() noexcept
121 if (
auto name = win32_GetUserDefaultLocaleName()) {
129[[nodiscard]]
inline bool os_settings::gather_left_to_right() noexcept
131 if (
auto locale = gather_locale()) {
134 auto locale_name = locale->name();
137 if (
auto i = locale_name.find(
'.'); i != locale_name.npos) {
138 locale_name = locale_name.substr(0, i);
141 auto locale_tag = language_tag{locale->name()};
145 return locale_tag.expand().left_to_right();
154 if (
auto languages = gather_languages(); not languages.empty()) {
155 return languages.front().expand().left_to_right();
162[[nodiscard]]
inline hi::theme_mode os_settings::gather_theme_mode()
164 if (
auto const result = win32_RegGetValue<uint32_t>(
166 "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
167 "AppsUseLightTheme")) {
168 return *result ? theme_mode::light : theme_mode::dark;
172 return theme_mode::light;
176[[nodiscard]]
inline hi::subpixel_orientation os_settings::gather_subpixel_orientation()
179 BOOL has_font_smoothing;
180 if (not SystemParametersInfoW(SPI_GETFONTSMOOTHING, 0, &has_font_smoothing, 0)) {
181 throw os_error(std::format(
"Could not get system parameter SPI_GETFONTSMOOTHING: {}",
get_last_error_message()));
184 if (has_font_smoothing == FALSE) {
186 return hi::subpixel_orientation::unknown;
191 UINT font_smooth_type;
192 if (not SystemParametersInfoW(SPI_GETFONTSMOOTHINGTYPE, 0, &font_smooth_type, 0)) {
193 throw os_error(std::format(
"Could not get system parameter SPI_GETFONTSMOOTHINGTYPE: {}",
get_last_error_message()));
196 if (font_smooth_type != FE_FONTSMOOTHINGCLEARTYPE) {
198 return hi::subpixel_orientation::unknown;
204 if (not SystemParametersInfoW(SPI_GETCLEARTYPE, 0, &has_clear_type, 0)) {
205 throw os_error(std::format(
"Could not get system parameter SPI_GETCLEARTYPE: {}",
get_last_error_message()));
208 if (has_clear_type == FALSE) {
210 return hi::subpixel_orientation::unknown;
215 UINT font_smooth_orientation;
216 if (not SystemParametersInfoW(SPI_GETFONTSMOOTHINGORIENTATION, 0, &font_smooth_orientation, 0)) {
218 std::format(
"Could not get system parameter SPI_GETFONTSMOOTHINGORIENTATION: {}",
get_last_error_message()));
221 if (font_smooth_orientation == FE_FONTSMOOTHINGORIENTATIONBGR) {
223 return hi::subpixel_orientation::horizontal_bgr;
224 }
else if (font_smooth_orientation == FE_FONTSMOOTHINGORIENTATIONRGB) {
226 return hi::subpixel_orientation::horizontal_rgb;
228 throw os_error(std::format(
"Unknown result from SPI_GETFONTSMOOTHINGORIENTATION: {}", font_smooth_orientation));
233[[nodiscard]]
inline bool os_settings::gather_uniform_HDR()
245[[nodiscard]]
inline float os_settings::gather_double_click_distance()
247 auto const width = GetSystemMetrics(SM_CXDOUBLECLK);
249 throw os_error(
"Could not retrieve SM_CXDOUBLECLK");
252 auto const height = GetSystemMetrics(SM_CYDOUBLECLK);
254 throw os_error(
"Could not retrieve SM_CYDOUBLECLK");
257 auto const diameter =
std::max(width, height);
258 return diameter * 0.5f;
263 using namespace std::literals::chrono_literals;
266 if (not SystemParametersInfoW(SPI_GETKEYBOARDDELAY, 0, &r, 0)) {
267 throw os_error(std::format(
"Could not get system parameter SPI_GETKEYBOARDDELAY: {}",
get_last_error_message()));
271 constexpr auto bias = 250ms;
272 constexpr auto gain = 250ms;
274 return bias + r * gain;
279 using namespace std::literals::chrono_literals;
282 if (not SystemParametersInfoW(SPI_GETKEYBOARDSPEED, 0, &r, 0)) {
283 throw os_error(std::format(
"Could not get system parameter SPI_GETKEYBOARDSPEED: {}",
get_last_error_message()));
287 constexpr auto bias = 2.5f;
288 constexpr auto gain = 0.887f;
289 auto const rate = bias + r * gain;
290 return std::chrono::duration_cast<std::chrono::milliseconds>(1000ms / rate);
295 using namespace std::literals::chrono_literals;
297 auto const r = GetCaretBlinkTime();
301 }
else if (r == INFINITE) {
313 return std::max(gather_keyboard_repeat_delay(), gather_keyboard_repeat_interval());
316[[nodiscard]]
inline float os_settings::gather_minimum_window_width()
318 auto const width = GetSystemMetrics(SM_CXMINTRACK);
320 throw os_error(
"Could not retrieve SM_CXMINTRACK");
322 return narrow_cast<float>(width);
325[[nodiscard]]
inline float os_settings::gather_minimum_window_height()
327 auto const height = GetSystemMetrics(SM_CYMINTRACK);
329 throw os_error(
"Could not retrieve SM_CYMINTRACK");
332 return narrow_cast<float>(height);
335[[nodiscard]]
inline float os_settings::gather_maximum_window_width()
337 auto const width = GetSystemMetrics(SM_CXMAXTRACK);
339 throw os_error(
"Could not retrieve SM_CXMAXTRACK");
341 return narrow_cast<float>(width);
344[[nodiscard]]
inline float os_settings::gather_maximum_window_height()
346 auto const height = GetSystemMetrics(SM_CYMAXTRACK);
348 throw os_error(
"Could not retrieve SM_CYMAXTRACK");
351 return narrow_cast<float>(height);
354[[nodiscard]]
inline uintptr_t os_settings::gather_primary_monitor_id()
356 auto const origin = POINT{0, 0};
357 auto const monitor = MonitorFromPoint(origin, MONITOR_DEFAULTTOPRIMARY);
358 return std::bit_cast<uintptr_t>(monitor);
361[[nodiscard]]
inline aarectangle os_settings::gather_primary_monitor_rectangle()
363 auto const width = GetSystemMetrics(SM_CXSCREEN);
365 throw os_error(
"Could not retrieve SM_CXSCREEN");
368 auto const height = GetSystemMetrics(SM_CYSCREEN);
370 throw os_error(
"Could not retrieve SM_CYSCREEN");
374 return aarectangle{extent2{narrow_cast<float>(width), narrow_cast<float>(height)}};
377[[nodiscard]]
inline aarectangle os_settings::gather_desktop_rectangle()
379 auto const primary_monitor_height = GetSystemMetrics(SM_CYSCREEN);
380 if (primary_monitor_height == 0) {
381 throw os_error(
"Could not retrieve SM_CYSCREEN");
384 auto const left = GetSystemMetrics(SM_XVIRTUALSCREEN);
385 auto const top = GetSystemMetrics(SM_YVIRTUALSCREEN);
387 auto const width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
389 throw os_error(
"Could not retrieve SM_CXVIRTUALSCREEN");
392 auto const height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
394 throw os_error(
"Could not retrieve SM_CYVIRTUALSCREEN");
400 auto const inv_bottom = primary_monitor_height -
bottom;
402 narrow_cast<float>(
left), narrow_cast<float>(inv_bottom), narrow_cast<float>(width), narrow_cast<float>(height)};
405[[nodiscard]]
inline policy os_settings::gather_gpu_policy()
407 using namespace std::literals;
410 if (not executable_file_) {
411 hi_log_error(
"Could not get path to executable: {}", executable_file_.error().message());
412 return policy::unspecified;
415 auto const user_gpu_preferences_key =
"Software\\Microsoft\\DirectX\\UserGpuPreferences";
416 if (
auto const result = win32_RegGetValue<std::string>(HKEY_CURRENT_USER, user_gpu_preferences_key, executable_file_->string())) {
417 for (
auto entry :
std::views::split(
std::string_view{*result},
";"sv)) {
418 auto entry_sv = std::string_view{entry};
419 if (entry_sv.starts_with(
"GpuPreference=")) {
420 if (entry_sv.ends_with(
"=0")) {
421 return policy::unspecified;
422 }
else if (entry_sv.ends_with(
"=1")) {
423 return policy::low_power;
424 }
else if (entry_sv.ends_with(
"=2")) {
425 return policy::high_performance;
427 hi_log_error(
"Unexpected GpuPreference value \"{}\".", entry_sv);
428 return policy::unspecified;
433 hi_log_error(
"Could not find GpuPreference entry.");
434 return policy::unspecified;
436 }
else if (result.error() == win32_error::file_not_found) {
437 return policy::unspecified;
441 return policy::unspecified;
Rules for working with win32 headers.
@ bottom
Align to the bottom.
@ left
Align the text to the left side.
std::expected< std::filesystem::path, std::error_code > executable_file() noexcept
Get the full path to this executable.
Definition path_location_win32_impl.hpp:25
The HikoGUI namespace.
Definition array_generic.hpp:20
std::expected< T, win32_error > win32_RegGetValue(HKEY key, std::string_view path, std::string_view name)=delete
Read from the registry value.
Definition winreg.hpp:282
hi_export std::string get_last_error_message()
Get the OS error message from the last error received on this thread.
Definition exception_win32_impl.hpp:30
policy
The performance policy to use.
Definition policy.hpp:18
DOXYGEN BUG.
Definition algorithm_misc.hpp:20