From d7cb0ebf05ea467b696a19ab3cfe28a709b6ac2e Mon Sep 17 00:00:00 2001 From: Ranieri Althoff Date: Fri, 27 Jun 2025 05:06:46 +0200 Subject: [PATCH] Implement blur with wayland background effect protocol --- Cargo.lock | 56 ++++++++------- Cargo.toml | 5 ++ rio-window/Cargo.toml | 4 -- .../src/platform_impl/linux/wayland/state.rs | 12 ++-- .../wayland/types/ext_background_effect.rs | 69 ++++++++++++++++++ .../linux/wayland/types/kwin_blur.rs | 70 ------------------- .../platform_impl/linux/wayland/types/mod.rs | 2 +- .../linux/wayland/window/state.rs | 41 ++++++----- 8 files changed, 132 insertions(+), 127 deletions(-) create mode 100644 rio-window/src/platform_impl/linux/wayland/types/ext_background_effect.rs delete mode 100644 rio-window/src/platform_impl/linux/wayland/types/kwin_blur.rs diff --git a/Cargo.lock b/Cargo.lock index fd46401991..841a7da460 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2880,7 +2880,6 @@ dependencies = [ "wayland-backend", "wayland-client", "wayland-protocols", - "wayland-protocols-plasma", "web-sys", "web-time", "windows-sys 0.59.0", @@ -3180,7 +3179,7 @@ dependencies = [ "wayland-cursor", "wayland-protocols", "wayland-protocols-wlr", - "wayland-scanner", + "wayland-scanner 0.31.6 (registry+https://github.com/rust-lang/crates.io-index)", "xkeysym", ] @@ -3230,7 +3229,7 @@ dependencies = [ "wasm-bindgen", "wayland-backend", "wayland-client", - "wayland-sys", + "wayland-sys 0.31.6 (registry+https://github.com/rust-lang/crates.io-index)", "web-sys", "windows-sys 0.59.0", "x11rb", @@ -3934,27 +3933,25 @@ dependencies = [ [[package]] name = "wayland-backend" version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121" +source = "git+https://github.com/Smithay/wayland-rs.git?rev=9de018a#9de018aad9e75f2d7b03b152520877a6431c1231" dependencies = [ "cc", "downcast-rs", - "rustix 0.38.44", + "rustix 1.0.7", "scoped-tls", "smallvec", - "wayland-sys", + "wayland-sys 0.31.6 (git+https://github.com/Smithay/wayland-rs.git?rev=9de018a)", ] [[package]] name = "wayland-client" version = "0.31.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" +source = "git+https://github.com/Smithay/wayland-rs.git?rev=9de018a#9de018aad9e75f2d7b03b152520877a6431c1231" dependencies = [ "bitflags 2.9.1", - "rustix 0.38.44", + "rustix 1.0.7", "wayland-backend", - "wayland-scanner", + "wayland-scanner 0.31.6 (git+https://github.com/Smithay/wayland-rs.git?rev=9de018a)", ] [[package]] @@ -3982,46 +3979,42 @@ dependencies = [ [[package]] name = "wayland-protocols" version = "0.32.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a" +source = "git+https://github.com/Smithay/wayland-rs.git?rev=9de018a#9de018aad9e75f2d7b03b152520877a6431c1231" dependencies = [ "bitflags 2.9.1", "wayland-backend", "wayland-client", - "wayland-scanner", + "wayland-scanner 0.31.6 (git+https://github.com/Smithay/wayland-rs.git?rev=9de018a)", ] [[package]] -name = "wayland-protocols-plasma" +name = "wayland-protocols-wlr" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fd38cdad69b56ace413c6bcc1fbf5acc5e2ef4af9d5f8f1f9570c0c83eae175" +checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf" dependencies = [ "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", - "wayland-scanner", + "wayland-scanner 0.31.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "wayland-protocols-wlr" -version = "0.3.8" +name = "wayland-scanner" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf" +checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" dependencies = [ - "bitflags 2.9.1", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-scanner", + "proc-macro2", + "quick-xml", + "quote", ] [[package]] name = "wayland-scanner" version = "0.31.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" +source = "git+https://github.com/Smithay/wayland-rs.git?rev=9de018a#9de018aad9e75f2d7b03b152520877a6431c1231" dependencies = [ "proc-macro2", "quick-xml", @@ -4033,6 +4026,15 @@ name = "wayland-sys" version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" +dependencies = [ + "once_cell", + "pkg-config", +] + +[[package]] +name = "wayland-sys" +version = "0.31.6" +source = "git+https://github.com/Smithay/wayland-rs.git?rev=9de018a#9de018aad9e75f2d7b03b152520877a6431c1231" dependencies = [ "dlib", "log 0.4.27", diff --git a/Cargo.toml b/Cargo.toml index 90c5f41b76..445bc22f77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,3 +90,8 @@ split-debuginfo = "unpacked" lto = false incremental = true opt-level = 0 + +[patch.crates-io] +wayland-backend = { git = "https://github.com/Smithay/wayland-rs.git", rev = "9de018a", optional = true } +wayland-client = { git = "https://github.com/Smithay/wayland-rs.git", rev = "9de018a", optional = true } +wayland-protocols = { git = "https://github.com/Smithay/wayland-rs.git", rev = "9de018a", optional = true } diff --git a/rio-window/Cargo.toml b/rio-window/Cargo.toml index 68a4a4d69a..f2e074a8b7 100644 --- a/rio-window/Cargo.toml +++ b/rio-window/Cargo.toml @@ -20,7 +20,6 @@ wayland = [ "wayland-client", "wayland-backend", "wayland-protocols", - "wayland-protocols-plasma", "sctk", "ahash", "memmap2", @@ -170,9 +169,6 @@ wayland-client = { version = "0.31.10", optional = true } wayland-protocols = { version = "0.32.8", features = [ "staging", ], optional = true } -wayland-protocols-plasma = { version = "0.3.8", features = [ - "client", -], optional = true } x11-dl = { version = "2.19.1", optional = true } x11rb = { version = "0.13.0", default-features = false, features = [ "allow-unsafe-code", diff --git a/rio-window/src/platform_impl/linux/wayland/state.rs b/rio-window/src/platform_impl/linux/wayland/state.rs index ff62406932..8f239ba34c 100644 --- a/rio-window/src/platform_impl/linux/wayland/state.rs +++ b/rio-window/src/platform_impl/linux/wayland/state.rs @@ -29,7 +29,7 @@ use crate::platform_impl::wayland::seat::{ PointerConstraintsState, RelativePointerState, TextInputState, WinitPointerData, WinitPointerDataExt, WinitSeatState, }; -use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager; +use crate::platform_impl::wayland::types::ext_background_effect::BackgroundEffectManager; use crate::platform_impl::wayland::types::wp_fractional_scaling::FractionalScalingManager; use crate::platform_impl::wayland::types::wp_viewporter::ViewporterState; use crate::platform_impl::wayland::types::xdg_activation::XdgActivationState; @@ -106,8 +106,8 @@ pub struct WinitState { /// Fractional scaling manager. pub fractional_scaling_manager: Option, - /// KWin blur manager. - pub kwin_blur_manager: Option, + /// Background effect manager. + pub background_effect_manager: Option, /// Loop handle to re-register event sources, such as keyboard repeat. pub loop_handle: LoopHandle<'static, Self>, @@ -179,7 +179,11 @@ impl WinitState { window_events_sink: Default::default(), viewporter_state, fractional_scaling_manager, - kwin_blur_manager: KWinBlurManager::new(globals, queue_handle).ok(), + background_effect_manager: BackgroundEffectManager::new( + globals, + queue_handle, + ) + .ok(), seats, text_input_state: TextInputState::new(globals, queue_handle).ok(), diff --git a/rio-window/src/platform_impl/linux/wayland/types/ext_background_effect.rs b/rio-window/src/platform_impl/linux/wayland/types/ext_background_effect.rs new file mode 100644 index 0000000000..58551d187f --- /dev/null +++ b/rio-window/src/platform_impl/linux/wayland/types/ext_background_effect.rs @@ -0,0 +1,69 @@ +//! Handling of background effect. + +use sctk::reexports::client::globals::{BindError, GlobalList}; +use sctk::reexports::client::protocol::wl_surface::WlSurface; +use sctk::reexports::client::{ + delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle, +}; +use sctk::reexports::protocols::ext::background_effect::v1::client::ext_background_effect_manager_v1::ExtBackgroundEffectManagerV1; +use sctk::reexports::protocols::ext::background_effect::v1::client::ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1; + +use sctk::globals::GlobalData; + +use crate::platform_impl::wayland::state::WinitState; + +/// Wayland background effect manager. +#[derive(Debug, Clone)] +pub struct BackgroundEffectManager { + manager: ExtBackgroundEffectManagerV1, +} + +impl BackgroundEffectManager { + pub fn new( + globals: &GlobalList, + queue_handle: &QueueHandle, + ) -> Result { + let manager = globals.bind(queue_handle, 1..=1, GlobalData)?; + Ok(Self { manager }) + } + + pub fn background_effect( + &self, + surface: &WlSurface, + queue_handle: &QueueHandle, + ) -> ExtBackgroundEffectSurfaceV1 { + self.manager + .get_background_effect(surface, queue_handle, ()) + } +} + +impl Dispatch + for BackgroundEffectManager +{ + fn event( + _: &mut WinitState, + _: &ExtBackgroundEffectManagerV1, + _: ::Event, + _: &GlobalData, + _: &Connection, + _: &QueueHandle, + ) { + unreachable!("no events defined for wayland_background_effect_manager"); + } +} + +impl Dispatch for BackgroundEffectManager { + fn event( + _: &mut WinitState, + _: &ExtBackgroundEffectSurfaceV1, + _: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + unreachable!("no events defined for wayland_background_effect_surface"); + } +} + +delegate_dispatch!(WinitState: [ExtBackgroundEffectManagerV1: GlobalData] => BackgroundEffectManager); +delegate_dispatch!(WinitState: [ExtBackgroundEffectSurfaceV1: ()] => BackgroundEffectManager); diff --git a/rio-window/src/platform_impl/linux/wayland/types/kwin_blur.rs b/rio-window/src/platform_impl/linux/wayland/types/kwin_blur.rs deleted file mode 100644 index f12eafea6b..0000000000 --- a/rio-window/src/platform_impl/linux/wayland/types/kwin_blur.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! Handling of KDE-compatible blur. - -use sctk::reexports::client::globals::{BindError, GlobalList}; -use sctk::reexports::client::protocol::wl_surface::WlSurface; -use sctk::reexports::client::{ - delegate_dispatch, Connection, Dispatch, Proxy, QueueHandle, -}; -use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur; -use wayland_protocols_plasma::blur::client::org_kde_kwin_blur_manager::OrgKdeKwinBlurManager; - -use sctk::globals::GlobalData; - -use crate::platform_impl::wayland::state::WinitState; - -/// KWin blur manager. -#[derive(Debug, Clone)] -pub struct KWinBlurManager { - manager: OrgKdeKwinBlurManager, -} - -impl KWinBlurManager { - pub fn new( - globals: &GlobalList, - queue_handle: &QueueHandle, - ) -> Result { - let manager = globals.bind(queue_handle, 1..=1, GlobalData)?; - Ok(Self { manager }) - } - - pub fn blur( - &self, - surface: &WlSurface, - queue_handle: &QueueHandle, - ) -> OrgKdeKwinBlur { - self.manager.create(surface, queue_handle, ()) - } - - pub fn unset(&self, surface: &WlSurface) { - self.manager.unset(surface) - } -} - -impl Dispatch for KWinBlurManager { - fn event( - _: &mut WinitState, - _: &OrgKdeKwinBlurManager, - _: ::Event, - _: &GlobalData, - _: &Connection, - _: &QueueHandle, - ) { - unreachable!("no events defined for org_kde_kwin_blur_manager"); - } -} - -impl Dispatch for KWinBlurManager { - fn event( - _: &mut WinitState, - _: &OrgKdeKwinBlur, - _: ::Event, - _: &(), - _: &Connection, - _: &QueueHandle, - ) { - unreachable!("no events defined for org_kde_kwin_blur"); - } -} - -delegate_dispatch!(WinitState: [OrgKdeKwinBlurManager: GlobalData] => KWinBlurManager); -delegate_dispatch!(WinitState: [OrgKdeKwinBlur: ()] => KWinBlurManager); diff --git a/rio-window/src/platform_impl/linux/wayland/types/mod.rs b/rio-window/src/platform_impl/linux/wayland/types/mod.rs index 77e67f48be..f6230fc8cb 100644 --- a/rio-window/src/platform_impl/linux/wayland/types/mod.rs +++ b/rio-window/src/platform_impl/linux/wayland/types/mod.rs @@ -1,7 +1,7 @@ //! Wayland protocol implementation boilerplate. pub mod cursor; -pub mod kwin_blur; +pub mod ext_background_effect; pub mod wp_fractional_scaling; pub mod wp_viewporter; pub mod xdg_activation; diff --git a/rio-window/src/platform_impl/linux/wayland/window/state.rs b/rio-window/src/platform_impl/linux/wayland/window/state.rs index e52caaf66b..4cff297e45 100644 --- a/rio-window/src/platform_impl/linux/wayland/window/state.rs +++ b/rio-window/src/platform_impl/linux/wayland/window/state.rs @@ -15,6 +15,7 @@ use sctk::reexports::client::{Connection, Proxy, QueueHandle}; use sctk::reexports::csd_frame::{ DecorationsFrame, FrameAction, FrameClick, ResizeEdge, WindowState as XdgWindowState, }; +use sctk::reexports::protocols::ext::background_effect::v1::client::ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1; use sctk::reexports::protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1::WpFractionalScaleV1; use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_v3::ZwpTextInputV3; use sctk::reexports::protocols::wp::viewporter::client::wp_viewport::WpViewport; @@ -28,14 +29,12 @@ use sctk::shell::WaylandSurface; use sctk::shm::slot::SlotPool; use sctk::shm::Shm; use sctk::subcompositor::SubcompositorState; -use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur; use crate::cursor::CustomCursor as RootCustomCursor; use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize, Size}; use crate::error::{ExternalError, NotSupportedError}; use crate::platform_impl::wayland::logical_to_physical_rounded; use crate::platform_impl::wayland::types::cursor::{CustomCursor, SelectedCursor}; -use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager; use crate::platform_impl::{PlatformCustomCursor, WindowId}; use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme}; @@ -142,8 +141,7 @@ pub struct WindowState { viewport: Option, fractional_scale: Option, - blur: Option, - blur_manager: Option, + background_effect: Option, /// Whether the client side decorations have pending move operations. /// @@ -181,10 +179,13 @@ impl WindowState { .fractional_scaling_manager .as_ref() .map(|fsm| fsm.fractional_scaling(window.wl_surface(), queue_handle)); + let background_effect = winit_state + .background_effect_manager + .as_ref() + .map(|bem| bem.background_effect(window.wl_surface(), queue_handle)); Self { - blur: None, - blur_manager: winit_state.kwin_blur_manager.clone(), + background_effect, compositor, connection, csd_fails: false, @@ -1074,21 +1075,19 @@ impl WindowState { /// Make window background blurred #[inline] pub fn set_blur(&mut self, blurred: bool) { - if blurred && self.blur.is_none() { - if let Some(blur_manager) = self.blur_manager.as_ref() { - let blur = - blur_manager.blur(self.window.wl_surface(), &self.queue_handle); - blur.commit(); - self.blur = Some(blur); + if let Some(background_effect) = self.background_effect.as_ref() { + if blurred { + if let Ok(region) = Region::new(&*self.compositor) { + region.add(0, 0, i32::MAX, i32::MAX); + background_effect.set_blur_region(Some(region.wl_region())); + } else { + warn!("Failed to create blur region for window"); + } } else { - info!("Blur manager unavailable, unable to change blur") + background_effect.set_blur_region(None); } - } else if !blurred && self.blur.is_some() { - self.blur_manager - .as_ref() - .unwrap() - .unset(self.window.wl_surface()); - self.blur.take().unwrap().release(); + } else { + info!("Background effect surface unavailable, unable to change blur"); } } @@ -1147,8 +1146,8 @@ impl WindowState { impl Drop for WindowState { fn drop(&mut self) { - if let Some(blur) = self.blur.take() { - blur.release(); + if let Some(be) = self.background_effect.take() { + be.destroy(); } if let Some(fs) = self.fractional_scale.take() {