winit-wayland: use ext-background-effect if available
A more modern protocol compared to the KDE one.
This commit is contained in:
parent
a610ac9c7a
commit
261cda5401
7 changed files with 199 additions and 30 deletions
|
|
@ -881,7 +881,8 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug {
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
///
|
///
|
||||||
/// - **Android / iOS / X11 / Web / Windows:** Unsupported.
|
/// - **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.
|
||||||
fn set_blur(&self, blur: bool);
|
fn set_blur(&self, blur: bool);
|
||||||
|
|
||||||
/// Modifies the window's visibility.
|
/// Modifies the window's visibility.
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ use crate::seat::{
|
||||||
PointerConstraintsState, PointerGesturesState, RelativePointerState, TextInputState,
|
PointerConstraintsState, PointerGesturesState, RelativePointerState, TextInputState,
|
||||||
WinitPointerData, WinitPointerDataExt, WinitSeatState,
|
WinitPointerData, WinitPointerDataExt, WinitSeatState,
|
||||||
};
|
};
|
||||||
use crate::types::kwin_blur::KWinBlurManager;
|
use crate::types::bgr_effects::BgrEffectManager;
|
||||||
use crate::types::wp_fractional_scaling::FractionalScalingManager;
|
use crate::types::wp_fractional_scaling::FractionalScalingManager;
|
||||||
use crate::types::wp_tablet_input_v2::TabletManager;
|
use crate::types::wp_tablet_input_v2::TabletManager;
|
||||||
use crate::types::wp_viewporter::ViewporterState;
|
use crate::types::wp_viewporter::ViewporterState;
|
||||||
|
|
@ -116,8 +116,8 @@ pub struct WinitState {
|
||||||
/// Fractional scaling manager.
|
/// Fractional scaling manager.
|
||||||
pub fractional_scaling_manager: Option<FractionalScalingManager>,
|
pub fractional_scaling_manager: Option<FractionalScalingManager>,
|
||||||
|
|
||||||
/// KWin blur manager.
|
/// Blur manager.
|
||||||
pub kwin_blur_manager: Option<KWinBlurManager>,
|
pub blur_manager: Option<BgrEffectManager>,
|
||||||
|
|
||||||
/// Loop handle to re-register event sources, such as keyboard repeat.
|
/// Loop handle to re-register event sources, such as keyboard repeat.
|
||||||
pub loop_handle: LoopHandle<'static, Self>,
|
pub loop_handle: LoopHandle<'static, Self>,
|
||||||
|
|
@ -192,7 +192,7 @@ impl WinitState {
|
||||||
window_events_sink: Default::default(),
|
window_events_sink: Default::default(),
|
||||||
viewporter_state,
|
viewporter_state,
|
||||||
fractional_scaling_manager,
|
fractional_scaling_manager,
|
||||||
kwin_blur_manager: KWinBlurManager::new(globals, queue_handle).ok(),
|
blur_manager: BgrEffectManager::new(globals, queue_handle).ok(),
|
||||||
|
|
||||||
seats,
|
seats,
|
||||||
text_input_state: TextInputState::new(globals, queue_handle).ok(),
|
text_input_state: TextInputState::new(globals, queue_handle).ok(),
|
||||||
|
|
|
||||||
85
winit-wayland/src/types/bgr_effects.rs
Normal file
85
winit-wayland/src/types/bgr_effects.rs
Normal file
|
|
@ -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::state::WinitState;
|
||||||
|
use crate::types::ext_background_effect::ExtBackgroundEffectManager;
|
||||||
|
use crate::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
winit-wayland/src/types/ext_background_effect.rs
Normal file
59
winit-wayland/src/types/ext_background_effect.rs
Normal file
|
|
@ -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::{Connection, Dispatch, Proxy, QueueHandle, delegate_dispatch};
|
||||||
|
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::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);
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
//! Wayland protocol implementation boilerplate.
|
//! Wayland protocol implementation boilerplate.
|
||||||
|
|
||||||
|
pub mod bgr_effects;
|
||||||
pub mod cursor;
|
pub mod cursor;
|
||||||
|
pub mod ext_background_effect;
|
||||||
pub mod kwin_blur;
|
pub mod kwin_blur;
|
||||||
pub mod wp_fractional_scaling;
|
pub mod wp_fractional_scaling;
|
||||||
pub mod wp_tablet_input_v2;
|
pub mod wp_tablet_input_v2;
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,8 @@ impl Window {
|
||||||
// Set transparency hint.
|
// Set transparency hint.
|
||||||
window_state.set_transparent(attributes.transparent);
|
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.
|
// Set the decorations hint.
|
||||||
window_state.set_decorate(attributes.decorations);
|
window_state.set_decorate(attributes.decorations);
|
||||||
|
|
@ -491,7 +492,9 @@ impl CoreWindow for Window {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_blur(&self, blur: bool) {
|
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]
|
#[inline]
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ use sctk::shm::slot::SlotPool;
|
||||||
use sctk::subcompositor::SubcompositorState;
|
use sctk::subcompositor::SubcompositorState;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
use wayland_protocols::xdg::toplevel_icon::v1::client::xdg_toplevel_icon_manager_v1::XdgToplevelIconManagerV1;
|
use wayland_protocols::xdg::toplevel_icon::v1::client::xdg_toplevel_icon_manager_v1::XdgToplevelIconManagerV1;
|
||||||
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
|
|
||||||
use winit_core::cursor::{CursorIcon, CustomCursor as CoreCustomCursor};
|
use winit_core::cursor::{CursorIcon, CustomCursor as CoreCustomCursor};
|
||||||
use winit_core::error::{NotSupportedError, RequestError};
|
use winit_core::error::{NotSupportedError, RequestError};
|
||||||
use winit_core::window::{
|
use winit_core::window::{
|
||||||
|
|
@ -43,8 +42,8 @@ use crate::seat::{
|
||||||
ZwpTextInputV3Ext,
|
ZwpTextInputV3Ext,
|
||||||
};
|
};
|
||||||
use crate::state::{WindowCompositorUpdate, WinitState};
|
use crate::state::{WindowCompositorUpdate, WinitState};
|
||||||
|
use crate::types::bgr_effects::{BgrEffectManager, SurfaceBlurEffect};
|
||||||
use crate::types::cursor::{CustomCursor, SelectedCursor, WaylandCustomCursor};
|
use crate::types::cursor::{CustomCursor, SelectedCursor, WaylandCustomCursor};
|
||||||
use crate::types::kwin_blur::KWinBlurManager;
|
|
||||||
use crate::types::xdg_toplevel_icon_manager::ToplevelIcon;
|
use crate::types::xdg_toplevel_icon_manager::ToplevelIcon;
|
||||||
|
|
||||||
#[cfg(feature = "sctk-adwaita")]
|
#[cfg(feature = "sctk-adwaita")]
|
||||||
|
|
@ -155,8 +154,8 @@ pub struct WindowState {
|
||||||
|
|
||||||
viewport: Option<WpViewport>,
|
viewport: Option<WpViewport>,
|
||||||
fractional_scale: Option<WpFractionalScaleV1>,
|
fractional_scale: Option<WpFractionalScaleV1>,
|
||||||
blur: Option<OrgKdeKwinBlur>,
|
blur: Option<SurfaceBlurEffect>,
|
||||||
blur_manager: Option<KWinBlurManager>,
|
blur_manager: Option<BgrEffectManager>,
|
||||||
|
|
||||||
/// Whether the client side decorations have pending move operations.
|
/// Whether the client side decorations have pending move operations.
|
||||||
///
|
///
|
||||||
|
|
@ -205,7 +204,7 @@ impl WindowState {
|
||||||
toplevel_icon: None,
|
toplevel_icon: None,
|
||||||
xdg_toplevel_icon_manager,
|
xdg_toplevel_icon_manager,
|
||||||
blur: None,
|
blur: None,
|
||||||
blur_manager: winit_state.kwin_blur_manager.clone(),
|
blur_manager: winit_state.blur_manager.clone(),
|
||||||
compositor,
|
compositor,
|
||||||
handle,
|
handle,
|
||||||
csd_fails: false,
|
csd_fails: false,
|
||||||
|
|
@ -704,6 +703,13 @@ impl WindowState {
|
||||||
// Set surface size without the borders.
|
// Set surface size without the borders.
|
||||||
viewport.set_destination(self.size.width as _, self.size.height as _);
|
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.
|
/// Get the scale factor of the window.
|
||||||
|
|
@ -1063,20 +1069,37 @@ impl WindowState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make window background blurred
|
/// Make window background blurred.
|
||||||
#[inline]
|
///
|
||||||
pub fn set_blur(&mut self, blurred: bool) {
|
/// Returns `true` if redraw is required.
|
||||||
if blurred && self.blur.is_none() {
|
#[must_use]
|
||||||
if let Some(blur_manager) = self.blur_manager.as_ref() {
|
pub fn set_blur(&mut self, blurred: bool) -> bool {
|
||||||
let blur = blur_manager.blur(self.window.wl_surface(), &self.queue_handle);
|
if !blurred {
|
||||||
blur.commit();
|
self.blur = None;
|
||||||
self.blur = Some(blur);
|
return true;
|
||||||
} 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());
|
let mgr = match self.blur_manager.as_mut() {
|
||||||
self.blur.take().unwrap().release();
|
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(®ion))
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1174,10 +1197,6 @@ impl WindowState {
|
||||||
|
|
||||||
impl Drop for WindowState {
|
impl Drop for WindowState {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(blur) = self.blur.take() {
|
|
||||||
blur.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(fs) = self.fractional_scale.take() {
|
if let Some(fs) = self.fractional_scale.take() {
|
||||||
fs.destroy();
|
fs.destroy();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue