Add Window::set_blur

Allow clients to request blur behind their window, implemented on
Wayland for now.
This commit is contained in:
Dmitry Sharshakov 2023-10-08 22:53:15 +03:00 committed by GitHub
parent f5dd1c008c
commit 0363be4776
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 167 additions and 2 deletions

View file

@ -843,6 +843,8 @@ impl Window {
pub fn set_transparent(&self, _transparent: bool) {}
pub fn set_blur(&self, _blur: bool) {}
pub fn set_visible(&self, _visibility: bool) {}
pub fn is_visible(&self) -> Option<bool> {

View file

@ -42,6 +42,10 @@ impl Inner {
debug!("`Window::set_transparent` is ignored on iOS")
}
pub fn set_blur(&self, _blur: bool) {
debug!("`Window::set_blur` is ignored on iOS")
}
pub fn set_visible(&self, visible: bool) {
self.window.setHidden(!visible)
}

View file

@ -329,6 +329,11 @@ impl Window {
x11_or_wayland!(match self; Window(w) => w.set_transparent(transparent));
}
#[inline]
pub fn set_blur(&self, blur: bool) {
x11_or_wayland!(match self; Window(w) => w.set_blur(blur));
}
#[inline]
pub fn set_visible(&self, visible: bool) {
x11_or_wayland!(match self; Window(w) => w.set_visible(visible))

View file

@ -31,6 +31,7 @@ use super::seat::{
PointerConstraintsState, RelativePointerState, TextInputState, WinitPointerData,
WinitPointerDataExt, WinitSeatState,
};
use super::types::kwin_blur::KWinBlurManager;
use super::types::wp_fractional_scaling::FractionalScalingManager;
use super::types::wp_viewporter::ViewporterState;
use super::types::xdg_activation::XdgActivationState;
@ -103,6 +104,9 @@ pub struct WinitState {
/// Fractional scaling manager.
pub fractional_scaling_manager: Option<FractionalScalingManager>,
/// KWin blur manager.
pub kwin_blur_manager: Option<KWinBlurManager>,
/// Loop handle to re-register event sources, such as keyboard repeat.
pub loop_handle: LoopHandle<'static, Self>,
@ -161,6 +165,7 @@ impl WinitState {
window_events_sink: Default::default(),
viewporter_state,
fractional_scaling_manager,
kwin_blur_manager: KWinBlurManager::new(globals, queue_handle).ok(),
seats,
text_input_state: TextInputState::new(globals, queue_handle).ok(),

View file

@ -0,0 +1,70 @@
//! Handling of KDE-compatible blur.
use sctk::reexports::client::globals::{BindError, GlobalList};
use sctk::reexports::client::protocol::wl_surface::WlSurface;
use sctk::reexports::client::Dispatch;
use sctk::reexports::client::{delegate_dispatch, Connection, Proxy, QueueHandle};
use wayland_protocols_plasma::blur::client::{
org_kde_kwin_blur::OrgKdeKwinBlur, 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<WinitState>,
) -> Result<Self, BindError> {
let manager = globals.bind(queue_handle, 1..=1, GlobalData)?;
Ok(Self { manager })
}
pub fn blur(
&self,
surface: &WlSurface,
queue_handle: &QueueHandle<WinitState>,
) -> OrgKdeKwinBlur {
self.manager.create(surface, queue_handle, ())
}
pub fn unset(&self, surface: &WlSurface) {
self.manager.unset(surface)
}
}
impl Dispatch<OrgKdeKwinBlurManager, GlobalData, WinitState> for KWinBlurManager {
fn event(
_: &mut WinitState,
_: &OrgKdeKwinBlurManager,
_: <OrgKdeKwinBlurManager as Proxy>::Event,
_: &GlobalData,
_: &Connection,
_: &QueueHandle<WinitState>,
) {
unreachable!("no events defined for org_kde_kwin_blur_manager");
}
}
impl Dispatch<OrgKdeKwinBlur, (), WinitState> for KWinBlurManager {
fn event(
_: &mut WinitState,
_: &OrgKdeKwinBlur,
_: <OrgKdeKwinBlur as Proxy>::Event,
_: &(),
_: &Connection,
_: &QueueHandle<WinitState>,
) {
unreachable!("no events defined for org_kde_kwin_blur");
}
}
delegate_dispatch!(WinitState: [OrgKdeKwinBlurManager: GlobalData] => KWinBlurManager);
delegate_dispatch!(WinitState: [OrgKdeKwinBlur: ()] => KWinBlurManager);

View file

@ -1,5 +1,6 @@
//! Wayland protocol implementation boilerplate.
pub mod kwin_blur;
pub mod wp_fractional_scaling;
pub mod wp_viewporter;
pub mod xdg_activation;

View file

@ -131,6 +131,8 @@ impl Window {
// Set transparency hint.
window_state.set_transparent(attributes.transparent);
window_state.set_blur(attributes.blur);
// Set the decorations hint.
window_state.set_decorate(attributes.decorations);
@ -409,6 +411,11 @@ impl Window {
self.window_state.lock().unwrap().scale_factor()
}
#[inline]
pub fn set_blur(&self, blur: bool) {
self.window_state.lock().unwrap().set_blur(blur);
}
#[inline]
pub fn set_decorations(&self, decorate: bool) {
self.window_state.lock().unwrap().set_decorate(decorate)

View file

@ -4,7 +4,7 @@ use std::mem::ManuallyDrop;
use std::num::NonZeroU32;
use std::sync::{Arc, Weak};
use log::warn;
use log::{info, warn};
use sctk::reexports::client::protocol::wl_seat::WlSeat;
use sctk::reexports::client::protocol::wl_shm::WlShm;
@ -23,9 +23,11 @@ use sctk::shell::xdg::XdgSurface;
use sctk::shell::WaylandSurface;
use sctk::shm::Shm;
use sctk::subcompositor::SubcompositorState;
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
use crate::dpi::{LogicalPosition, LogicalSize};
use crate::error::{ExternalError, NotSupportedError};
use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
use crate::platform_impl::WindowId;
use crate::window::{CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme};
@ -130,6 +132,8 @@ pub struct WindowState {
viewport: Option<WpViewport>,
fractional_scale: Option<WpFractionalScaleV1>,
blur: Option<OrgKdeKwinBlur>,
blur_manager: Option<KWinBlurManager>,
/// Whether the client side decorations have pending move operations.
///
@ -159,6 +163,8 @@ impl WindowState {
.map(|fsm| fsm.fractional_scaling(window.wl_surface(), queue_handle));
Self {
blur: None,
blur_manager: winit_state.kwin_blur_manager.clone(),
compositor,
connection,
csd_fails: false,
@ -840,6 +846,26 @@ 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();
}
}
/// Set the window title to a new value.
///
/// This will autmatically truncate the title to something meaningfull.
@ -900,6 +926,10 @@ impl Drop for WindowState {
ManuallyDrop::drop(&mut self.window);
}
if let Some(blur) = &self.blur {
blur.release();
}
surface.destroy();
}
}

View file

@ -1027,6 +1027,9 @@ impl UnownedWindow {
#[inline]
pub fn set_transparent(&self, _transparent: bool) {}
#[inline]
pub fn set_blur(&self, _blur: bool) {}
fn set_decorations_inner(&self, decorations: bool) -> Result<VoidCookie<'_>, X11Error> {
self.shared_state_lock().is_decorated = decorations;
let mut hints = self.xconn.get_motif_hints(self.xwindow);

View file

@ -596,6 +596,8 @@ impl WinitWindow {
self.setOpaque(!transparent)
}
pub fn set_blur(&self, _blur: bool) {}
pub fn set_visible(&self, visible: bool) {
match visible {
true => self.makeKeyAndOrderFront(None),

View file

@ -261,6 +261,9 @@ impl Window {
#[inline]
pub fn set_transparent(&self, _transparent: bool) {}
#[inline]
pub fn set_blur(&self, _blur: bool) {}
#[inline]
pub fn set_visible(&self, _visibility: bool) {}

View file

@ -92,6 +92,8 @@ impl Inner {
pub fn set_transparent(&self, _transparent: bool) {}
pub fn set_blur(&self, _blur: bool) {}
pub fn set_visible(&self, _visible: bool) {
// Intentionally a no-op
}

View file

@ -127,6 +127,8 @@ impl Window {
pub fn set_transparent(&self, _transparent: bool) {}
pub fn set_blur(&self, _blur: bool) {}
#[inline]
pub fn set_visible(&self, visible: bool) {
let window = self.window.clone();