use std::sync::OnceLock; use ::util::ResultExt; use windows::{ UI::{ Color, ViewManagement::{UIColorType, UISettings}, }, Wdk::System::SystemServices::RtlGetVersion, Win32::{Foundation::*, Graphics::Dwm::*, UI::WindowsAndMessaging::*}, core::{BOOL, HSTRING}, }; use crate::*; #[derive(Debug, Clone, Copy)] pub(crate) enum WindowsVersion { Win10, Win11, } impl WindowsVersion { pub(crate) fn new() -> anyhow::Result { let mut version = unsafe { std::mem::zeroed() }; let status = unsafe { RtlGetVersion(&mut version) }; status.ok()?; if version.dwBuildNumber >= 22000 { Ok(WindowsVersion::Win11) } else { Ok(WindowsVersion::Win10) } } } pub(crate) trait HiLoWord { fn hiword(&self) -> u16; fn loword(&self) -> u16; fn signed_hiword(&self) -> i16; fn signed_loword(&self) -> i16; } impl HiLoWord for WPARAM { fn hiword(&self) -> u16 { ((self.0 >> 16) & 0xFFFF) as u16 } fn loword(&self) -> u16 { (self.0 & 0xFFFF) as u16 } fn signed_hiword(&self) -> i16 { ((self.0 >> 16) & 0xFFFF) as i16 } fn signed_loword(&self) -> i16 { (self.0 & 0xFFFF) as i16 } } impl HiLoWord for LPARAM { fn hiword(&self) -> u16 { ((self.0 >> 16) & 0xFFFF) as u16 } fn loword(&self) -> u16 { (self.0 & 0xFFFF) as u16 } fn signed_hiword(&self) -> i16 { ((self.0 >> 16) & 0xFFFF) as i16 } fn signed_loword(&self) -> i16 { (self.0 & 0xFFFF) as i16 } } pub(crate) unsafe fn get_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX) -> isize { #[cfg(target_pointer_width = "64")] unsafe { GetWindowLongPtrW(hwnd, nindex) } #[cfg(target_pointer_width = "32")] unsafe { GetWindowLongW(hwnd, nindex) as isize } } pub(crate) unsafe fn set_window_long( hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX, dwnewlong: isize, ) -> isize { #[cfg(target_pointer_width = "64")] unsafe { SetWindowLongPtrW(hwnd, nindex, dwnewlong) } #[cfg(target_pointer_width = "32")] unsafe { SetWindowLongW(hwnd, nindex, dwnewlong as i32) as isize } } pub(crate) fn windows_credentials_target_name(url: &str) -> String { format!("zed:url={}", url) } pub(crate) fn load_cursor(style: CursorStyle) -> Option { static ARROW: OnceLock = OnceLock::new(); static IBEAM: OnceLock = OnceLock::new(); static CROSS: OnceLock = OnceLock::new(); static HAND: OnceLock = OnceLock::new(); static SIZEWE: OnceLock = OnceLock::new(); static SIZENS: OnceLock = OnceLock::new(); static NO: OnceLock = OnceLock::new(); let (lock, name) = match style { CursorStyle::IBeam | CursorStyle::IBeamCursorForVerticalLayout => (&IBEAM, IDC_IBEAM), CursorStyle::Crosshair => (&CROSS, IDC_CROSS), CursorStyle::PointingHand | CursorStyle::DragLink => (&HAND, IDC_HAND), CursorStyle::ResizeLeft | CursorStyle::ResizeRight | CursorStyle::ResizeLeftRight | CursorStyle::ResizeColumn => (&SIZEWE, IDC_SIZEWE), CursorStyle::ResizeUp | CursorStyle::ResizeDown | CursorStyle::ResizeUpDown | CursorStyle::ResizeRow => (&SIZENS, IDC_SIZENS), CursorStyle::OperationNotAllowed => (&NO, IDC_NO), CursorStyle::None => return None, _ => (&ARROW, IDC_ARROW), }; Some( *(*lock.get_or_init(|| { HCURSOR( unsafe { LoadImageW(None, name, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) } .log_err() .unwrap_or_default() .0, ) .into() })), ) } /// This function is used to configure the dark mode for the window built-in title bar. pub(crate) fn configure_dwm_dark_mode(hwnd: HWND, appearance: WindowAppearance) { let dark_mode_enabled: BOOL = match appearance { WindowAppearance::Dark | WindowAppearance::VibrantDark => true.into(), WindowAppearance::Light | WindowAppearance::VibrantLight => false.into(), }; unsafe { DwmSetWindowAttribute( hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark_mode_enabled as *const _ as _, std::mem::size_of::() as u32, ) .log_err(); } } #[inline] pub(crate) fn logical_point(x: f32, y: f32, scale_factor: f32) -> Point { Point { x: px(x / scale_factor), y: px(y / scale_factor), } } // https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/apply-windows-themes #[inline] pub(crate) fn system_appearance() -> Result { let ui_settings = UISettings::new()?; let foreground_color = ui_settings.GetColorValue(UIColorType::Foreground)?; // If the foreground is light, then is_color_light will evaluate to true, // meaning Dark mode is enabled. if is_color_light(&foreground_color) { Ok(WindowAppearance::Dark) } else { Ok(WindowAppearance::Light) } } #[inline(always)] fn is_color_light(color: &Color) -> bool { ((5 * color.G as u32) + (2 * color.R as u32) + color.B as u32) > (8 * 128) } pub(crate) fn show_error(title: &str, content: String) { let _ = unsafe { MessageBoxW( None, &HSTRING::from(content), &HSTRING::from(title), MB_ICONERROR | MB_SYSTEMMODAL, ) }; }