On Windows, expose DWM attributes (#3409)
This commit is contained in:
parent
d7c7ba1d6c
commit
b0c59c8416
5 changed files with 222 additions and 1 deletions
|
|
@ -33,6 +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`
|
||||
|
||||
# 0.29.10
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,10 @@ 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
|
||||
* Setting the window border color
|
||||
* Setting the title bar background color
|
||||
* Setting the title color
|
||||
* Setting the corner rounding preference
|
||||
|
||||
### macOS
|
||||
* Window activation policy
|
||||
|
|
|
|||
|
|
@ -15,6 +15,60 @@ pub type HMENU = isize;
|
|||
/// Monitor Handle type used by Win32 API
|
||||
pub type HMONITOR = isize;
|
||||
|
||||
/// Describes a color used by Windows
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Color(u32);
|
||||
|
||||
impl Color {
|
||||
/// Use the system's default color
|
||||
pub const SYSTEM_DEFAULT: Color = Color(0xFFFFFFFF);
|
||||
|
||||
//Special constant only valid for the window border and therefore modeled using Option<Color> for user facing code
|
||||
const NONE: Color = Color(0xFFFFFFFE);
|
||||
|
||||
/// Create a new color from the given RGB values
|
||||
pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
|
||||
Self((r as u32) | ((g as u32) << 8) | ((b as u32) << 16))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Color {
|
||||
fn default() -> Self {
|
||||
Self::SYSTEM_DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes how the corners of a window should look like.
|
||||
///
|
||||
/// For a detailed explanation, see [`DWM_WINDOW_CORNER_PREFERENCE docs`].
|
||||
///
|
||||
/// [`DWM_WINDOW_CORNER_PREFERENCE docs`]: https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_window_corner_preference
|
||||
#[repr(i32)]
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum CornerPreference {
|
||||
/// Corresponds to `DWMWCP_DEFAULT`.
|
||||
///
|
||||
/// Let the system decide when to round window corners.
|
||||
#[default]
|
||||
Default = 0,
|
||||
|
||||
/// Corresponds to `DWMWCP_DONOTROUND`.
|
||||
///
|
||||
/// Never round window corners.
|
||||
DoNotRound = 1,
|
||||
|
||||
/// Corresponds to `DWMWCP_ROUND`.
|
||||
///
|
||||
/// Round the corners, if appropriate.
|
||||
Round = 2,
|
||||
|
||||
/// Corresponds to `DWMWCP_ROUNDSMALL`.
|
||||
///
|
||||
/// Round the corners if appropriate, with a small radius.
|
||||
RoundSmall = 3,
|
||||
}
|
||||
|
||||
/// Additional methods on `EventLoop` that are specific to Windows.
|
||||
pub trait EventLoopBuilderExtWindows {
|
||||
/// Whether to allow the event loop to be created off of the main thread.
|
||||
|
|
@ -133,6 +187,26 @@ 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 the color of the window border.
|
||||
///
|
||||
/// Supported starting with Windows 11 Build 22000.
|
||||
fn set_border_color(&self, color: Option<Color>);
|
||||
|
||||
/// Sets the background color of the title bar.
|
||||
///
|
||||
/// Supported starting with Windows 11 Build 22000.
|
||||
fn set_title_background_color(&self, color: Option<Color>);
|
||||
|
||||
/// Sets the color of the window title.
|
||||
///
|
||||
/// Supported starting with Windows 11 Build 22000.
|
||||
fn set_title_text_color(&self, color: Color);
|
||||
|
||||
/// Sets the preferred style of the window corners.
|
||||
///
|
||||
/// Supported starting with Windows 11 Build 22000.
|
||||
fn set_corner_preference(&self, preference: CornerPreference);
|
||||
}
|
||||
|
||||
impl WindowExtWindows for Window {
|
||||
|
|
@ -155,6 +229,29 @@ impl WindowExtWindows for Window {
|
|||
fn set_undecorated_shadow(&self, shadow: bool) {
|
||||
self.window.set_undecorated_shadow(shadow)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_border_color(&self, color: Option<Color>) {
|
||||
self.window.set_border_color(color.unwrap_or(Color::NONE))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_title_background_color(&self, color: Option<Color>) {
|
||||
// The windows docs don't mention NONE as a valid options but it works in practice and is useful
|
||||
// to circumvent the Windows option "Show accent color on title bars and window borders"
|
||||
self.window
|
||||
.set_title_background_color(color.unwrap_or(Color::NONE))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_title_text_color(&self, color: Color) {
|
||||
self.window.set_title_text_color(color)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_corner_preference(&self, preference: CornerPreference) {
|
||||
self.window.set_corner_preference(preference)
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional methods on `WindowBuilder` that are specific to Windows.
|
||||
|
|
@ -217,6 +314,26 @@ pub trait WindowBuilderExtWindows {
|
|||
/// The shadow is hidden by default.
|
||||
/// 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 the color of the window border.
|
||||
///
|
||||
/// Supported starting with Windows 11 Build 22000.
|
||||
fn with_border_color(self, color: Option<Color>) -> Self;
|
||||
|
||||
/// Sets the background color of the title bar.
|
||||
///
|
||||
/// Supported starting with Windows 11 Build 22000.
|
||||
fn with_title_background_color(self, color: Option<Color>) -> Self;
|
||||
|
||||
/// Sets the color of the window title.
|
||||
///
|
||||
/// Supported starting with Windows 11 Build 22000.
|
||||
fn with_title_text_color(self, color: Color) -> Self;
|
||||
|
||||
/// Sets the preferred style of the window corners.
|
||||
///
|
||||
/// Supported starting with Windows 11 Build 22000.
|
||||
fn with_corner_preference(self, corners: CornerPreference) -> Self;
|
||||
}
|
||||
|
||||
impl WindowBuilderExtWindows for WindowBuilder {
|
||||
|
|
@ -267,6 +384,30 @@ impl WindowBuilderExtWindows for WindowBuilder {
|
|||
self.window.platform_specific.decoration_shadow = shadow;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_border_color(mut self, color: Option<Color>) -> Self {
|
||||
self.window.platform_specific.border_color = Some(color.unwrap_or(Color::NONE));
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_title_background_color(mut self, color: Option<Color>) -> Self {
|
||||
self.window.platform_specific.title_background_color = Some(color.unwrap_or(Color::NONE));
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_title_text_color(mut self, color: Color) -> Self {
|
||||
self.window.platform_specific.title_text_color = Some(color);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_corner_preference(mut self, corners: CornerPreference) -> Self {
|
||||
self.window.platform_specific.corner_preference = Some(corners);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional methods on `MonitorHandle` that are specific to Windows.
|
||||
|
|
|
|||
|
|
@ -25,6 +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};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PlatformSpecificWindowBuilderAttributes {
|
||||
|
|
@ -36,6 +37,10 @@ pub struct PlatformSpecificWindowBuilderAttributes {
|
|||
pub skip_taskbar: bool,
|
||||
pub class_name: String,
|
||||
pub decoration_shadow: bool,
|
||||
pub border_color: Option<Color>,
|
||||
pub title_background_color: Option<Color>,
|
||||
pub title_text_color: Option<Color>,
|
||||
pub corner_preference: Option<CornerPreference>,
|
||||
}
|
||||
|
||||
impl Default for PlatformSpecificWindowBuilderAttributes {
|
||||
|
|
@ -49,6 +54,10 @@ impl Default for PlatformSpecificWindowBuilderAttributes {
|
|||
skip_taskbar: false,
|
||||
class_name: "Window Class".to_string(),
|
||||
decoration_shadow: false,
|
||||
border_color: None,
|
||||
title_background_color: None,
|
||||
title_text_color: None,
|
||||
corner_preference: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,11 @@ use windows_sys::Win32::{
|
|||
HWND, LPARAM, OLE_E_WRONGCOMPOBJ, POINT, POINTS, RECT, RPC_E_CHANGED_MODE, S_OK, WPARAM,
|
||||
},
|
||||
Graphics::{
|
||||
Dwm::{DwmEnableBlurBehindWindow, DWM_BB_BLURREGION, DWM_BB_ENABLE, DWM_BLURBEHIND},
|
||||
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,
|
||||
},
|
||||
Gdi::{
|
||||
ChangeDisplaySettingsExW, ClientToScreen, CreateRectRgn, DeleteObject, InvalidateRgn,
|
||||
RedrawWindow, CDS_FULLSCREEN, DISP_CHANGE_BADFLAGS, DISP_CHANGE_BADMODE,
|
||||
|
|
@ -56,6 +60,7 @@ use windows_sys::Win32::{
|
|||
|
||||
use log::warn;
|
||||
|
||||
use crate::platform::windows::{Color, CornerPreference};
|
||||
use crate::{
|
||||
cursor::Cursor,
|
||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||
|
|
@ -1060,6 +1065,54 @@ impl Window {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_border_color(&self, color: Color) {
|
||||
unsafe {
|
||||
DwmSetWindowAttribute(
|
||||
self.hwnd(),
|
||||
DWMWA_BORDER_COLOR,
|
||||
&color as *const _ as _,
|
||||
mem::size_of::<Color>() as _,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_title_background_color(&self, color: Color) {
|
||||
unsafe {
|
||||
DwmSetWindowAttribute(
|
||||
self.hwnd(),
|
||||
DWMWA_CAPTION_COLOR,
|
||||
&color as *const _ as _,
|
||||
mem::size_of::<Color>() as _,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_title_text_color(&self, color: Color) {
|
||||
unsafe {
|
||||
DwmSetWindowAttribute(
|
||||
self.hwnd(),
|
||||
DWMWA_TEXT_COLOR,
|
||||
&color as *const _ as _,
|
||||
mem::size_of::<Color>() as _,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_corner_preference(&self, preference: CornerPreference) {
|
||||
unsafe {
|
||||
DwmSetWindowAttribute(
|
||||
self.hwnd(),
|
||||
DWMWA_WINDOW_CORNER_PREFERENCE,
|
||||
&(preference as DWM_WINDOW_CORNER_PREFERENCE) as *const _ as _,
|
||||
mem::size_of::<DWM_WINDOW_CORNER_PREFERENCE>() as _,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Window {
|
||||
|
|
@ -1265,6 +1318,19 @@ impl<'a> InitData<'a> {
|
|||
if let Some(position) = attributes.position {
|
||||
win.set_outer_position(position);
|
||||
}
|
||||
|
||||
if let Some(color) = self.attributes.platform_specific.border_color {
|
||||
win.set_border_color(color);
|
||||
}
|
||||
if let Some(color) = self.attributes.platform_specific.title_background_color {
|
||||
win.set_title_background_color(color);
|
||||
}
|
||||
if let Some(color) = self.attributes.platform_specific.title_text_color {
|
||||
win.set_title_text_color(color);
|
||||
}
|
||||
if let Some(corner) = self.attributes.platform_specific.corner_preference {
|
||||
win.set_corner_preference(corner);
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn init(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue