mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-26 21:58:10 +01:00
Fix windows not resizing when spawning very quickly
This commit is contained in:
parent
8621d87938
commit
15d5778dab
5 changed files with 165 additions and 60 deletions
|
@ -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);
|
||||
|
||||
|
|
101
src/handlers.rs
101
src/handlers.rs
|
@ -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!(),
|
||||
|
|
57
src/state.rs
57
src/state.rs
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>)>),
|
||||
|
|
Loading…
Reference in a new issue