use windows::Win32::Foundation::HWND;
use windows::Win32::Graphics::Gdi::{
CDS_FULLSCREEN, ChangeDisplaySettingsExW, DEVMODEW, DISP_CHANGE_SUCCESSFUL,
ENUM_CURRENT_SETTINGS, ENUM_DISPLAY_SETTINGS_MODE, EnumDisplaySettingsW, GetMonitorInfoW,
MONITOR_DEFAULTTONEAREST, MONITORINFOEXW, MonitorFromWindow,
};
use windows::core::PCWSTR;
use crate::gfx::display_mode::{DisplayMode, best_native_index};
fn device_name(hwnd: HWND) -> Option<[u16; 32]> {
let mon = unsafe { MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) };
let mut info = MONITORINFOEXW::default();
info.monitorInfo.cbSize = std::mem::size_of::<MONITORINFOEXW>() as u32;
unsafe { GetMonitorInfoW(mon, &mut info.monitorInfo) }
.as_bool()
.then_some(info.szDevice)
}
fn enum_mode(device: &[u16; 32], index: ENUM_DISPLAY_SETTINGS_MODE) -> Option<DEVMODEW> {
let mut dm = DEVMODEW {
dmSize: std::mem::size_of::<DEVMODEW>() as u16,
..Default::default()
};
unsafe { EnumDisplaySettingsW(PCWSTR(device.as_ptr()), index, &mut dm) }
.as_bool()
.then_some(dm)
}
fn display_mode_of(dm: &DEVMODEW) -> Option<DisplayMode> {
if dm.dmPelsWidth == 0 || dm.dmPelsHeight == 0 || dm.dmBitsPerPel < 32 {
return None;
}
let refresh_hz = if dm.dmDisplayFrequency <= 1 {
0
} else {
dm.dmDisplayFrequency
};
Some(DisplayMode {
width: dm.dmPelsWidth,
height: dm.dmPelsHeight,
refresh_hz,
})
}
fn all_modes(device: &[u16; 32]) -> Vec<(DisplayMode, DEVMODEW)> {
let mut out = Vec::new();
let mut i = 0u32;
while let Some(dm) = enum_mode(device, ENUM_DISPLAY_SETTINGS_MODE(i)) {
i += 1;
if let Some(mode) = display_mode_of(&dm) {
out.push((mode, dm));
}
}
out
}
pub(super) fn enumerate(hwnd: HWND) -> Vec<DisplayMode> {
let Some(device) = device_name(hwnd) else {
return Vec::new();
};
all_modes(&device).into_iter().map(|(m, _)| m).collect()
}
pub(super) fn current(hwnd: HWND) -> Option<DisplayMode> {
let device = device_name(hwnd)?;
display_mode_of(&enum_mode(&device, ENUM_CURRENT_SETTINGS)?)
}
pub(super) struct FullscreenDisplayMode {
desired: Option<DisplayMode>,
original: Option<DEVMODEW>,
device: Option<[u16; 32]>,
applied: Option<DisplayMode>,
}
impl FullscreenDisplayMode {
pub(super) fn new() -> Self {
Self {
desired: None,
original: None,
device: None,
applied: None,
}
}
pub(super) fn set_desired(&mut self, mode: DisplayMode) {
self.desired = Some(mode);
}
pub(super) fn reconcile(&mut self, hwnd: HWND, fullscreen: bool) -> bool {
if !fullscreen {
return self.restore();
}
let Some(desired) = self.desired else {
return false;
};
if self.applied == Some(desired) {
return false;
}
if self.device.is_none() {
self.device = device_name(hwnd);
}
let Some(device) = self.device else {
return false;
};
let modes = all_modes(&device);
let shaped: Vec<DisplayMode> = modes.iter().map(|(m, _)| *m).collect();
let Some(idx) = best_native_index(&shaped, desired) else {
tracing::warn!(
"display has no {}x{} mode; keeping the current mode",
desired.width,
desired.height
);
self.desired = None;
return false;
};
if self.original.is_none() {
self.original = enum_mode(&device, ENUM_CURRENT_SETTINGS);
}
let devmode = &modes[idx].1;
let err = unsafe {
ChangeDisplaySettingsExW(
PCWSTR(device.as_ptr()),
Some(std::ptr::from_ref(devmode)),
None,
CDS_FULLSCREEN,
None,
)
};
if err == DISP_CHANGE_SUCCESSFUL {
self.applied = Some(desired);
true
} else {
tracing::warn!(
"ChangeDisplaySettingsExW({}x{}@{}Hz) failed: {:?}",
desired.width,
desired.height,
desired.refresh_hz,
err
);
self.desired = None;
false
}
}
pub(super) fn restore(&mut self) -> bool {
let Some(original) = self.original.take() else {
return false;
};
let Some(device) = self.device else {
return false;
};
let err = unsafe {
ChangeDisplaySettingsExW(
PCWSTR(device.as_ptr()),
Some(std::ptr::from_ref(&original)),
None,
CDS_FULLSCREEN,
None,
)
};
if err != DISP_CHANGE_SUCCESSFUL {
tracing::warn!("restoring the desktop display mode failed: {:?}", err);
}
self.applied = None;
true
}
}
impl Drop for FullscreenDisplayMode {
fn drop(&mut self) {
self.restore();
}
}