Add Window::set_transparent

Provide a hint to system compositor whether the window is transparent or
not. Only implemented on macOS and Wayland for now.
This commit is contained in:
Kirill Chibisov 2023-01-15 23:39:36 +03:00 committed by GitHub
parent 6f60c7a6cc
commit 62ce14a013
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 84 additions and 1 deletions

View file

@ -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

View file

@ -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<bool> {

View file

@ -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)
}

View file

@ -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))

View file

@ -431,6 +431,9 @@ impl<T: 'static> EventLoop<T> {
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

View file

@ -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.

View file

@ -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<bool>,
/// Wether the window is transparent.
pub transparent: Cell<bool>,
/// Visible cursor or not.
cursor_visible: Cell<bool>,
@ -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(&region.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,

View file

@ -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);

View file

@ -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),

View file

@ -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) {}

View file

@ -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
}

View file

@ -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();

View file

@ -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.