mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-26 21:58:10 +01:00
Fix flickering when swapping tiled windows
This commit is contained in:
parent
5423c10bc7
commit
9f65bc386e
7 changed files with 166 additions and 43 deletions
|
@ -100,5 +100,3 @@ You can find the rest of the controls in the [`example_config`](api/lua/example_
|
|||
|
||||
## A Small Note
|
||||
This is currently just a summer project I'm working on, but I hope that I can work on it enough that it becomes somewhat usable! If development slows down during the rest of the year, it's because :star:university:star:.
|
||||
|
||||
Also the only layout is kinda wonk right now if you close all but one window
|
||||
|
|
|
@ -375,7 +375,11 @@ pub fn run_winit() -> Result<(), Box<dyn Error>> {
|
|||
TimeoutAction::ToDuration(Duration::from_millis(6))
|
||||
})?;
|
||||
|
||||
event_loop.run(None, &mut CalloopData { display, state }, |_data| {})?;
|
||||
event_loop.run(
|
||||
Some(Duration::from_millis(6)),
|
||||
&mut CalloopData { display, state },
|
||||
|_data| {},
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -40,14 +40,20 @@ impl<B: Backend> PointerGrab<State<B>> for MoveSurfaceGrab<State<B>> {
|
|||
return;
|
||||
}
|
||||
|
||||
let tiled = WindowState::with_state(&self.window, |state| {
|
||||
matches!(state.floating, Float::Tiled(_))
|
||||
});
|
||||
data.space.raise_element(&self.window, false);
|
||||
|
||||
// tracing::info!("window geo is: {:?}", self.window.geometry());
|
||||
// tracing::info!("loc is: {:?}", data.space.element_location(&self.window));
|
||||
|
||||
let tiled = WindowState::with_state(&self.window, |state| state.floating.is_tiled());
|
||||
|
||||
if tiled {
|
||||
// INFO: this is being used instead of space.element_under(event.location) because that
|
||||
// | uses the bounding box, which is different from the actual geometry
|
||||
let window_under = data
|
||||
.space
|
||||
.elements()
|
||||
.rev()
|
||||
.find(|&win| {
|
||||
if let Some(loc) = data.space.element_location(win) {
|
||||
let size = win.geometry().size;
|
||||
|
@ -64,15 +70,13 @@ impl<B: Backend> PointerGrab<State<B>> for MoveSurfaceGrab<State<B>> {
|
|||
return;
|
||||
}
|
||||
|
||||
let window_under_floating = WindowState::with_state(&window_under, |state| {
|
||||
matches!(state.floating, Float::Floating)
|
||||
});
|
||||
let window_under_floating =
|
||||
WindowState::with_state(&window_under, |state| state.floating.is_floating());
|
||||
|
||||
if window_under_floating {
|
||||
return;
|
||||
}
|
||||
|
||||
tracing::info!("{:?}, {:?}", self.window.geometry(), self.window.bbox());
|
||||
data.swap_window_positions(&self.window, &window_under);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -32,8 +32,8 @@ use smithay::{
|
|||
dmabuf,
|
||||
fractional_scale::{self, FractionalScaleHandler},
|
||||
shell::xdg::{
|
||||
PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData, XdgShellHandler,
|
||||
XdgShellState, XdgToplevelSurfaceData,
|
||||
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData,
|
||||
XdgShellHandler, XdgShellState, XdgToplevelSurfaceData,
|
||||
},
|
||||
shm::{ShmHandler, ShmState},
|
||||
},
|
||||
|
@ -43,6 +43,7 @@ use crate::{
|
|||
backend::Backend,
|
||||
layout::Layout,
|
||||
state::{ClientState, State},
|
||||
window::window_state::{WindowResizeState, WindowState},
|
||||
};
|
||||
|
||||
impl<B: Backend> BufferHandler for State<B> {
|
||||
|
@ -86,8 +87,6 @@ impl<B: Backend> CompositorHandler for State<B> {
|
|||
}
|
||||
|
||||
fn commit(&mut self, surface: &WlSurface) {
|
||||
// println!("CompositorHandler commit()");
|
||||
|
||||
utils::on_commit_buffer_handler::<Self>(surface);
|
||||
|
||||
if !compositor::is_sync_subsurface(surface) {
|
||||
|
@ -105,6 +104,17 @@ impl<B: Backend> CompositorHandler for State<B> {
|
|||
ensure_initial_configure(surface, self);
|
||||
|
||||
crate::grab::resize_grab::handle_commit(self, surface);
|
||||
|
||||
if let Some(window) = self.window_for_surface(surface) {
|
||||
WindowState::with_state(&window, |state| {
|
||||
if let WindowResizeState::WaitingForCommit(new_pos) = state.resize_state {
|
||||
// tracing::info!("Committing, new location");
|
||||
state.resize_state = WindowResizeState::Idle;
|
||||
self.space.map_element(window.clone(), new_pos, false);
|
||||
}
|
||||
// state.resize_state
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
|
||||
|
@ -127,13 +137,14 @@ fn ensure_initial_configure<B: Backend>(surface: &WlSurface, state: &mut State<B
|
|||
// println!("initial_configure_sent is {}", initial_configure_sent);
|
||||
|
||||
if !initial_configure_sent {
|
||||
tracing::info!("Initial configure");
|
||||
window.toplevel().send_configure();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(popup) = state.popup_manager.find_popup(surface) {
|
||||
let PopupKind::Xdg(ref popup) = popup;
|
||||
let PopupKind::Xdg(popup) = &popup;
|
||||
let initial_configure_sent = compositor::with_states(surface, |states| {
|
||||
states
|
||||
.data_map
|
||||
|
@ -315,6 +326,26 @@ impl<B: Backend> XdgShellHandler for State<B> {
|
|||
}
|
||||
}
|
||||
|
||||
fn ack_configure(&mut self, surface: WlSurface, configure: Configure) {
|
||||
// TODO: add serial to WaitingForAck
|
||||
if let Some(window) = self.window_for_surface(&surface) {
|
||||
WindowState::with_state(&window, |state| {
|
||||
if let WindowResizeState::WaitingForAck(serial, new_loc) = state.resize_state {
|
||||
match &configure {
|
||||
Configure::Toplevel(configure) => {
|
||||
// tracing::info!("acking before serial check");
|
||||
if configure.serial >= serial {
|
||||
// tracing::info!("acking, serial >=");
|
||||
state.resize_state = WindowResizeState::WaitingForCommit(new_loc);
|
||||
}
|
||||
}
|
||||
Configure::Popup(_) => todo!(),
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: impl the rest of the fns in XdgShellHandler
|
||||
}
|
||||
delegate_xdg_shell!(@<B: Backend> State<B>);
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
use smithay::desktop::Window;
|
||||
use smithay::{
|
||||
desktop::Window,
|
||||
utils::SERIAL_COUNTER,
|
||||
wayland::{compositor, shell::xdg::XdgToplevelSurfaceData},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backend::Backend,
|
||||
state::State,
|
||||
window::window_state::{Float, WindowState},
|
||||
window::window_state::{WindowResizeState, WindowState},
|
||||
};
|
||||
|
||||
use super::{Direction, Layout};
|
||||
|
@ -14,11 +18,11 @@ impl Layout {
|
|||
mut windows: Vec<Window>,
|
||||
side: Direction,
|
||||
) {
|
||||
windows.retain(|win| {
|
||||
WindowState::with_state(win, |state| matches!(state.floating, Float::Tiled(_)))
|
||||
});
|
||||
windows.retain(|win| WindowState::with_state(win, |state| state.floating.is_tiled()));
|
||||
match side {
|
||||
Direction::Left => {
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
|
||||
let window_count = windows.len();
|
||||
if window_count == 0 {
|
||||
return;
|
||||
|
@ -37,9 +41,31 @@ impl Layout {
|
|||
tl_state.size = Some(state.space.output_geometry(&output).unwrap().size);
|
||||
});
|
||||
|
||||
state
|
||||
.space
|
||||
.map_element(window, output.current_location(), false);
|
||||
WindowState::with_state(&window, |state| {
|
||||
state.resize_state =
|
||||
WindowResizeState::WaitingForAck(serial, output.current_location());
|
||||
});
|
||||
|
||||
// state.loop_handle.insert_idle(move |_calloop_data| {
|
||||
// window.toplevel().send_pending_configure();
|
||||
// });
|
||||
let initial_configure_sent =
|
||||
compositor::with_states(window.toplevel().wl_surface(), |states| {
|
||||
states
|
||||
.data_map
|
||||
.get::<XdgToplevelSurfaceData>()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.initial_configure_sent
|
||||
});
|
||||
if initial_configure_sent {
|
||||
window.toplevel().send_pending_configure();
|
||||
}
|
||||
|
||||
// state
|
||||
// .space
|
||||
// .map_element(window, output.current_location(), false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -55,9 +81,14 @@ impl Layout {
|
|||
tl_state.size = Some(size);
|
||||
});
|
||||
|
||||
state
|
||||
.space
|
||||
.map_element(first_window.clone(), output.current_location(), false);
|
||||
// state
|
||||
// .space
|
||||
// .map_element(first_window.clone(), output.current_location(), false);
|
||||
|
||||
WindowState::with_state(first_window, |state| {
|
||||
state.resize_state =
|
||||
WindowResizeState::WaitingForAck(serial, output.current_location());
|
||||
});
|
||||
|
||||
let window_count = windows.len() as i32;
|
||||
let height = output_size.h / window_count;
|
||||
|
@ -73,22 +104,33 @@ impl Layout {
|
|||
|
||||
let mut new_loc = output.current_location();
|
||||
new_loc.x = x;
|
||||
new_loc.y = i as i32 * height;
|
||||
new_loc.y = (i as i32) * height;
|
||||
|
||||
state.space.map_element(win.clone(), new_loc, false);
|
||||
// state.space.map_element(win.clone(), new_loc, false);
|
||||
WindowState::with_state(win, |state| {
|
||||
state.resize_state = WindowResizeState::WaitingForAck(serial, new_loc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
state.backend_data.reset_buffers(&output);
|
||||
|
||||
// INFO: We send configures when the event loop is idle so
|
||||
// | CompositorHandler::commit() sends the initial configure
|
||||
// TODO: maybe check if the initial configure was sent instead?
|
||||
state.loop_handle.insert_idle(|_calloop_data| {
|
||||
for win in windows {
|
||||
for win in windows {
|
||||
let initial_configure_sent =
|
||||
compositor::with_states(win.toplevel().wl_surface(), |states| {
|
||||
states
|
||||
.data_map
|
||||
.get::<XdgToplevelSurfaceData>()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.initial_configure_sent
|
||||
});
|
||||
if initial_configure_sent {
|
||||
win.toplevel().send_pending_configure();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Direction::Right => todo!(),
|
||||
Direction::Top => todo!(),
|
||||
|
|
|
@ -3,17 +3,24 @@ use std::cell::RefCell;
|
|||
use smithay::{
|
||||
desktop::Window,
|
||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||
utils::SERIAL_COUNTER,
|
||||
wayland::{compositor, seat::WaylandFocus},
|
||||
};
|
||||
|
||||
use crate::{backend::Backend, layout::Layout, state::State};
|
||||
use crate::{
|
||||
backend::Backend, layout::Layout, state::State, window::window_state::WindowResizeState,
|
||||
};
|
||||
|
||||
use self::window_state::{Float, WindowState};
|
||||
|
||||
pub mod window_state;
|
||||
|
||||
pub trait SurfaceState: Default + 'static {
|
||||
/// Access the [SurfaceState] associated with a [WlSurface]
|
||||
/// Access the [SurfaceState] associated with a [WlSurface].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if you use it within itself due to the use of a [RefCell].
|
||||
fn with_state<F, T>(wl_surface: &WlSurface, function: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
|
@ -39,8 +46,10 @@ impl<B: Backend> State<B> {
|
|||
pub fn swap_window_positions(&mut self, win1: &Window, win2: &Window) {
|
||||
let win1_loc = self.space.element_location(win1).unwrap(); // TODO: handle unwraps
|
||||
let win2_loc = self.space.element_location(win2).unwrap();
|
||||
let win1_geo = self.space.element_geometry(win1).unwrap();
|
||||
let win2_geo = self.space.element_geometry(win2).unwrap();
|
||||
let win1_geo = win1.geometry();
|
||||
let win2_geo = win2.geometry();
|
||||
// tracing::info!("win1: {:?}, {:?}", win1_loc, win1_geo);
|
||||
// tracing::info!("win2: {:?}, {:?}", win2_loc, win2_geo);
|
||||
|
||||
win1.toplevel().with_pending_state(|state| {
|
||||
state.size = Some(win2_geo.size);
|
||||
|
@ -49,11 +58,18 @@ impl<B: Backend> State<B> {
|
|||
state.size = Some(win1_geo.size);
|
||||
});
|
||||
|
||||
self.space.map_element(win1.clone(), win2_loc, false);
|
||||
self.space.map_element(win2.clone(), win1_loc, false);
|
||||
let serial = win1.toplevel().send_configure();
|
||||
WindowState::with_state(win1, |state| {
|
||||
state.resize_state = WindowResizeState::WaitingForAck(serial, win2_loc);
|
||||
});
|
||||
|
||||
win1.toplevel().send_pending_configure();
|
||||
win2.toplevel().send_pending_configure();
|
||||
let serial = win2.toplevel().send_configure();
|
||||
WindowState::with_state(win2, |state| {
|
||||
state.resize_state = WindowResizeState::WaitingForAck(serial, win1_loc);
|
||||
});
|
||||
|
||||
// self.space.map_element(win1.clone(), win2_loc, false);
|
||||
// self.space.map_element(win2.clone(), win1_loc, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
use std::{borrow::BorrowMut, cell::RefCell};
|
||||
use std::cell::RefCell;
|
||||
|
||||
use smithay::{
|
||||
desktop::Window,
|
||||
utils::{Logical, Point, Size},
|
||||
utils::{Logical, Point, Serial, Size},
|
||||
};
|
||||
|
||||
pub struct WindowState {
|
||||
pub floating: Float,
|
||||
pub resize_state: WindowResizeState,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub enum WindowResizeState {
|
||||
#[default]
|
||||
Idle,
|
||||
WaitingForAck(Serial, Point<i32, Logical>),
|
||||
WaitingForCommit(Point<i32, Logical>),
|
||||
}
|
||||
|
||||
pub enum Float {
|
||||
|
@ -15,6 +24,24 @@ pub enum Float {
|
|||
Floating,
|
||||
}
|
||||
|
||||
impl Float {
|
||||
/// Returns `true` if the float is [`Tiled`].
|
||||
///
|
||||
/// [`Tiled`]: Float::Tiled
|
||||
#[must_use]
|
||||
pub fn is_tiled(&self) -> bool {
|
||||
matches!(self, Self::Tiled(..))
|
||||
}
|
||||
|
||||
/// Returns `true` if the float is [`Floating`].
|
||||
///
|
||||
/// [`Floating`]: Float::Floating
|
||||
#[must_use]
|
||||
pub fn is_floating(&self) -> bool {
|
||||
matches!(self, Self::Floating)
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowState {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
|
@ -43,6 +70,7 @@ impl Default for WindowState {
|
|||
Self {
|
||||
// TODO: get this from a config file instead of hardcoding
|
||||
floating: Float::Tiled(None),
|
||||
resize_state: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue