use bevy::ecs::system::NonSendMarker;
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use bevy::winit::WINIT_WINDOWS;
use raw_window_handle::HasWindowHandle;
use raw_window_handle::RawWindowHandle;
use windows::Win32::Foundation::HWND;
use windows::Win32::Foundation::LPARAM;
use windows::Win32::Foundation::LRESULT;
use windows::Win32::Foundation::RECT;
use windows::Win32::Foundation::WPARAM;
use windows::Win32::UI::Shell::DefSubclassProc;
use windows::Win32::UI::Shell::RemoveWindowSubclass;
use windows::Win32::UI::Shell::SetWindowSubclass;
use windows::Win32::UI::WindowsAndMessaging::SWP_NOACTIVATE;
use windows::Win32::UI::WindowsAndMessaging::SWP_NOZORDER;
use windows::Win32::UI::WindowsAndMessaging::SetWindowPos;
use windows::Win32::UI::WindowsAndMessaging::WM_DPICHANGED;
const SUBCLASS_ID: usize = 1;
struct SendSyncHwnd(HWND);
unsafe impl Send for SendSyncHwnd {}
unsafe impl Sync for SendSyncHwnd {}
fn get_hwnd(window_entity: Entity) -> Option<HWND> {
WINIT_WINDOWS.with(|ww| {
let ww = ww.borrow();
let winit_window = ww.get_window(window_entity)?;
match winit_window.window_handle().ok()?.as_raw() {
RawWindowHandle::Win32(handle) => Some(HWND(handle.hwnd.get() as *mut _)),
_ => None,
}
})
}
fn handle_dpi_changed(hwnd: HWND, lparam: LPARAM) -> LRESULT {
let suggested_rect = unsafe { &*(lparam.0 as *const RECT) };
let result = unsafe {
SetWindowPos(
hwnd,
None,
suggested_rect.left,
suggested_rect.top,
suggested_rect.right - suggested_rect.left,
suggested_rect.bottom - suggested_rect.top,
SWP_NOZORDER | SWP_NOACTIVATE,
)
};
if result.is_err() {
warn!("[windows_dpi_fix] SetWindowPos failed: {:?}", result);
}
LRESULT(0)
}
unsafe extern "system" fn subclass_proc(
hwnd: HWND,
msg: u32,
wparam: WPARAM,
lparam: LPARAM,
_uidsubclass: usize,
_dwrefdata: usize,
) -> LRESULT {
if msg == WM_DPICHANGED {
debug!("[windows_dpi_fix] Intercepted WM_DPICHANGED");
return handle_dpi_changed(hwnd, lparam);
}
unsafe { DefSubclassProc(hwnd, msg, wparam, lparam) }
}
#[derive(Resource)]
pub struct DpiFixGuard {
hwnd: SendSyncHwnd,
}
impl Drop for DpiFixGuard {
fn drop(&mut self) {
let result = unsafe { RemoveWindowSubclass(self.hwnd.0, Some(subclass_proc), SUBCLASS_ID) };
if result.as_bool() {
debug!("[windows_dpi_fix] Removed DPI fix subclass");
}
}
}
pub fn install_dpi_fix(
mut commands: Commands,
window_entity: Single<Entity, With<PrimaryWindow>>,
_non_send: NonSendMarker,
) {
let Some(hwnd) = get_hwnd(*window_entity) else {
warn!("[windows_dpi_fix] Could not get HWND for primary window");
return;
};
let result = unsafe { SetWindowSubclass(hwnd, Some(subclass_proc), SUBCLASS_ID, 0) };
if result.as_bool() {
debug!("[windows_dpi_fix] Installed DPI change workaround");
commands.insert_resource(DpiFixGuard {
hwnd: SendSyncHwnd(hwnd),
});
} else {
warn!("[windows_dpi_fix] Failed to install subclass");
}
}
pub fn init(app: &mut App) { app.add_systems(Startup, install_dpi_fix); }