Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions examples/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ impl Application {
Action::ToggleDecorations => window.toggle_decorations(),
Action::ToggleFullscreen => window.toggle_fullscreen(),
Action::ToggleMaximize => window.toggle_maximize(),
Action::ToggleVisible => window.toggle_visible(),
Action::ToggleImeInput => window.toggle_ime(),
Action::Minimize => window.minimize(),
Action::NextCursor => window.next_cursor(),
Expand Down Expand Up @@ -548,6 +549,7 @@ struct WindowState {
named_idx: usize,
custom_idx: usize,
cursor_hidden: bool,
visible: bool,
}

impl WindowState {
Expand Down Expand Up @@ -582,6 +584,7 @@ impl WindowState {
ime,
cursor_position: Default::default(),
cursor_hidden: Default::default(),
visible: true,
modifiers: Default::default(),
occluded: Default::default(),
rotated: Default::default(),
Expand All @@ -605,6 +608,11 @@ impl WindowState {
self.window.set_minimized(true);
}

pub fn toggle_visible(&mut self) {
self.visible = !self.visible;
self.window.set_visible(self.visible);
}

pub fn cursor_moved(&mut self, position: PhysicalPosition<f64>) {
self.cursor_position = Some(position);
if self.ime {
Expand Down Expand Up @@ -900,6 +908,7 @@ enum Action {
ToggleResizable,
ToggleFullscreen,
ToggleMaximize,
ToggleVisible,
Minimize,
NextCursor,
NextCustomCursor,
Expand Down Expand Up @@ -931,6 +940,7 @@ impl Action {
Action::ToggleResizable => "Toggle window resizable state",
Action::ToggleFullscreen => "Toggle fullscreen",
Action::ToggleMaximize => "Maximize",
Action::ToggleVisible => "Toggle visible",
Action::Minimize => "Minimize",
Action::ToggleResizeIncrements => "Use resize increments when resizing window",
Action::NextCursor => "Advance the cursor to the next value",
Expand Down Expand Up @@ -1072,6 +1082,8 @@ const KEY_BINDINGS: &[Binding<&'static str>] = &[
Binding::new("P", ModifiersState::CONTROL, Action::ToggleResizeIncrements),
Binding::new("R", ModifiersState::CONTROL, Action::ToggleResizable),
Binding::new("R", ModifiersState::ALT, Action::RequestResize),
// V.
Binding::new("V", ModifiersState::CONTROL, Action::ToggleVisible),
// M.
Binding::new("M", ModifiersState::CONTROL, Action::ToggleMaximize),
Binding::new("M", ModifiersState::ALT, Action::Minimize),
Expand Down
4 changes: 4 additions & 0 deletions src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,7 @@ The migration guide could reference other migration examples in the current
changelog entry.

## Unreleased

### Added

- Implement `Window::set_visible` via null-buffer unmap/remap on wayland.
9 changes: 9 additions & 0 deletions src/platform_impl/linux/wayland/event_loop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,15 @@ impl<T: 'static> EventLoop<T> {
let mut window =
state.windows.get_mut().get_mut(window_id).unwrap().lock().unwrap();

if !window.is_visible() {
window_requests.get(window_id).unwrap().take_redraw_requested();
return None;
}

if window.is_unmapped() {
return None;
}

if window.frame_callback_state() == FrameCallbackState::Requested {
return None;
}
Expand Down
22 changes: 13 additions & 9 deletions src/platform_impl/linux/wayland/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,15 +282,19 @@ impl WindowHandler for WinitState {
self.window_compositor_updates.len() - 1
};

// Populate the configure to the window.
self.window_compositor_updates[pos].resized |= self
.windows
.get_mut()
.get_mut(&window_id)
.expect("got configure for dead window.")
.lock()
.unwrap()
.configure(configure, &self.shm, &self.subcompositor_state);
// Populate the configure to the window and clear unmapped flag.
{
let mut window_state = self
.windows
.get_mut()
.get_mut(&window_id)
.expect("got configure for dead window.")
.lock()
.unwrap();
self.window_compositor_updates[pos].resized |=
window_state.configure(configure, &self.shm, &self.subcompositor_state);
window_state.clear_unmapped();
}

// NOTE: configure demands wl_surface::commit, however winit doesn't commit on behalf of the
// users, since it can break a lot of things, thus it'll ask users to redraw instead.
Expand Down
37 changes: 34 additions & 3 deletions src/platform_impl/linux/wayland/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ impl Window {
// Non-resizable implies that the min and max sizes are set to the same value.
window_state.set_resizable(attributes.resizable);

// Set initial visibility.
window_state.set_visible(attributes.visible);

// Set startup mode.
match attributes.fullscreen.map(Into::into) {
Some(Fullscreen::Exclusive(_)) => {
Expand Down Expand Up @@ -250,13 +253,41 @@ impl Window {
}

#[inline]
pub fn set_visible(&self, _visible: bool) {
// Not possible on Wayland.
pub fn set_visible(&self, visible: bool) {
if visible {
let mut state = self.window_state.lock().unwrap();
if state.is_visible() {
return;
}
state.set_visible(true);
state.frame_callback_reset();
if state.is_unmapped() {
// Re-send xdg_toplevel state to trigger a configure cycle
let title = state.title().to_owned();
state.set_title(title);
drop(state);
self.surface().commit();
return;
}
drop(state);
self.request_redraw();
} else {
{
let mut state = self.window_state.lock().unwrap();
if !state.is_visible() {
return;
}
state.set_visible(false);
state.set_unmapped();
}
self.surface().attach(None, 0, 0);
self.surface().commit();
}
}

#[inline]
pub fn is_visible(&self) -> Option<bool> {
None
Some(self.window_state.lock().unwrap().is_visible())
}

#[inline]
Expand Down
34 changes: 34 additions & 0 deletions src/platform_impl/linux/wayland/window/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@ pub struct WindowState {
// field drop order guarantees.
/// The window frame, which is created from the configure request.
frame: Option<WinitFrame>,

/// Whether the window is visible.
visible: bool,

/// Whether the surface was unmapped via null buffer and needs a configure cycle before the
/// next buffer attach.
unmapped: bool,
}

impl WindowState {
Expand Down Expand Up @@ -219,6 +226,8 @@ impl WindowState {
title: String::default(),
transparent: false,
viewport,
visible: true,
unmapped: false,
window,
}
}
Expand Down Expand Up @@ -584,6 +593,31 @@ impl WindowState {
self.last_configure.is_some()
}

#[inline]
pub fn is_visible(&self) -> bool {
self.visible
}

#[inline]
pub fn set_visible(&mut self, visible: bool) {
self.visible = visible;
}

#[inline]
pub fn is_unmapped(&self) -> bool {
self.unmapped
}

#[inline]
pub fn set_unmapped(&mut self) {
self.unmapped = true;
}

#[inline]
pub fn clear_unmapped(&mut self) {
self.unmapped = false;
}

#[inline]
pub fn is_decorated(&mut self) -> bool {
let csd = self
Expand Down
4 changes: 2 additions & 2 deletions src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ impl Window {
///
/// ## Platform-specific
///
/// - **Android / Wayland / Web:** Unsupported.
/// - **Android / Web:** Unsupported.
/// - **iOS:** Can only be called on the main thread.
#[inline]
pub fn set_visible(&self, visible: bool) {
Expand All @@ -983,7 +983,7 @@ impl Window {
/// ## Platform-specific
///
/// - **X11:** Not implemented.
/// - **Wayland / iOS / Android / Web:** Unsupported.
/// - **iOS / Android / Web:** Unsupported.
#[inline]
pub fn is_visible(&self) -> Option<bool> {
let _span = tracing::debug_span!("winit::Window::is_visible",).entered();
Expand Down
Loading