diff --git a/Cargo.toml b/Cargo.toml index 4bf4324..9001b8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,9 @@ features = [ "Win32_Foundation", "Win32_UI_WindowsAndMessaging", "Win32_UI_Input_KeyboardAndMouse", + "Win32_UI_HiDpi", "Win32_Graphics_Gdi", + "Win32_System_LibraryLoader", "Win32_System_SystemServices", ] diff --git a/src/backend/win32/app.rs b/src/backend/win32/app.rs index c8fbb4f..5f31a35 100644 --- a/src/backend/win32/app.rs +++ b/src/backend/win32/app.rs @@ -12,6 +12,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{ RegisterClassW, TranslateMessage, UnregisterClassW, MSG, WNDCLASSW, }; +use super::dpi::DpiFns; use super::timer::{TimerHandleInner, Timers}; use super::window::wnd_proc; use super::{class_name, hinstance, to_wstring, OsError}; @@ -19,6 +20,7 @@ use crate::{App, AppContext, AppOptions, Error, IntoInnerError, Result}; pub struct AppState { pub class: u16, + pub dpi: DpiFns, pub timers: Timers, pub data: RefCell>>, } @@ -68,10 +70,13 @@ impl AppInner { class }; + let dpi = DpiFns::load(); + let timers = Timers::new()?; let state = Rc::new(AppState { class, + dpi, timers, data: RefCell::new(None), }); diff --git a/src/backend/win32/dpi.rs b/src/backend/win32/dpi.rs new file mode 100644 index 0000000..0041011 --- /dev/null +++ b/src/backend/win32/dpi.rs @@ -0,0 +1,73 @@ +use std::mem; + +use windows_sys::core::HRESULT; +use windows_sys::Win32::Foundation::{BOOL, HWND, RECT}; +use windows_sys::Win32::Graphics::Gdi::HMONITOR; +use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA}; +use windows_sys::Win32::UI::HiDpi::{ + DPI_AWARENESS_CONTEXT, MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS, +}; +use windows_sys::Win32::UI::WindowsAndMessaging::{WINDOW_EX_STYLE, WINDOW_STYLE}; + +macro_rules! c_str { + ($str:literal) => { + concat!($str, "\0").as_ptr() + }; +} + +#[allow(non_snake_case)] +pub struct DpiFns { + pub SetProcessDPIAware: Option BOOL>, + pub SetProcessDpiAwareness: + Option HRESULT>, + pub SetProcessDpiAwarenessContext: + Option BOOL>, + pub GetDpiForMonitor: Option< + unsafe extern "system" fn( + hmonitor: HMONITOR, + dpitype: MONITOR_DPI_TYPE, + dpix: *mut u32, + dpiy: *mut u32, + ) -> HRESULT, + >, + pub GetDpiForWindow: Option u32>, + pub EnableNonClientDpiScaling: Option BOOL>, + pub AdjustWindowRectExForDpi: Option< + unsafe extern "system" fn( + lprect: *mut RECT, + dwstyle: WINDOW_STYLE, + bmenu: BOOL, + dwexstyle: WINDOW_EX_STYLE, + dpi: u32, + ) -> BOOL, + >, +} + +impl DpiFns { + pub fn load() -> DpiFns { + macro_rules! load { + ($lib:expr, $symbol:literal) => { + if $lib != 0 { + mem::transmute(GetProcAddress($lib, c_str!($symbol))) + } else { + None + } + }; + } + + unsafe { + let user32 = LoadLibraryA(c_str!("user32.dll")); + let shcore = LoadLibraryA(c_str!("shcore.dll")); + + DpiFns { + SetProcessDPIAware: load!(user32, "SetProcessDPIAware"), + SetProcessDpiAwareness: load!(shcore, "SetProcessDpiAwareness"), + SetProcessDpiAwarenessContext: load!(user32, "SetProcessDpiAwarenessContext"), + GetDpiForMonitor: load!(shcore, "GetDpiForMonitor"), + GetDpiForWindow: load!(user32, "GetDpiForWindow"), + EnableNonClientDpiScaling: load!(user32, "EnableNonClientDpiScaling"), + AdjustWindowRectExForDpi: load!(user32, "AdjustWindowRectExForDpi"), + } + } + } +} diff --git a/src/backend/win32/mod.rs b/src/backend/win32/mod.rs index ce264ac..bc4f36f 100644 --- a/src/backend/win32/mod.rs +++ b/src/backend/win32/mod.rs @@ -6,6 +6,7 @@ use windows_sys::Win32::Foundation::{HMODULE, WIN32_ERROR}; use windows_sys::Win32::System::SystemServices::IMAGE_DOS_HEADER; mod app; +mod dpi; mod timer; mod window;