Windows: Add transparency effect (#20400)

Release Notes:

- Added Transparency effect for Windows #19405 


![image](https://github.com/user-attachments/assets/b0750020-5a89-48c9-b26e-13b30874cf8d)


![image](https://github.com/user-attachments/assets/80609a14-b8c3-4159-b909-1e61f4c3eac3)

---------

Co-authored-by: thedeveloper-sharath <35845141+thedeveloper-sharath@users.noreply.github.com>
This commit is contained in:
Gowtham K 2024-11-16 16:54:30 +05:30 committed by GitHub
parent 21c785ede4
commit b421ffafb5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -647,11 +647,47 @@ impl PlatformWindow for WindowsWindow {
} }
fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) { fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
self.0 let mut window_state = self.0.state.borrow_mut();
.state window_state
.borrow_mut()
.renderer .renderer
.update_transparency(background_appearance != WindowBackgroundAppearance::Opaque); .update_transparency(background_appearance != WindowBackgroundAppearance::Opaque);
let mut version = unsafe { std::mem::zeroed() };
let status = unsafe { windows::Wdk::System::SystemServices::RtlGetVersion(&mut version) };
if status.is_ok() {
if background_appearance == WindowBackgroundAppearance::Blurred {
if version.dwBuildNumber >= 17763 {
set_window_composition_attribute(window_state.hwnd, Some((0, 0, 0, 10)), 4);
}
} else {
if version.dwBuildNumber >= 17763 {
set_window_composition_attribute(window_state.hwnd, None, 0);
}
}
//Transparent effect might cause some flickering and performance issues due `WS_EX_COMPOSITED` is enabled
//if `WS_EX_COMPOSITED` is removed the window instance won't initiate
if background_appearance == WindowBackgroundAppearance::Transparent {
unsafe {
let current_style = GetWindowLongW(window_state.hwnd, GWL_EXSTYLE);
SetWindowLongW(
window_state.hwnd,
GWL_EXSTYLE,
current_style | WS_EX_LAYERED.0 as i32 | WS_EX_COMPOSITED.0 as i32,
);
SetLayeredWindowAttributes(window_state.hwnd, COLORREF(0), 225, LWA_ALPHA)
.inspect_err(|e| log::error!("Unable to set window to transparent: {e}"))
.ok();
};
} else {
unsafe {
let current_style = GetWindowLongW(window_state.hwnd, GWL_EXSTYLE);
SetWindowLongW(
window_state.hwnd,
GWL_EXSTYLE,
current_style & !WS_EX_LAYERED.0 as i32 & !WS_EX_COMPOSITED.0 as i32,
);
}
}
}
} }
fn minimize(&self) { fn minimize(&self) {
@ -932,6 +968,23 @@ struct StyleAndBounds {
cy: i32, cy: i32,
} }
#[repr(C)]
struct WINDOWCOMPOSITIONATTRIBDATA {
attrib: u32,
pv_data: *mut std::ffi::c_void,
cb_data: usize,
}
#[repr(C)]
struct AccentPolicy {
accent_state: u32,
accent_flags: u32,
gradient_color: u32,
animation_id: u32,
}
type Color = (u8, u8, u8, u8);
#[derive(Debug, Default, Clone, Copy)] #[derive(Debug, Default, Clone, Copy)]
pub(crate) struct WindowBorderOffset { pub(crate) struct WindowBorderOffset {
width_offset: i32, width_offset: i32,
@ -1136,6 +1189,44 @@ fn retrieve_window_placement(
Ok(placement) Ok(placement)
} }
fn set_window_composition_attribute(hwnd: HWND, color: Option<Color>, state: u32) {
unsafe {
type SetWindowCompositionAttributeType =
unsafe extern "system" fn(HWND, *mut WINDOWCOMPOSITIONATTRIBDATA) -> BOOL;
let module_name = PCSTR::from_raw("user32.dll\0".as_ptr());
let user32 = GetModuleHandleA(module_name);
if user32.is_ok() {
let func_name = PCSTR::from_raw("SetWindowCompositionAttribute\0".as_ptr());
let set_window_composition_attribute: SetWindowCompositionAttributeType =
std::mem::transmute(GetProcAddress(user32.unwrap(), func_name));
let mut color = color.unwrap_or_default();
let is_acrylic = state == 4;
if is_acrylic && color.3 == 0 {
color.3 = 1;
}
let accent = AccentPolicy {
accent_state: state,
accent_flags: if is_acrylic { 0 } else { 2 },
gradient_color: (color.0 as u32)
| ((color.1 as u32) << 8)
| ((color.2 as u32) << 16)
| (color.3 as u32) << 24,
animation_id: 0,
};
let mut data = WINDOWCOMPOSITIONATTRIBDATA {
attrib: 0x13,
pv_data: &accent as *const _ as *mut _,
cb_data: std::mem::size_of::<AccentPolicy>(),
};
let _ = set_window_composition_attribute(hwnd, &mut data as *mut _ as _);
} else {
let _ = user32
.inspect_err(|e| log::error!("Error getting module: {e}"))
.ok();
}
}
}
mod windows_renderer { mod windows_renderer {
use std::{num::NonZeroIsize, sync::Arc}; use std::{num::NonZeroIsize, sync::Arc};