diff --git a/CHANGELOG.md b/CHANGELOG.md index bc628208..125e367b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ And please only add new entries to the top of this list, right below the `# Unre - **Breaking:** Remove the unstable `xlib_xconnection()` function from the private interface. - Added Orbital support for Redox OS - On X11, added `drag_resize_window` method. +- Added `Window::set_transparent` to provide a hint about transparency of the window on Wayland and macOS. # 0.27.5 diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 6e1ce364..78dc14fd 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -947,6 +947,8 @@ impl Window { pub fn set_title(&self, _title: &str) {} + pub fn set_transparent(&self, _transparent: bool) {} + pub fn set_visible(&self, _visibility: bool) {} pub fn is_visible(&self) -> Option { diff --git a/src/platform_impl/ios/window.rs b/src/platform_impl/ios/window.rs index 8435faeb..b4ed3dcd 100644 --- a/src/platform_impl/ios/window.rs +++ b/src/platform_impl/ios/window.rs @@ -43,6 +43,10 @@ impl Inner { debug!("`Window::set_title` is ignored on iOS") } + pub fn set_transparent(&self, _transparent: bool) { + debug!("`Window::set_transparent` is ignored on iOS") + } + pub fn set_visible(&self, visible: bool) { self.window.setHidden(!visible) } diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 8ddc9a7a..cd3863e9 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -324,6 +324,11 @@ impl Window { x11_or_wayland!(match self; Window(w) => w.set_title(title)); } + #[inline] + pub fn set_transparent(&self, transparent: bool) { + x11_or_wayland!(match self; Window(w) => w.set_transparent(transparent)); + } + #[inline] pub fn set_visible(&self, visible: bool) { x11_or_wayland!(match self; Window(w) => w.set_visible(visible)) diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index cf62b8d0..4421b463 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -431,6 +431,9 @@ impl EventLoop { window_handle.window.resize(size.width, size.height); window_handle.window.refresh(); + // Update the opaque region. + window_handle.set_transparent(window_handle.transparent.get()); + // Mark that refresh isn't required, since we've done it right now. state .window_user_requests diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index 7b00027d..fdcee917 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -261,6 +261,9 @@ impl Window { window_requests.clone(), ); + // Set opaque region. + window_handle.set_transparent(attributes.transparent); + // Set resizable state, so we can determine how to handle `Window::set_inner_size`. window_handle.is_resizable.set(attributes.resizable); @@ -332,6 +335,11 @@ impl Window { self.send_request(WindowRequest::Title(title.to_owned())); } + #[inline] + pub fn set_transparent(&self, transparent: bool) { + self.send_request(WindowRequest::Transparent(transparent)); + } + #[inline] pub fn set_visible(&self, _visible: bool) { // Not possible on Wayland. diff --git a/src/platform_impl/linux/wayland/window/shim.rs b/src/platform_impl/linux/wayland/window/shim.rs index 0b4fedf9..d43df558 100644 --- a/src/platform_impl/linux/wayland/window/shim.rs +++ b/src/platform_impl/linux/wayland/window/shim.rs @@ -80,6 +80,9 @@ pub enum WindowRequest { /// Enable IME on the given window. AllowIme(bool), + /// Mark the window as opaque. + Transparent(bool), + /// Request Attention. /// /// `None` unsets the attention request. @@ -154,6 +157,9 @@ pub struct WindowHandle { /// Allow IME events for that window. pub ime_allowed: Cell, + /// Wether the window is transparent. + pub transparent: Cell, + /// Visible cursor or not. cursor_visible: Cell, @@ -194,6 +200,7 @@ impl WindowHandle { pending_window_requests, cursor_icon: Cell::new(CursorIcon::Default), is_resizable: Cell::new(true), + transparent: Cell::new(false), cursor_grab_mode: Cell::new(CursorGrabMode::None), cursor_visible: Cell::new(true), pointers: Vec::new(), @@ -349,6 +356,19 @@ impl WindowHandle { } } + pub fn set_transparent(&self, transparent: bool) { + self.transparent.set(transparent); + let surface = self.window.surface(); + if transparent { + surface.set_opaque_region(None); + } else { + let region = self.compositor.create_region(); + region.add(0, 0, i32::MAX, i32::MAX); + surface.set_opaque_region(Some(®ion.detach())); + region.destroy(); + } + } + pub fn set_ime_allowed(&self, allowed: bool, event_sink: &mut EventSink) { if self.ime_allowed.get() == allowed { return; @@ -452,6 +472,13 @@ pub fn handle_window_requests(winit_state: &mut WinitState) { WindowRequest::Minimize => { window_handle.window.set_minimized(); } + WindowRequest::Transparent(transparent) => { + window_handle.set_transparent(transparent); + + // This requires surface commit. + let window_request = window_user_requests.get_mut(window_id).unwrap(); + window_request.redraw_requested = true; + } WindowRequest::Decorate(decorate) => { let decorations = match decorate { true => Decorations::FollowServer, diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index f0a8bf46..ec91c13b 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -903,6 +903,9 @@ impl UnownedWindow { .expect("Failed to set window title"); } + #[inline] + pub fn set_transparent(&self, _transparent: bool) {} + fn set_decorations_inner(&self, decorations: bool) -> util::Flusher<'_> { self.shared_state_lock().is_decorated = decorations; let mut hints = self.xconn.get_motif_hints(self.xwindow); diff --git a/src/platform_impl/macos/window.rs b/src/platform_impl/macos/window.rs index 042c52a9..e6cedd91 100644 --- a/src/platform_impl/macos/window.rs +++ b/src/platform_impl/macos/window.rs @@ -506,6 +506,10 @@ impl WinitWindow { util::set_title_sync(self, title); } + pub fn set_transparent(&self, transparent: bool) { + self.setOpaque(!transparent) + } + pub fn set_visible(&self, visible: bool) { match visible { true => util::make_key_and_order_front_sync(self), diff --git a/src/platform_impl/orbital/window.rs b/src/platform_impl/orbital/window.rs index f08f6d23..fd1aa9eb 100644 --- a/src/platform_impl/orbital/window.rs +++ b/src/platform_impl/orbital/window.rs @@ -240,6 +240,9 @@ impl Window { .expect("failed to set title"); } + #[inline] + pub fn set_transparent(&self, _transparent: bool) {} + #[inline] pub fn set_visible(&self, _visibility: bool) {} diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index 4d335c94..4a558298 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -87,6 +87,8 @@ impl Window { self.canvas.borrow().set_attribute("alt", title); } + pub fn set_transparent(&self, _transparent: bool) {} + pub fn set_visible(&self, _visible: bool) { // Intentionally a no-op } diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 9cf6278c..cbf6dadc 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -113,6 +113,8 @@ impl Window { } } + pub fn set_transparent(&self, _transparent: bool) {} + #[inline] pub fn set_visible(&self, visible: bool) { let window = self.window.clone(); diff --git a/src/window.rs b/src/window.rs index 1c8b2db9..f9e52338 100644 --- a/src/window.rs +++ b/src/window.rs @@ -306,7 +306,9 @@ impl WindowBuilder { /// Sets whether the background of the window should be transparent. /// /// If this is `true`, writing colors with alpha values different than - /// `1.0` will produce a transparent window. + /// `1.0` will produce a transparent window. On some platforms this + /// is more of a hint for the system and you'd still have the alpha + /// buffer. To control it see [`Window::set_transparent`]. /// /// The default is `false`. #[inline] @@ -735,6 +737,23 @@ impl Window { self.window.set_title(title) } + /// Change the window transparency state. + /// + /// This is just a hint that may not change anything about + /// the window transparency, however doing a missmatch between + /// the content of your window and this hint may result in + /// visual artifacts. + /// + /// The default value follows the [`WindowBuilder::with_transparent`]. + /// + /// ## Platform-specific + /// + /// - **Windows / X11 / Web / iOS / Android / Orbital:** Unsupported. + #[inline] + pub fn set_transparent(&self, transparent: bool) { + self.window.set_transparent(transparent) + } + /// Modifies the window's visibility. /// /// If `false`, this will hide the window. If `true`, this will show the window.