//! One-shot primary-display refresh probe (OnceLock-cached). //! Fail-closed: never panics into callers; no TTY IO; no display mode mutation. use std::sync::OnceLock; use std::time::Instant; use super::{DisplayServer, HostOs, is_wsl}; /// Sane bounds; outside → fail closed. const MIN_HZ: u32 = 30; const MAX_HZ: u32 = 500; #[derive(Debug, Clone, Copy, PartialEq, Eq, strum::Display, strum::AsRefStr)] #[strum(serialize_all = "snake_case")] pub enum DisplayRefreshSource { None, MacosCoreGraphics, WindowsEnumDisplaySettings, Linux, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct DisplayRefreshProbeResult { pub hz: Option, pub source: DisplayRefreshSource, /// Empty when ok; else a stable skip/error token. pub skip_reason: &'static str, pub duration_ms: u64, } impl DisplayRefreshProbeResult { /// `ok` | `skipped` | `error` pub fn outcome(self) -> &'static str { if self.hz.is_some() { "ok" } else if self.skip_reason == "error" { "error" } else { "skipped" } } } /// Once per process. Infallible; never panics. pub fn probe_display_refresh() -> DisplayRefreshProbeResult { static CACHE: OnceLock = OnceLock::new(); *CACHE.get_or_init(probe_uncached) } fn probe_uncached() -> DisplayRefreshProbeResult { let start = Instant::now(); let (hz, source, skip_reason) = probe_inner(); DisplayRefreshProbeResult { hz, source, skip_reason, duration_ms: start.elapsed().as_millis() as u64, } } fn probe_inner() -> (Option, DisplayRefreshSource, &'static str) { let is_ssh = kigi_shared::clipboard::is_remote_session(); let wsl = is_wsl(); let os = HostOs::current(); let display = DisplayServer::current(); // Avoid FFI when env already forces a skip. let platform_hz = if precheck_skip(is_ssh, wsl).is_some() { None } else { match os { HostOs::Macos => Some(probe_macos()), HostOs::Windows => Some(probe_windows()), HostOs::Linux | HostOs::Other => None, } }; decide(is_ssh, wsl, os, display, platform_hz) } /// Pure matrix used by production and tests; inject only the platform result. fn decide( is_ssh: bool, is_wsl: bool, os: HostOs, display: DisplayServer, platform_hz: Option>, ) -> (Option, DisplayRefreshSource, &'static str) { if let Some(reason) = precheck_skip(is_ssh, is_wsl) { return (None, DisplayRefreshSource::None, reason); } match os { HostOs::Macos => { let source = DisplayRefreshSource::MacosCoreGraphics; match platform_hz.unwrap_or(Err("error")) { Ok(hz) => accept_hz(hz, source), Err(reason) => (None, source, reason), } } HostOs::Windows => { let source = DisplayRefreshSource::WindowsEnumDisplaySettings; match platform_hz.unwrap_or(Err("error")) { Ok(hz) => accept_hz(hz, source), Err(reason) => (None, source, reason), } } HostOs::Linux => { let reason = linux_skip_reason(display); (None, DisplayRefreshSource::Linux, reason) } HostOs::Other => (None, DisplayRefreshSource::None, "unsupported"), } } fn precheck_skip(is_ssh: bool, is_wsl: bool) -> Option<&'static str> { if is_ssh { return Some("ssh"); } if is_wsl { return Some("wsl"); } None } fn linux_skip_reason(display: DisplayServer) -> &'static str { match display { DisplayServer::Wayland => "wayland_unsupported", DisplayServer::X11 => "x11_unsupported", _ => "no_display", } } fn accept_hz( hz: u32, source: DisplayRefreshSource, ) -> (Option, DisplayRefreshSource, &'static str) { if !(MIN_HZ..=MAX_HZ).contains(&hz) { return (None, source, "out_of_range"); } (Some(hz), source, "") } #[cfg(target_os = "macos")] fn probe_macos() -> Result { // Fail-closed if FFI panics (abort builds still abort). match std::panic::catch_unwind(|| { // SAFETY: read-only CoreGraphics display query; no mode mutation. unsafe { macos_main_display_refresh_hz() } }) { Ok(inner) => inner, Err(_) => Err("error"), } } #[cfg(not(target_os = "macos"))] fn probe_macos() -> Result { Err("unsupported") } #[cfg(target_os = "macos")] unsafe fn macos_main_display_refresh_hz() -> Result { type CgDisplayModeRef = *mut core::ffi::c_void; type CgDirectDisplayId = u32; #[link(name = "CoreGraphics", kind = "framework")] unsafe extern "C" { fn CGMainDisplayID() -> CgDirectDisplayId; fn CGDisplayCopyDisplayMode(display: CgDirectDisplayId) -> CgDisplayModeRef; fn CGDisplayModeGetRefreshRate(mode: CgDisplayModeRef) -> f64; fn CGDisplayModeRelease(mode: CgDisplayModeRef); } // SAFETY: stable public CG APIs; null mode handled; Release pairs with Copy. let display = unsafe { CGMainDisplayID() }; let mode = unsafe { CGDisplayCopyDisplayMode(display) }; if mode.is_null() { return Err("error"); } let rate = unsafe { CGDisplayModeGetRefreshRate(mode) }; unsafe { CGDisplayModeRelease(mode) }; // 0.0 is documented indeterminate for some LCD/VRR panels — skip, not error. // Future primary-display fallback must be thread-safe; no AppKit/NSScreen here. if !rate.is_finite() || rate < 0.0 { return Err("error"); } if rate == 0.0 { return Err("indeterminate"); } Ok(rate.round() as u32) } #[cfg(target_os = "windows")] fn probe_windows() -> Result { match std::panic::catch_unwind(|| { // SAFETY: read-only EnumDisplayDevices/Settings for primary only. unsafe { windows_primary_display_refresh_hz() } }) { Ok(inner) => inner, Err(_) => Err("error"), } } #[cfg(not(target_os = "windows"))] fn probe_windows() -> Result { Err("unsupported") } /// Primary monitor Hz (matches macOS `CGMainDisplayID`). Null device name to /// `EnumDisplaySettingsW` is the *current* adapter, which can differ from the /// primary on multi-monitor machines. #[cfg(target_os = "windows")] unsafe fn windows_primary_display_refresh_hz() -> Result { use windows_sys::Win32::Graphics::Gdi::{ DEVMODEW, DISPLAY_DEVICE_PRIMARY_DEVICE, DISPLAY_DEVICEW, ENUM_CURRENT_SETTINGS, EnumDisplayDevicesW, EnumDisplaySettingsW, }; // Bound device enumeration so a broken driver cannot spin forever. for i in 0u32..32 { // SAFETY: zeroed DISPLAY_DEVICEW with cb set is the documented pattern. let mut device: DISPLAY_DEVICEW = unsafe { std::mem::zeroed() }; device.cb = std::mem::size_of::() as u32; // SAFETY: null parent = desktop adapters; i indexes adapters. let ok = unsafe { EnumDisplayDevicesW(std::ptr::null(), i, &mut device, 0) }; if ok == 0 { break; } if device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE == 0 { continue; } // SAFETY: zeroed DEVMODEW with dmSize set; DeviceName is the primary. let mut devmode: DEVMODEW = unsafe { std::mem::zeroed() }; devmode.dmSize = std::mem::size_of::() as u16; let ok = unsafe { EnumDisplaySettingsW( device.DeviceName.as_ptr(), ENUM_CURRENT_SETTINGS, &mut devmode, ) }; if ok == 0 { return Err("error"); } let hz = devmode.dmDisplayFrequency; // 0/1 often mean "default hardware rate" — fail closed. if hz < 2 { return Err("error"); } return Ok(hz); } Err("error") } #[cfg(test)] mod tests { use super::*; /// Real OS path smoke: must not panic (FFI wrapped + fail-closed). /// Outcome may be ok/skipped/error depending on host; we only require /// process survival and a valid outcome token. #[test] fn probe_display_refresh_never_panics() { let r = probe_display_refresh(); assert!( matches!(r.outcome(), "ok" | "skipped" | "error"), "unexpected outcome {:?}", r.outcome() ); if let Some(hz) = r.hz { assert!((MIN_HZ..=MAX_HZ).contains(&hz), "hz out of bounds: {hz}"); assert_eq!(r.outcome(), "ok"); assert!(r.skip_reason.is_empty()); } else { assert!(!r.skip_reason.is_empty() || r.outcome() == "error"); } // Second call hits OnceLock — still must not panic. let r2 = probe_display_refresh(); assert_eq!(r.hz, r2.hz); assert_eq!(r.outcome(), r2.outcome()); } #[test] fn ssh_skips_before_platform() { let (hz, source, reason) = decide( true, false, HostOs::Macos, DisplayServer::Unknown, Some(Ok(120)), ); assert_eq!(hz, None); assert_eq!(source, DisplayRefreshSource::None); assert_eq!(reason, "ssh"); } #[test] fn wsl_skips() { let (hz, source, reason) = decide(false, true, HostOs::Linux, DisplayServer::X11, Some(Ok(60))); assert_eq!(hz, None); assert_eq!(source, DisplayRefreshSource::None); assert_eq!(reason, "wsl"); } #[test] fn linux_wayland_unsupported() { let (hz, source, reason) = decide(false, false, HostOs::Linux, DisplayServer::Wayland, None); assert_eq!(hz, None); assert_eq!(source, DisplayRefreshSource::Linux); assert_eq!(reason, "wayland_unsupported"); } #[test] fn linux_x11_unsupported() { let (hz, source, reason) = decide(false, false, HostOs::Linux, DisplayServer::X11, None); assert_eq!(hz, None); assert_eq!(source, DisplayRefreshSource::Linux); assert_eq!(reason, "x11_unsupported"); } #[test] fn linux_no_display() { let (hz, source, reason) = decide(false, false, HostOs::Linux, DisplayServer::Unknown, None); assert_eq!(hz, None); assert_eq!(source, DisplayRefreshSource::Linux); assert_eq!(reason, "no_display"); } #[test] fn host_os_other_unsupported() { let (hz, source, reason) = decide(false, false, HostOs::Other, DisplayServer::Unknown, None); assert_eq!(hz, None); assert_eq!(source, DisplayRefreshSource::None); assert_eq!(reason, "unsupported"); } #[test] fn out_of_range_low() { let (hz, source, reason) = decide( false, false, HostOs::Macos, DisplayServer::Unknown, Some(Ok(15)), ); assert_eq!(hz, None); assert_eq!(source, DisplayRefreshSource::MacosCoreGraphics); assert_eq!(reason, "out_of_range"); } #[test] fn out_of_range_high() { let (hz, source, reason) = decide( false, false, HostOs::Windows, DisplayServer::Unknown, Some(Ok(1000)), ); assert_eq!(hz, None); assert_eq!(source, DisplayRefreshSource::WindowsEnumDisplaySettings); assert_eq!(reason, "out_of_range"); } #[test] fn ok_120_macos() { let (hz, source, reason) = decide( false, false, HostOs::Macos, DisplayServer::Unknown, Some(Ok(120)), ); assert_eq!(hz, Some(120)); assert_eq!(source, DisplayRefreshSource::MacosCoreGraphics); assert_eq!(reason, ""); } #[test] fn ok_144_windows() { let (hz, source, reason) = decide( false, false, HostOs::Windows, DisplayServer::Unknown, Some(Ok(144)), ); assert_eq!(hz, Some(144)); assert_eq!(source, DisplayRefreshSource::WindowsEnumDisplaySettings); assert_eq!(reason, ""); } #[test] fn backend_error() { let (hz, source, reason) = decide( false, false, HostOs::Macos, DisplayServer::Unknown, Some(Err("error")), ); assert_eq!(hz, None); assert_eq!(source, DisplayRefreshSource::MacosCoreGraphics); assert_eq!(reason, "error"); } #[test] fn indeterminate_is_skipped_not_error() { let (hz, source, reason) = decide( false, false, HostOs::Macos, DisplayServer::Unknown, Some(Err("indeterminate")), ); assert_eq!( (hz, source, reason), ( None, DisplayRefreshSource::MacosCoreGraphics, "indeterminate" ) ); assert_eq!( DisplayRefreshProbeResult { hz: None, source, skip_reason: reason, duration_ms: 0, } .outcome(), "skipped" ); } #[test] fn missing_platform_hz_is_error() { let (hz, source, reason) = decide(false, false, HostOs::Macos, DisplayServer::Unknown, None); assert_eq!(hz, None); assert_eq!(source, DisplayRefreshSource::MacosCoreGraphics); assert_eq!(reason, "error"); } #[test] fn boundary_hz_accepted() { for hz_in in [30u32, 500] { let (hz, _, reason) = decide( false, false, HostOs::Macos, DisplayServer::Unknown, Some(Ok(hz_in)), ); assert_eq!(hz, Some(hz_in)); assert_eq!(reason, ""); } } #[test] fn source_strum_snake_case_stable() { assert_eq!(DisplayRefreshSource::None.as_ref(), "none"); assert_eq!( DisplayRefreshSource::MacosCoreGraphics.as_ref(), "macos_core_graphics" ); assert_eq!( DisplayRefreshSource::WindowsEnumDisplaySettings.as_ref(), "windows_enum_display_settings" ); assert_eq!(DisplayRefreshSource::Linux.as_ref(), "linux"); assert_eq!(DisplayRefreshSource::Linux.to_string(), "linux"); } #[test] fn outcome_tokens() { let ok = DisplayRefreshProbeResult { hz: Some(120), source: DisplayRefreshSource::MacosCoreGraphics, skip_reason: "", duration_ms: 1, }; assert_eq!(ok.outcome(), "ok"); let skipped = DisplayRefreshProbeResult { hz: None, source: DisplayRefreshSource::None, skip_reason: "ssh", duration_ms: 0, }; assert_eq!(skipped.outcome(), "skipped"); let err = DisplayRefreshProbeResult { hz: None, source: DisplayRefreshSource::MacosCoreGraphics, skip_reason: "error", duration_ms: 2, }; assert_eq!(err.outcome(), "error"); } }