From b421ffafb57f9a62bf65167fd6a023f32716b720 Mon Sep 17 00:00:00 2001 From: Gowtham K <73059450+dovakin0007@users.noreply.github.com> Date: Sat, 16 Nov 2024 16:54:30 +0530 Subject: [PATCH] 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> --- crates/gpui/src/platform/windows/window.rs | 97 +++++++++++++++++++++- 1 file changed, 94 insertions(+), 3 deletions(-) diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 46b54e689d..f2600d3c6f 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -647,11 +647,47 @@ impl PlatformWindow for WindowsWindow { } fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) { - self.0 - .state - .borrow_mut() + let mut window_state = self.0.state.borrow_mut(); + window_state .renderer .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) { @@ -932,6 +968,23 @@ struct StyleAndBounds { 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)] pub(crate) struct WindowBorderOffset { width_offset: i32, @@ -1136,6 +1189,44 @@ fn retrieve_window_placement( Ok(placement) } +fn set_window_composition_attribute(hwnd: HWND, color: Option, 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::(), + }; + 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 { use std::{num::NonZeroIsize, sync::Arc};