mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-27 21:58:18 +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,
|
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)]
|
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
|
||||||
pub struct ModifierMask(u8);
|
pub struct ModifierMask(u8);
|
||||||
|
|
||||||
|
|
101
src/handlers.rs
101
src/handlers.rs
|
@ -4,14 +4,16 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::utils,
|
backend::renderer::utils,
|
||||||
delegate_compositor, delegate_data_device, delegate_fractional_scale, delegate_output,
|
delegate_compositor, delegate_data_device, delegate_fractional_scale, delegate_output,
|
||||||
delegate_presentation, delegate_relative_pointer, delegate_seat, delegate_shm,
|
delegate_presentation, delegate_relative_pointer, delegate_seat, delegate_shm,
|
||||||
delegate_viewporter, delegate_xdg_shell,
|
delegate_viewporter, delegate_xdg_shell,
|
||||||
desktop::{
|
desktop::{
|
||||||
find_popup_root_surface, PopupKeyboardGrab, PopupKind, PopupPointerGrab,
|
find_popup_root_surface, utils::surface_primary_scanout_output, PopupKeyboardGrab,
|
||||||
PopupUngrabStrategy, Window,
|
PopupKind, PopupPointerGrab, PopupUngrabStrategy, Window,
|
||||||
},
|
},
|
||||||
input::{
|
input::{
|
||||||
pointer::{CursorImageStatus, Focus},
|
pointer::{CursorImageStatus, Focus},
|
||||||
|
@ -48,7 +50,7 @@ use smithay::{
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::Backend,
|
backend::Backend,
|
||||||
state::{ClientState, State, WithState},
|
state::{ClientState, State, WithState},
|
||||||
window::window_state::WindowResizeState,
|
window::{window_state::WindowResizeState, WindowBlocker, BLOCKER_COUNTER},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<B: Backend> BufferHandler for State<B> {
|
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 {
|
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);
|
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.windows.push(window.clone());
|
||||||
// self.space.map_element(window.clone(), (0, 0), true);
|
// 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| {
|
self.loop_handle.insert_idle(move |data| {
|
||||||
data.state
|
data.state
|
||||||
.seat
|
.seat
|
||||||
|
@ -263,22 +330,6 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
||||||
SERIAL_COUNTER.next_serial(),
|
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) {
|
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
|
||||||
|
@ -404,8 +455,18 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
||||||
match &configure {
|
match &configure {
|
||||||
Configure::Toplevel(configure) => {
|
Configure::Toplevel(configure) => {
|
||||||
if configure.serial >= serial {
|
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);
|
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!(),
|
Configure::Popup(_) => todo!(),
|
||||||
|
|
57
src/state.rs
57
src/state.rs
|
@ -11,7 +11,7 @@ use std::{
|
||||||
os::{fd::AsRawFd, unix::net::UnixStream},
|
os::{fd::AsRawFd, unix::net::UnixStream},
|
||||||
path::Path,
|
path::Path,
|
||||||
process::Stdio,
|
process::Stdio,
|
||||||
sync::{Arc, Mutex}, time::Duration,
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
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
|
/// Schedule something to be done when windows have finished committing and have become
|
||||||
/// idle.
|
/// 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
|
where
|
||||||
F: FnOnce(&mut CalloopData<B>) + 'static,
|
F: FnOnce(&mut CalloopData<B>) + 'static,
|
||||||
{
|
{
|
||||||
tracing::debug!("scheduling on_commit");
|
// tracing::debug!("scheduling on_commit");
|
||||||
self.loop_handle.insert_idle(|data| {
|
// tracing::debug!("win len is {}", windows.len());
|
||||||
tracing::debug!("running idle cb");
|
|
||||||
tracing::debug!("win len is {}", windows.len());
|
|
||||||
for window in windows.iter() {
|
for window in windows.iter() {
|
||||||
window.with_state(|state| {
|
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))
|
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.loop_handle.insert_idle(|data| {
|
||||||
data.state.schedule_on_commit(windows, on_commit);
|
schedule_on_commit(data, windows, on_commit);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
on_commit(data);
|
on_commit(data);
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: Backend> State<B> {
|
impl<B: Backend> State<B> {
|
||||||
|
|
|
@ -4,13 +4,18 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use std::sync::atomic::AtomicU32;
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::Window,
|
desktop::Window,
|
||||||
reexports::{
|
reexports::{
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||||
wayland_server::protocol::wl_surface::WlSurface,
|
wayland_server::protocol::wl_surface::WlSurface,
|
||||||
},
|
},
|
||||||
wayland::seat::WaylandFocus,
|
wayland::{
|
||||||
|
compositor::{Blocker, BlockerState},
|
||||||
|
seat::WaylandFocus,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -104,8 +109,10 @@ pub fn toggle_floating<B: Backend>(state: &mut State<B>, window: &Window) {
|
||||||
});
|
});
|
||||||
|
|
||||||
let clone = window.clone();
|
let clone = window.clone();
|
||||||
state.schedule_on_commit(render, move |data| {
|
state.loop_handle.insert_idle(move |data| {
|
||||||
data.state.space.raise_element(&clone, true);
|
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 location: (i32, i32),
|
||||||
pub floating: bool,
|
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::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
|
fmt,
|
||||||
sync::atomic::{AtomicU32, Ordering},
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ pub struct WindowState {
|
||||||
/// [`resize_state`]: WindowState#structfield.resize_state
|
/// [`resize_state`]: WindowState#structfield.resize_state
|
||||||
/// [`XdgShellHandler.ack_configure()`]: smithay::wayland::shell::xdg::XdgShellHandler#method.ack_configure
|
/// [`XdgShellHandler.ack_configure()`]: smithay::wayland::shell::xdg::XdgShellHandler#method.ack_configure
|
||||||
/// [`CompositorHandler.commit()`]: smithay::wayland::compositor::CompositorHandler#tymethod.commit
|
/// [`CompositorHandler.commit()`]: smithay::wayland::compositor::CompositorHandler#tymethod.commit
|
||||||
#[derive(Debug, Default)]
|
#[derive(Default, Clone)]
|
||||||
pub enum WindowResizeState {
|
pub enum WindowResizeState {
|
||||||
/// The window doesn't need to be moved.
|
/// The window doesn't need to be moved.
|
||||||
#[default]
|
#[default]
|
||||||
|
@ -78,6 +79,16 @@ pub enum WindowResizeState {
|
||||||
Acknowledged(Point<i32, Logical>),
|
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 {
|
pub enum Float {
|
||||||
/// The previous location and size of the window when it was floating, if any.
|
/// The previous location and size of the window when it was floating, if any.
|
||||||
Tiled(Option<(Point<i32, Logical>, Size<i32, Logical>)>),
|
Tiled(Option<(Point<i32, Logical>, Size<i32, Logical>)>),
|
||||||
|
|
Loading…
Reference in a new issue