From 98d3391f2d53260b0b432926e200a4a6186dedbe Mon Sep 17 00:00:00 2001 From: Dubzer Date: Thu, 25 Jan 2024 20:59:10 +0300 Subject: [PATCH] Add DWMWA_SYSTEMBACKDROP_TYPE support on Windows (#3257) --- CHANGELOG.md | 2 +- FEATURES.md | 1 + src/platform/windows.rs | 53 +++++++++++++++++++++++++++++ src/platform_impl/windows/mod.rs | 4 ++- src/platform_impl/windows/window.rs | 21 ++++++++++-- 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 260b747bf5..01fd3ebb78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ Unreleased` header. - Add the `OwnedDisplayHandle` type for allowing safe display handle usage outside of trivial cases. - **Breaking:** Rename `TouchpadMagnify` to `PinchGesture`, `SmartMagnify` to `DoubleTapGesture` and `TouchpadRotate` to `RotationGesture` to represent the action rather than the intent. - on iOS, add detection support for `PinchGesture`, `DoubleTapGesture` and `RotationGesture`. -- on Windows: add `with_border_color`, `with_title_background_color`, `with_title_text_color` and `with_corner_preference` +- on Windows: add `with_system_backdrop`, `with_border_color`, `with_title_background_color`, `with_title_text_color` and `with_corner_preference` - On Windows, Remove `WS_CAPTION`, `WS_BORDER` and `WS_EX_WINDOWEDGE` styles for child windows without decorations. - On Windows, fixed a race condition when sending an event through the loop proxy. diff --git a/FEATURES.md b/FEATURES.md index f8f53fd98c..2819b48ec0 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -126,6 +126,7 @@ If your PR makes notable changes to Winit's features, please update this section * Setting a menu bar * `WS_EX_NOREDIRECTIONBITMAP` support * Theme the title bar according to Windows 10 Dark Mode setting or set a preferred theme +* Changing a system-drawn backdrop * Setting the window border color * Setting the title bar background color * Setting the title color diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 0a9d251adc..cbf9699ca8 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -15,6 +15,38 @@ pub type HMENU = isize; /// Monitor Handle type used by Win32 API pub type HMONITOR = isize; +/// Describes a system-drawn backdrop material of a window. +/// +/// For a detailed explanation, see [`DWM_SYSTEMBACKDROP_TYPE docs`]. +/// +/// [`DWM_SYSTEMBACKDROP_TYPE docs`]: https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +pub enum BackdropType { + /// Corresponds to `DWMSBT_AUTO`. + /// + /// Usually draws a default backdrop effect on the title bar. + #[default] + Auto = 0, + + /// Corresponds to `DWMSBT_NONE`. + None = 1, + + /// Corresponds to `DWMSBT_MAINWINDOW`. + /// + /// Draws the Mica backdrop material. + MainWindow = 2, + + /// Corresponds to `DWMSBT_TRANSIENTWINDOW`. + /// + /// Draws the Background Acrylic backdrop material. + TransientWindow = 3, + + /// Corresponds to `DWMSBT_TABBEDWINDOW`. + /// + /// Draws the Alt Mica backdrop material. + TabbedWindow = 4, +} + /// Describes a color used by Windows #[repr(transparent)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -188,6 +220,11 @@ pub trait WindowExtWindows { /// Enabling the shadow causes a thin 1px line to appear on the top of the window. fn set_undecorated_shadow(&self, shadow: bool); + /// Sets system-drawn backdrop type. + /// + /// Requires Windows 11 build 22523+. + fn set_system_backdrop(&self, backdrop_type: BackdropType); + /// Sets the color of the window border. /// /// Supported starting with Windows 11 Build 22000. @@ -230,6 +267,11 @@ impl WindowExtWindows for Window { self.window.set_undecorated_shadow(shadow) } + #[inline] + fn set_system_backdrop(&self, backdrop_type: BackdropType) { + self.window.set_system_backdrop(backdrop_type) + } + #[inline] fn set_border_color(&self, color: Option) { self.window.set_border_color(color.unwrap_or(Color::NONE)) @@ -315,6 +357,11 @@ pub trait WindowBuilderExtWindows { /// Enabling the shadow causes a thin 1px line to appear on the top of the window. fn with_undecorated_shadow(self, shadow: bool) -> Self; + /// Sets system-drawn backdrop type. + /// + /// Requires Windows 11 build 22523+. + fn with_system_backdrop(self, backdrop_type: BackdropType) -> Self; + /// This sets or removes `WS_CLIPCHILDREN` style. fn with_clip_children(self, flag: bool) -> Self; @@ -388,6 +435,12 @@ impl WindowBuilderExtWindows for WindowBuilder { self } + #[inline] + fn with_system_backdrop(mut self, backdrop_type: BackdropType) -> Self { + self.window.platform_specific.backdrop_type = backdrop_type; + self + } + #[inline] fn with_clip_children(mut self, flag: bool) -> Self { self.window.platform_specific.clip_children = flag; diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 13b861de65..8f1f33512a 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -25,7 +25,7 @@ use crate::platform_impl::Fullscreen; use crate::event::DeviceId as RootDeviceId; use crate::icon::Icon; use crate::keyboard::Key; -use crate::platform::windows::{Color, CornerPreference}; +use crate::platform::windows::{BackdropType, Color, CornerPreference}; #[derive(Clone, Debug)] pub struct PlatformSpecificWindowBuilderAttributes { @@ -37,6 +37,7 @@ pub struct PlatformSpecificWindowBuilderAttributes { pub skip_taskbar: bool, pub class_name: String, pub decoration_shadow: bool, + pub backdrop_type: BackdropType, pub clip_children: bool, pub border_color: Option, pub title_background_color: Option, @@ -55,6 +56,7 @@ impl Default for PlatformSpecificWindowBuilderAttributes { skip_taskbar: false, class_name: "Window Class".to_string(), decoration_shadow: false, + backdrop_type: BackdropType::default(), clip_children: true, border_color: None, title_background_color: None, diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 7a77ae8152..546128cc23 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -16,8 +16,9 @@ use windows_sys::Win32::{ Graphics::{ Dwm::{ DwmEnableBlurBehindWindow, DwmSetWindowAttribute, DWMWA_BORDER_COLOR, - DWMWA_CAPTION_COLOR, DWMWA_TEXT_COLOR, DWMWA_WINDOW_CORNER_PREFERENCE, - DWM_BB_BLURREGION, DWM_BB_ENABLE, DWM_BLURBEHIND, DWM_WINDOW_CORNER_PREFERENCE, + DWMWA_CAPTION_COLOR, DWMWA_SYSTEMBACKDROP_TYPE, DWMWA_TEXT_COLOR, + DWMWA_WINDOW_CORNER_PREFERENCE, DWM_BB_BLURREGION, DWM_BB_ENABLE, DWM_BLURBEHIND, + DWM_SYSTEMBACKDROP_TYPE, DWM_WINDOW_CORNER_PREFERENCE, }, Gdi::{ ChangeDisplaySettingsExW, ClientToScreen, CreateRectRgn, DeleteObject, InvalidateRgn, @@ -60,12 +61,12 @@ use windows_sys::Win32::{ use log::warn; -use crate::platform::windows::{Color, CornerPreference}; use crate::{ cursor::Cursor, dpi::{PhysicalPosition, PhysicalSize, Position, Size}, error::{ExternalError, NotSupportedError, OsError as RootOsError}, icon::Icon, + platform::windows::{BackdropType, Color, CornerPreference}, platform_impl::platform::{ dark_mode::try_theme, definitions::{ @@ -1019,6 +1020,18 @@ impl Window { }); } + #[inline] + pub fn set_system_backdrop(&self, backdrop_type: BackdropType) { + unsafe { + DwmSetWindowAttribute( + self.hwnd(), + DWMWA_SYSTEMBACKDROP_TYPE, + &(backdrop_type as i32) as *const _ as _, + mem::size_of::() as _, + ); + } + } + #[inline] pub fn focus_window(&self) { let window_flags = self.window_state_lock().window_flags(); @@ -1308,6 +1321,8 @@ impl<'a> InitData<'a> { win.set_outer_position(position); } + win.set_system_backdrop(self.attributes.platform_specific.backdrop_type); + if let Some(color) = self.attributes.platform_specific.border_color { win.set_border_color(color); }