Add Window::set_blur
Allow clients to request blur behind their window, implemented on Wayland for now.
This commit is contained in:
parent
f5dd1c008c
commit
0363be4776
17 changed files with 167 additions and 2 deletions
|
|
@ -28,6 +28,7 @@ And please only add new entries to the top of this list, right below the `# Unre
|
|||
- **Breaking:** Change default `ControlFlow` from `Poll` to `Wait`.
|
||||
- **Breaking:** remove `DeviceEvent::Text`.
|
||||
- On Android, fix `DeviceId` to contain device id's.
|
||||
- Add `Window::set_blur` to request a blur behind the window; implemented on Wayland for now.
|
||||
|
||||
# 0.29.1-beta
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|||
[features]
|
||||
default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
|
||||
x11 = ["x11-dl", "bytemuck", "percent-encoding", "xkbcommon-dl/x11", "x11rb"]
|
||||
wayland = ["wayland-client", "wayland-backend", "wayland-protocols", "sctk", "fnv", "memmap2"]
|
||||
wayland = ["wayland-client", "wayland-backend", "wayland-protocols", "wayland-protocols-plasma", "sctk", "fnv", "memmap2"]
|
||||
wayland-dlopen = ["wayland-backend/dlopen"]
|
||||
wayland-csd-adwaita = ["sctk-adwaita", "sctk-adwaita/ab_glyph"]
|
||||
wayland-csd-adwaita-crossfont = ["sctk-adwaita", "sctk-adwaita/crossfont"]
|
||||
|
|
@ -149,6 +149,7 @@ sctk-adwaita = { version = "0.6.0", default_features = false, optional = true }
|
|||
wayland-client = { version = "0.30.0", optional = true }
|
||||
wayland-backend = { version = "0.1.0", default_features = false, features = ["client_system"], optional = true }
|
||||
wayland-protocols = { version = "0.30.0", features = [ "staging"], optional = true }
|
||||
wayland-protocols-plasma = { version = "0.1.0", features = [ "client" ], optional = true }
|
||||
calloop = "0.10.5"
|
||||
rustix = { version = "0.38.4", default-features = false, features = ["std", "system", "thread", "process"] }
|
||||
x11-dl = { version = "2.18.5", optional = true }
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ Legend:
|
|||
|Window resizing |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|✔️ |✔️ |
|
||||
|Window resize increments |❌ |✔️ |✔️ |❌ |**N/A**|**N/A**|**N/A**|**N/A** |
|
||||
|Window transparency |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|N/A |✔️ |
|
||||
|Window blur |❌ |❌ |❌ |✔️ |**N/A**|**N/A**|N/A |❌ |
|
||||
|Window maximization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|
||||
|Window maximization toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|
||||
|Window minimization |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A**|**N/A** |
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
70
src/platform_impl/linux/wayland/types/kwin_blur.rs
Normal file
70
src/platform_impl/linux/wayland/types/kwin_blur.rs
Normal 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);
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ pub struct WindowAttributes {
|
|||
pub maximized: bool,
|
||||
pub visible: bool,
|
||||
pub transparent: bool,
|
||||
pub blur: bool,
|
||||
pub decorations: bool,
|
||||
pub window_icon: Option<Icon>,
|
||||
pub preferred_theme: Option<Theme>,
|
||||
|
|
@ -176,6 +177,7 @@ impl Default for WindowAttributes {
|
|||
fullscreen: None,
|
||||
visible: true,
|
||||
transparent: false,
|
||||
blur: false,
|
||||
decorations: true,
|
||||
window_level: Default::default(),
|
||||
window_icon: None,
|
||||
|
|
@ -343,6 +345,17 @@ impl WindowBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets whether the background of the window should be blurred by the system.
|
||||
///
|
||||
/// The default is `false`.
|
||||
///
|
||||
/// See [`Window::set_blur`] for details.
|
||||
#[inline]
|
||||
pub fn with_blur(mut self, blur: bool) -> Self {
|
||||
self.window.blur = blur;
|
||||
self
|
||||
}
|
||||
|
||||
/// Get whether the window will support transparency.
|
||||
#[inline]
|
||||
pub fn transparent(&self) -> bool {
|
||||
|
|
@ -884,6 +897,19 @@ impl Window {
|
|||
.maybe_queue_on_main(move |w| w.set_transparent(transparent))
|
||||
}
|
||||
|
||||
/// Change the window blur state.
|
||||
///
|
||||
/// If `true`, this will make the transparent window background blurry.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Android / iOS / macOS / X11 / Web / Windows:** Unsupported.
|
||||
/// - **Wayland:** Only works with org_kde_kwin_blur_manager protocol.
|
||||
#[inline]
|
||||
pub fn set_blur(&self, blur: bool) {
|
||||
self.window.maybe_queue_on_main(move |w| w.set_blur(blur))
|
||||
}
|
||||
|
||||
/// Modifies the window's visibility.
|
||||
///
|
||||
/// If `false`, this will hide the window. If `true`, this will show the window.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue