Fix windows not resizing when spawning very quickly

This commit is contained in:
Ottatop 2023-07-16 20:44:18 -05:00 committed by Ottatop
parent 8621d87938
commit 15d5778dab
5 changed files with 165 additions and 60 deletions

View file

@ -119,7 +119,7 @@ pub enum Modifier {
Super = 0b0000_1000,
}
/// A bitmask of [Modifiers] for the purpose of hashing.
/// A bitmask of [`Modifier`]s for the purpose of hashing.
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
pub struct ModifierMask(u8);

View file

@ -4,14 +4,16 @@
//
// SPDX-License-Identifier: MPL-2.0
use std::time::Duration;
use smithay::{
backend::renderer::utils,
delegate_compositor, delegate_data_device, delegate_fractional_scale, delegate_output,
delegate_presentation, delegate_relative_pointer, delegate_seat, delegate_shm,
delegate_viewporter, delegate_xdg_shell,
desktop::{
find_popup_root_surface, PopupKeyboardGrab, PopupKind, PopupPointerGrab,
PopupUngrabStrategy, Window,
find_popup_root_surface, utils::surface_primary_scanout_output, PopupKeyboardGrab,
PopupKind, PopupPointerGrab, PopupUngrabStrategy, Window,
},
input::{
pointer::{CursorImageStatus, Focus},
@ -48,7 +50,7 @@ use smithay::{
use crate::{
backend::Backend,
state::{ClientState, State, WithState},
window::window_state::WindowResizeState,
window::{window_state::WindowResizeState, WindowBlocker, BLOCKER_COUNTER},
};
impl<B: Backend> BufferHandler for State<B> {
@ -122,6 +124,12 @@ impl<B: Backend> CompositorHandler for State<B> {
}
});
}
// let states = self
// .windows
// .iter()
// .map(|win| win.with_state(|state| state.resize_state.clone()))
// .collect::<Vec<_>>();
// tracing::debug!("states: {states:?}");
}
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
@ -250,8 +258,67 @@ impl<B: Backend> XdgShellHandler for State<B> {
tracing::debug!("new window, tags are {:?}", state.tags);
});
let windows_on_output = self
.windows
.iter()
.filter(|win| {
win.with_state(|state| {
self.focus_state
.focused_output
.as_ref()
.unwrap()
.with_state(|op_state| {
op_state
.tags
.iter()
.any(|tag| state.tags.iter().any(|tg| tg == tag))
})
})
})
.cloned()
.collect::<Vec<_>>();
self.windows.push(window.clone());
// self.space.map_element(window.clone(), (0, 0), true);
if let Some(focused_output) = self.focus_state.focused_output.clone() {
focused_output.with_state(|state| {
let first_tag = state.focused_tags().next();
if let Some(first_tag) = first_tag {
first_tag.layout().layout(
self.windows.clone(),
state.focused_tags().cloned().collect(),
&self.space,
&focused_output,
);
}
});
BLOCKER_COUNTER.store(1, std::sync::atomic::Ordering::SeqCst);
tracing::debug!(
"blocker {}",
BLOCKER_COUNTER.load(std::sync::atomic::Ordering::SeqCst)
);
for win in windows_on_output.iter() {
compositor::add_blocker(win.toplevel().wl_surface(), WindowBlocker);
}
let clone = window.clone();
self.loop_handle.insert_idle(|data| {
crate::state::schedule_on_commit(data, vec![clone], move |data| {
BLOCKER_COUNTER.store(0, std::sync::atomic::Ordering::SeqCst);
tracing::debug!(
"blocker {}",
BLOCKER_COUNTER.load(std::sync::atomic::Ordering::SeqCst)
);
for client in windows_on_output
.iter()
.filter_map(|win| win.toplevel().wl_surface().client())
{
data.state
.client_compositor_state(&client)
.blocker_cleared(&mut data.state, &data.display.handle())
}
})
});
}
self.loop_handle.insert_idle(move |data| {
data.state
.seat
@ -263,22 +330,6 @@ impl<B: Backend> XdgShellHandler for State<B> {
SERIAL_COUNTER.next_serial(),
);
});
self.loop_handle.insert_idle(move |data| {
if let Some(focused_output) = &data.state.focus_state.focused_output {
focused_output.with_state(|state| {
let first_tag = state.focused_tags().next();
if let Some(first_tag) = first_tag {
first_tag.layout().layout(
data.state.windows.clone(),
state.focused_tags().cloned().collect(),
&data.state.space,
focused_output,
);
}
});
}
});
}
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
@ -404,8 +455,18 @@ impl<B: Backend> XdgShellHandler for State<B> {
match &configure {
Configure::Toplevel(configure) => {
if configure.serial >= serial {
tracing::debug!("acked configure, new loc is {:?}", new_loc);
// tracing::debug!("acked configure, new loc is {:?}", new_loc);
state.resize_state = WindowResizeState::Acknowledged(new_loc);
if let Some(focused_output) =
self.focus_state.focused_output.clone()
{
window.send_frame(
&focused_output,
self.clock.now(),
Some(Duration::ZERO),
surface_primary_scanout_output,
);
}
}
}
Configure::Popup(_) => todo!(),

View file

@ -11,7 +11,7 @@ use std::{
os::{fd::AsRawFd, unix::net::UnixStream},
path::Path,
process::Stdio,
sync::{Arc, Mutex}, time::Duration,
sync::{Arc, Mutex},
};
use crate::{
@ -676,45 +676,58 @@ impl<B: Backend> State<B> {
})
})
});
for window in render.iter() {
// INFO: Here we send a frame with a duration of 0. This is because some windows won't
// | send a commit when they're not visible. More info in smithay::desktop::utils::send_frames_surface_tree
window.send_frame(output, self.clock.now(), Some(Duration::ZERO), surface_primary_scanout_output);
}
self.schedule_on_commit(render, |data| {
for win in do_not_render {
data.state.space.unmap_elem(&win);
}
});
}
let clone = render.clone();
self.loop_handle.insert_idle(|data| {
schedule_on_commit(data, clone, |dt| {
for win in do_not_render {
dt.state.space.unmap_elem(&win);
}
})
});
// let blocker = WindowBlockerAll::new(render.clone());
// blocker.insert_into_loop(self);
// for win in render.iter() {
// compositor::add_blocker(win.toplevel().wl_surface(), blocker.clone());
// }
// let (blocker, source) = WindowBlocker::block_all::<B>(render.clone());
// for win in render.iter() {
// compositor::add_blocker(win.toplevel().wl_surface(), blocker.clone());
// }
// self.loop_handle.insert_idle(move |data| source(render.clone(), data));
// let (blocker, source) = WindowBlocker::new::<B>(render.clone());
// for win in render.iter() {
// compositor::add_blocker(win.toplevel().wl_surface(), blocker.clone());
// }
// self.loop_handle.insert_idle(move |data| source(render.clone(), render.clone(), data));
}
}
/// Schedule something to be done when windows have finished committing and have become
/// idle.
pub fn schedule_on_commit<F>(&mut self, windows: Vec<Window>, on_commit: F)
pub fn schedule_on_commit<F, B: Backend>(data: &mut CalloopData<B>, windows: Vec<Window>, on_commit: F)
where
F: FnOnce(&mut CalloopData<B>) + 'static,
{
tracing::debug!("scheduling on_commit");
self.loop_handle.insert_idle(|data| {
tracing::debug!("running idle cb");
tracing::debug!("win len is {}", windows.len());
// tracing::debug!("scheduling on_commit");
// tracing::debug!("win len is {}", windows.len());
for window in windows.iter() {
window.with_state(|state| {
tracing::debug!("win state is {:?}", state.resize_state);
// tracing::debug!("win state is {:?}", state.resize_state);
});
if window.with_state(|state| !matches!(state.resize_state, WindowResizeState::Idle))
{
tracing::debug!("some windows not idle");
// tracing::debug!("some windows not idle");
data.state.loop_handle.insert_idle(|data| {
data.state.schedule_on_commit(windows, on_commit);
schedule_on_commit(data, windows, on_commit);
});
return;
}
}
on_commit(data);
});
}
}
impl<B: Backend> State<B> {

View file

@ -4,13 +4,18 @@
//
// SPDX-License-Identifier: MPL-2.0
use std::sync::atomic::AtomicU32;
use smithay::{
desktop::Window,
reexports::{
wayland_protocols::xdg::shell::server::xdg_toplevel,
wayland_server::protocol::wl_surface::WlSurface,
},
wayland::seat::WaylandFocus,
wayland::{
compositor::{Blocker, BlockerState},
seat::WaylandFocus,
},
};
use crate::{
@ -104,8 +109,10 @@ pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &Window) {
});
let clone = window.clone();
state.schedule_on_commit(render, move |data| {
data.state.space.raise_element(&clone, true);
state.loop_handle.insert_idle(move |data| {
crate::state::schedule_on_commit(data, render, move |dt| {
dt.state.space.raise_element(&clone, true);
});
});
}
@ -120,3 +127,16 @@ pub struct WindowProperties {
pub location: (i32, i32),
pub floating: bool,
}
pub struct WindowBlocker;
pub static BLOCKER_COUNTER: AtomicU32 = AtomicU32::new(0);
impl Blocker for WindowBlocker {
fn state(&self) -> BlockerState {
if BLOCKER_COUNTER.load(std::sync::atomic::Ordering::SeqCst) > 0 {
BlockerState::Pending
} else {
BlockerState::Released
}
}
}

View file

@ -6,6 +6,7 @@
use std::{
cell::RefCell,
fmt,
sync::atomic::{AtomicU32, Ordering},
};
@ -63,7 +64,7 @@ pub struct WindowState {
/// [`resize_state`]: WindowState#structfield.resize_state
/// [`XdgShellHandler.ack_configure()`]: smithay::wayland::shell::xdg::XdgShellHandler#method.ack_configure
/// [`CompositorHandler.commit()`]: smithay::wayland::compositor::CompositorHandler#tymethod.commit
#[derive(Debug, Default)]
#[derive(Default, Clone)]
pub enum WindowResizeState {
/// The window doesn't need to be moved.
#[default]
@ -78,6 +79,16 @@ pub enum WindowResizeState {
Acknowledged(Point<i32, Logical>),
}
impl fmt::Debug for WindowResizeState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Idle => write!(f, "Idle"),
Self::Requested(_arg0, _arg1) => write!(f, "Requested"),
Self::Acknowledged(_arg0) => write!(f, "Acknowledged"),
}
}
}
pub enum Float {
/// The previous location and size of the window when it was floating, if any.
Tiled(Option<(Point<i32, Logical>, Size<i32, Logical>)>),