Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ on how to add them:
- On X11, add `Window::even_more_rare_api`.
- On Wayland, add `Window::common_api`.
- On Windows, add `Window::some_rare_api`.
- On Wayland, added ext-background-effect-v1 support.
```

When the change requires non-trivial amount of work for users to comply
Expand Down
8 changes: 4 additions & 4 deletions src/platform_impl/linux/wayland/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::bgr_effects::BgrEffectManager;
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;
Expand Down Expand Up @@ -106,8 +106,8 @@ pub struct WinitState {
/// Fractional scaling manager.
pub fractional_scaling_manager: Option<FractionalScalingManager>,

/// KWin blur manager.
pub kwin_blur_manager: Option<KWinBlurManager>,
/// Blur manager.
pub blur_manager: Option<BgrEffectManager>,

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

seats,
text_input_state: TextInputState::new(globals, queue_handle).ok(),
Expand Down
85 changes: 85 additions & 0 deletions src/platform_impl/linux/wayland/types/bgr_effects.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use sctk::compositor::Region;
use sctk::reexports::client::QueueHandle;
use sctk::reexports::client::globals::{BindError, GlobalList};
use sctk::reexports::client::protocol::wl_surface::WlSurface;
use sctk::reexports::protocols::ext::background_effect::v1::client::ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1;
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;

use crate::platform_impl::wayland::state::WinitState;
use crate::platform_impl::wayland::types::ext_background_effect::ExtBackgroundEffectManager;
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;

/// Wrapper around various background effects for [`WlSurface`].
#[derive(Debug, Clone)]
pub enum BgrEffectManager {
Ext(ExtBackgroundEffectManager),
KWin(KWinBlurManager),
}

impl BgrEffectManager {
pub fn new(
globals: &GlobalList,
queue_handle: &QueueHandle<WinitState>,
) -> Result<Self, BindError> {
ExtBackgroundEffectManager::new(globals, queue_handle)
.map(Self::Ext)
.or_else(|_| KWinBlurManager::new(globals, queue_handle).map(Self::KWin))
}

/// Creates a new blur effect for the surface.
pub fn new_blur_effect(
&mut self,
surface: &WlSurface,
queue_handle: &QueueHandle<WinitState>,
) -> SurfaceBlurEffect {
match self {
BgrEffectManager::Ext(mgr) => SurfaceBlurEffect::Ext(mgr.blur(surface, queue_handle)),
BgrEffectManager::KWin(mgr) => SurfaceBlurEffect::Kwin(
mgr.blur(surface, queue_handle),
mgr.clone(),
surface.clone(),
),
}
}
}

#[derive(Debug)]
pub enum SurfaceBlurEffect {
Ext(ExtBackgroundEffectSurfaceV1),
Kwin(OrgKdeKwinBlur, KWinBlurManager, WlSurface),
}

impl SurfaceBlurEffect {
/// Returns `true` if the main surface commit is required.
///
/// `None` clears the blur.
#[must_use]
pub fn set_blur(&self, region: Option<&Region>) -> bool {
let region = region.map(|region| region.wl_region());
match self {
SurfaceBlurEffect::Ext(surface) => {
surface.set_blur_region(region);
true
},
SurfaceBlurEffect::Kwin(blur, ..) => {
blur.set_region(region);
blur.commit();
true
},
}
}
}

impl Drop for SurfaceBlurEffect {
fn drop(&mut self) {
match self {
SurfaceBlurEffect::Ext(surface) => surface.destroy(),
SurfaceBlurEffect::Kwin(blur, mgr, wl_surface) => {
blur.set_region(None);
blur.commit();
blur.release();
mgr.unset(wl_surface);
},
}
}
}
59 changes: 59 additions & 0 deletions src/platform_impl/linux/wayland/types/ext_background_effect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use sctk::globals::GlobalData;
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::ext::background_effect::v1::client::ext_background_effect_manager_v1::ExtBackgroundEffectManagerV1;
use wayland_protocols::ext::background_effect::v1::client::ext_background_effect_surface_v1::ExtBackgroundEffectSurfaceV1;

use crate::platform_impl::wayland::state::WinitState;

#[derive(Debug, Clone)]
pub struct ExtBackgroundEffectManager {
manager: ExtBackgroundEffectManagerV1,
}

impl ExtBackgroundEffectManager {
pub fn new(
globals: &GlobalList,
queue_handle: &QueueHandle<WinitState>,
) -> Result<Self, BindError> {
let manager = globals.bind(queue_handle, 1..=1, GlobalData)?;
Ok(Self { manager })
}

pub fn blur(
&mut self,
surface: &WlSurface,
queue_handle: &QueueHandle<WinitState>,
) -> ExtBackgroundEffectSurfaceV1 {
self.manager.get_background_effect(surface, queue_handle, ())
}
}

impl Dispatch<ExtBackgroundEffectManagerV1, GlobalData, WinitState> for ExtBackgroundEffectManager {
fn event(
_: &mut WinitState,
_: &ExtBackgroundEffectManagerV1,
_: <ExtBackgroundEffectManagerV1 as Proxy>::Event,
_: &GlobalData,
_: &Connection,
_: &QueueHandle<WinitState>,
) {
}
}

impl Dispatch<ExtBackgroundEffectSurfaceV1, (), WinitState> for ExtBackgroundEffectManager {
fn event(
_: &mut WinitState,
_: &ExtBackgroundEffectSurfaceV1,
_: <ExtBackgroundEffectSurfaceV1 as Proxy>::Event,
_: &(),
_: &Connection,
_: &QueueHandle<WinitState>,
) {
// There is no event
}
}

delegate_dispatch!(WinitState: [ExtBackgroundEffectManagerV1: GlobalData] => ExtBackgroundEffectManager);
delegate_dispatch!(WinitState: [ExtBackgroundEffectSurfaceV1: ()] => ExtBackgroundEffectManager);
2 changes: 2 additions & 0 deletions src/platform_impl/linux/wayland/types/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Wayland protocol implementation boilerplate.

pub mod bgr_effects;
pub mod cursor;
pub mod ext_background_effect;
pub mod kwin_blur;
pub mod wp_fractional_scaling;
pub mod wp_viewporter;
Expand Down
7 changes: 5 additions & 2 deletions src/platform_impl/linux/wayland/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ impl Window {
// Set transparency hint.
window_state.set_transparent(attributes.transparent);

window_state.set_blur(attributes.blur);
// Set blur.
let _ = window_state.set_blur(attributes.blur);

// Set the decorations hint.
window_state.set_decorate(attributes.decorations);
Expand Down Expand Up @@ -413,7 +414,9 @@ impl Window {

#[inline]
pub fn set_blur(&self, blur: bool) {
self.window_state.lock().unwrap().set_blur(blur);
if self.window_state.lock().unwrap().set_blur(blur) {
self.request_redraw();
}
}

#[inline]
Expand Down
65 changes: 42 additions & 23 deletions src/platform_impl/linux/wayland/window/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,13 @@ 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, PhysicalPosition, PhysicalSize, Size};
use crate::error::{ExternalError, NotSupportedError};
use crate::platform_impl::wayland::logical_to_physical_rounded;
use crate::platform_impl::wayland::types::bgr_effects::{BgrEffectManager, SurfaceBlurEffect};
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};

Expand Down Expand Up @@ -143,8 +142,8 @@ pub struct WindowState {

viewport: Option<WpViewport>,
fractional_scale: Option<WpFractionalScaleV1>,
blur: Option<OrgKdeKwinBlur>,
blur_manager: Option<KWinBlurManager>,
blur: Option<SurfaceBlurEffect>,
blur_manager: Option<BgrEffectManager>,

/// Whether the client side decorations have pending move operations.
///
Expand Down Expand Up @@ -185,7 +184,7 @@ impl WindowState {

Self {
blur: None,
blur_manager: winit_state.kwin_blur_manager.clone(),
blur_manager: winit_state.blur_manager.clone(),
compositor,
connection,
csd_fails: false,
Expand Down Expand Up @@ -717,6 +716,13 @@ impl WindowState {
// Set inner size without the borders.
viewport.set_destination(self.size.width as _, self.size.height as _);
}

// Update blur region with new size.
if self.blur.is_some() {
// NOTE: either user resized or configure, in both cases
// the redraw scheduling is done on the caller side.
let _ = self.set_blur(true);
}
}

/// Get the scale factor of the window.
Expand Down Expand Up @@ -1077,20 +1083,37 @@ 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);
} else {
info!("Blur manager unavailable, unable to change blur")
}
} else if !blurred && self.blur.is_some() {
self.blur_manager.as_ref().unwrap().unset(self.window.wl_surface());
self.blur.take().unwrap().release();
/// Make window background blurred.
///
/// Returns `true` if redraw is required.
#[must_use]
pub fn set_blur(&mut self, blurred: bool) -> bool {
if !blurred {
self.blur = None;
return true;
}

let mgr = match self.blur_manager.as_mut() {
Some(mgr) => mgr,
None => {
info!("Blur manager unavailable, unable to change blur");
return false;
},
};

let blur = match self.blur.as_ref() {
Some(blur) => blur,
None => {
self.blur = Some(mgr.new_blur_effect(self.window.wl_surface(), &self.queue_handle));
self.blur.as_ref().unwrap()
},
};

if let Ok(region) = Region::new(&*self.compositor) {
region.add(0, 0, i32::MAX, i32::MAX);
blur.set_blur(Some(&region))
} else {
false
}
}

Expand Down Expand Up @@ -1149,10 +1172,6 @@ impl WindowState {

impl Drop for WindowState {
fn drop(&mut self) {
if let Some(blur) = self.blur.take() {
blur.release();
}

if let Some(fs) = self.fractional_scale.take() {
fs.destroy();
}
Expand Down
3 changes: 2 additions & 1 deletion src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,8 @@ impl Window {
/// ## Platform-specific
///
/// - **Android / iOS / X11 / Web / Windows:** Unsupported.
/// - **Wayland:** Only works with org_kde_kwin_blur_manager protocol.
/// - **Wayland:** Only works with `org_kde_kwin_blur_manager` or
/// `ext_background_effect_manager_v1` protocol.
#[inline]
pub fn set_blur(&self, blur: bool) {
let _span = tracing::debug_span!("winit::Window::set_blur", blur).entered();
Expand Down
Loading