Skip to content

Commit 6d6e135

Browse files
kchibisovchiyuki0325
authored andcommitted
wayland: use ext-background-effect if available
A more modern protocol compared to the KDE one. (cherry picked from commit c4afadb)
1 parent e9809ef commit 6d6e135

8 files changed

Lines changed: 200 additions & 30 deletions

File tree

src/changelog/unreleased.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ on how to add them:
1616
- On X11, add `Window::even_more_rare_api`.
1717
- On Wayland, add `Window::common_api`.
1818
- On Windows, add `Window::some_rare_api`.
19+
- On Wayland, added ext-background-effect-v1 support.
1920
```
2021

2122
When the change requires non-trivial amount of work for users to comply

src/platform_impl/linux/wayland/state.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::platform_impl::wayland::seat::{
2929
PointerConstraintsState, RelativePointerState, TextInputState, WinitPointerData,
3030
WinitPointerDataExt, WinitSeatState,
3131
};
32-
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
32+
use crate::platform_impl::wayland::types::bgr_effects::BgrEffectManager;
3333
use crate::platform_impl::wayland::types::wp_fractional_scaling::FractionalScalingManager;
3434
use crate::platform_impl::wayland::types::wp_viewporter::ViewporterState;
3535
use crate::platform_impl::wayland::types::xdg_activation::XdgActivationState;
@@ -106,8 +106,8 @@ pub struct WinitState {
106106
/// Fractional scaling manager.
107107
pub fractional_scaling_manager: Option<FractionalScalingManager>,
108108

109-
/// KWin blur manager.
110-
pub kwin_blur_manager: Option<KWinBlurManager>,
109+
/// Blur manager.
110+
pub blur_manager: Option<BgrEffectManager>,
111111

112112
/// Loop handle to re-register event sources, such as keyboard repeat.
113113
pub loop_handle: LoopHandle<'static, Self>,
@@ -176,7 +176,7 @@ impl WinitState {
176176
window_events_sink: Default::default(),
177177
viewporter_state,
178178
fractional_scaling_manager,
179-
kwin_blur_manager: KWinBlurManager::new(globals, queue_handle).ok(),
179+
blur_manager: BgrEffectManager::new(globals, queue_handle).ok(),
180180

181181
seats,
182182
text_input_state: TextInputState::new(globals, queue_handle).ok(),
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use sctk::compositor::Region;
2+
use sctk::reexports::client::QueueHandle;
3+
use sctk::reexports::client::globals::{BindError, GlobalList};
4+
use sctk::reexports::client::protocol::wl_surface::WlSurface;
5+
use sctk::reexports::protocols::ext::background_effect::v1::client::ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1;
6+
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
7+
8+
use crate::platform_impl::wayland::state::WinitState;
9+
use crate::platform_impl::wayland::types::ext_background_effect::ExtBackgroundEffectManager;
10+
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
11+
12+
/// Wrapper around various background effects for [`WlSurface`].
13+
#[derive(Debug, Clone)]
14+
pub enum BgrEffectManager {
15+
Ext(ExtBackgroundEffectManager),
16+
KWin(KWinBlurManager),
17+
}
18+
19+
impl BgrEffectManager {
20+
pub fn new(
21+
globals: &GlobalList,
22+
queue_handle: &QueueHandle<WinitState>,
23+
) -> Result<Self, BindError> {
24+
ExtBackgroundEffectManager::new(globals, queue_handle)
25+
.map(Self::Ext)
26+
.or_else(|_| KWinBlurManager::new(globals, queue_handle).map(Self::KWin))
27+
}
28+
29+
/// Creates a new blur effect for the surface.
30+
pub fn new_blur_effect(
31+
&mut self,
32+
surface: &WlSurface,
33+
queue_handle: &QueueHandle<WinitState>,
34+
) -> SurfaceBlurEffect {
35+
match self {
36+
BgrEffectManager::Ext(mgr) => SurfaceBlurEffect::Ext(mgr.blur(surface, queue_handle)),
37+
BgrEffectManager::KWin(mgr) => SurfaceBlurEffect::Kwin(
38+
mgr.blur(surface, queue_handle),
39+
mgr.clone(),
40+
surface.clone(),
41+
),
42+
}
43+
}
44+
}
45+
46+
#[derive(Debug)]
47+
pub enum SurfaceBlurEffect {
48+
Ext(ExtBackgroundEffectSurfaceV1),
49+
Kwin(OrgKdeKwinBlur, KWinBlurManager, WlSurface),
50+
}
51+
52+
impl SurfaceBlurEffect {
53+
/// Returns `true` if the main surface commit is required.
54+
///
55+
/// `None` clears the blur.
56+
#[must_use]
57+
pub fn set_blur(&self, region: Option<&Region>) -> bool {
58+
let region = region.map(|region| region.wl_region());
59+
match self {
60+
SurfaceBlurEffect::Ext(surface) => {
61+
surface.set_blur_region(region);
62+
true
63+
},
64+
SurfaceBlurEffect::Kwin(blur, ..) => {
65+
blur.set_region(region);
66+
blur.commit();
67+
true
68+
},
69+
}
70+
}
71+
}
72+
73+
impl Drop for SurfaceBlurEffect {
74+
fn drop(&mut self) {
75+
match self {
76+
SurfaceBlurEffect::Ext(surface) => surface.destroy(),
77+
SurfaceBlurEffect::Kwin(blur, mgr, wl_surface) => {
78+
blur.set_region(None);
79+
blur.commit();
80+
blur.release();
81+
mgr.unset(wl_surface);
82+
},
83+
}
84+
}
85+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use sctk::globals::GlobalData;
2+
use sctk::reexports::client::globals::{BindError, GlobalList};
3+
use sctk::reexports::client::protocol::wl_surface::WlSurface;
4+
use sctk::reexports::client::{Connection, Dispatch, Proxy, QueueHandle, delegate_dispatch};
5+
use wayland_protocols::ext::background_effect::v1::client::ext_background_effect_manager_v1::ExtBackgroundEffectManagerV1;
6+
use wayland_protocols::ext::background_effect::v1::client::ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1;
7+
8+
use crate::platform_impl::wayland::state::WinitState;
9+
10+
#[derive(Debug, Clone)]
11+
pub struct ExtBackgroundEffectManager {
12+
manager: ExtBackgroundEffectManagerV1,
13+
}
14+
15+
impl ExtBackgroundEffectManager {
16+
pub fn new(
17+
globals: &GlobalList,
18+
queue_handle: &QueueHandle<WinitState>,
19+
) -> Result<Self, BindError> {
20+
let manager = globals.bind(queue_handle, 1..=1, GlobalData)?;
21+
Ok(Self { manager })
22+
}
23+
24+
pub fn blur(
25+
&mut self,
26+
surface: &WlSurface,
27+
queue_handle: &QueueHandle<WinitState>,
28+
) -> ExtBackgroundEffectSurfaceV1 {
29+
self.manager.get_background_effect(surface, queue_handle, ())
30+
}
31+
}
32+
33+
impl Dispatch<ExtBackgroundEffectManagerV1, GlobalData, WinitState> for ExtBackgroundEffectManager {
34+
fn event(
35+
_: &mut WinitState,
36+
_: &ExtBackgroundEffectManagerV1,
37+
_: <ExtBackgroundEffectManagerV1 as Proxy>::Event,
38+
_: &GlobalData,
39+
_: &Connection,
40+
_: &QueueHandle<WinitState>,
41+
) {
42+
}
43+
}
44+
45+
impl Dispatch<ExtBackgroundEffectSurfaceV1, (), WinitState> for ExtBackgroundEffectManager {
46+
fn event(
47+
_: &mut WinitState,
48+
_: &ExtBackgroundEffectSurfaceV1,
49+
_: <ExtBackgroundEffectSurfaceV1 as Proxy>::Event,
50+
_: &(),
51+
_: &Connection,
52+
_: &QueueHandle<WinitState>,
53+
) {
54+
// There is no event
55+
}
56+
}
57+
58+
delegate_dispatch!(WinitState: [ExtBackgroundEffectManagerV1: GlobalData] => ExtBackgroundEffectManager);
59+
delegate_dispatch!(WinitState: [ExtBackgroundEffectSurfaceV1: ()] => ExtBackgroundEffectManager);

src/platform_impl/linux/wayland/types/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Wayland protocol implementation boilerplate.
22
3+
pub mod bgr_effects;
34
pub mod cursor;
5+
pub mod ext_background_effect;
46
pub mod kwin_blur;
57
pub mod wp_fractional_scaling;
68
pub mod wp_viewporter;

src/platform_impl/linux/wayland/window/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ impl Window {
119119
// Set transparency hint.
120120
window_state.set_transparent(attributes.transparent);
121121

122-
window_state.set_blur(attributes.blur);
122+
// Set blur.
123+
let _ = window_state.set_blur(attributes.blur);
123124

124125
// Set the decorations hint.
125126
window_state.set_decorate(attributes.decorations);
@@ -413,7 +414,9 @@ impl Window {
413414

414415
#[inline]
415416
pub fn set_blur(&self, blur: bool) {
416-
self.window_state.lock().unwrap().set_blur(blur);
417+
if self.window_state.lock().unwrap().set_blur(blur) {
418+
self.request_redraw();
419+
}
417420
}
418421

419422
#[inline]

src/platform_impl/linux/wayland/window/state.rs

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,13 @@ use sctk::shell::WaylandSurface;
2828
use sctk::shm::slot::SlotPool;
2929
use sctk::shm::Shm;
3030
use sctk::subcompositor::SubcompositorState;
31-
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
3231

3332
use crate::cursor::CustomCursor as RootCustomCursor;
3433
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Size};
3534
use crate::error::{ExternalError, NotSupportedError};
3635
use crate::platform_impl::wayland::logical_to_physical_rounded;
3736
use crate::platform_impl::wayland::types::cursor::{CustomCursor, SelectedCursor};
38-
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
37+
use crate::platform_impl::wayland::types::bgr_effects::{BgrEffectManager, SurfaceBlurEffect};
3938
use crate::platform_impl::{PlatformCustomCursor, WindowId};
4039
use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme};
4140

@@ -143,8 +142,8 @@ pub struct WindowState {
143142

144143
viewport: Option<WpViewport>,
145144
fractional_scale: Option<WpFractionalScaleV1>,
146-
blur: Option<OrgKdeKwinBlur>,
147-
blur_manager: Option<KWinBlurManager>,
145+
blur: Option<SurfaceBlurEffect>,
146+
blur_manager: Option<BgrEffectManager>,
148147

149148
/// Whether the client side decorations have pending move operations.
150149
///
@@ -185,7 +184,7 @@ impl WindowState {
185184

186185
Self {
187186
blur: None,
188-
blur_manager: winit_state.kwin_blur_manager.clone(),
187+
blur_manager: winit_state.blur_manager.clone(),
189188
compositor,
190189
connection,
191190
csd_fails: false,
@@ -717,6 +716,13 @@ impl WindowState {
717716
// Set inner size without the borders.
718717
viewport.set_destination(self.size.width as _, self.size.height as _);
719718
}
719+
720+
// Update blur region with new size.
721+
if self.blur.is_some() {
722+
// NOTE: either user resized or configure, in both cases
723+
// the redraw scheduling is done on the caller side.
724+
let _ = self.set_blur(true);
725+
}
720726
}
721727

722728
/// Get the scale factor of the window.
@@ -1077,20 +1083,37 @@ impl WindowState {
10771083
}
10781084
}
10791085

1080-
/// Make window background blurred
1081-
#[inline]
1082-
pub fn set_blur(&mut self, blurred: bool) {
1083-
if blurred && self.blur.is_none() {
1084-
if let Some(blur_manager) = self.blur_manager.as_ref() {
1085-
let blur = blur_manager.blur(self.window.wl_surface(), &self.queue_handle);
1086-
blur.commit();
1087-
self.blur = Some(blur);
1088-
} else {
1089-
info!("Blur manager unavailable, unable to change blur")
1090-
}
1091-
} else if !blurred && self.blur.is_some() {
1092-
self.blur_manager.as_ref().unwrap().unset(self.window.wl_surface());
1093-
self.blur.take().unwrap().release();
1086+
/// Make window background blurred.
1087+
///
1088+
/// Returns `true` if redraw is required.
1089+
#[must_use]
1090+
pub fn set_blur(&mut self, blurred: bool) -> bool {
1091+
if !blurred {
1092+
self.blur = None;
1093+
return true;
1094+
}
1095+
1096+
let mgr = match self.blur_manager.as_mut() {
1097+
Some(mgr) => mgr,
1098+
None => {
1099+
info!("Blur manager unavailable, unable to change blur");
1100+
return false;
1101+
},
1102+
};
1103+
1104+
let blur = match self.blur.as_ref() {
1105+
Some(blur) => blur,
1106+
None => {
1107+
self.blur = Some(mgr.new_blur_effect(self.window.wl_surface(), &self.queue_handle));
1108+
self.blur.as_ref().unwrap()
1109+
},
1110+
};
1111+
1112+
if let Ok(region) = Region::new(&*self.compositor) {
1113+
region.add(0, 0, i32::MAX, i32::MAX);
1114+
blur.set_blur(Some(&region))
1115+
} else {
1116+
false
10941117
}
10951118
}
10961119

@@ -1149,10 +1172,6 @@ impl WindowState {
11491172

11501173
impl Drop for WindowState {
11511174
fn drop(&mut self) {
1152-
if let Some(blur) = self.blur.take() {
1153-
blur.release();
1154-
}
1155-
11561175
if let Some(fs) = self.fractional_scale.take() {
11571176
fs.destroy();
11581177
}

src/window.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,8 @@ impl Window {
954954
/// ## Platform-specific
955955
///
956956
/// - **Android / iOS / X11 / Web / Windows:** Unsupported.
957-
/// - **Wayland:** Only works with org_kde_kwin_blur_manager protocol.
957+
/// - **Wayland:** Only works with `org_kde_kwin_blur_manager` or
958+
/// `ext_background_effect_manager_v1` protocol.
958959
#[inline]
959960
pub fn set_blur(&self, blur: bool) {
960961
let _span = tracing::debug_span!("winit::Window::set_blur", blur).entered();

0 commit comments

Comments
 (0)