diff --git a/src/api/msg.rs b/src/api/msg.rs index 3c1b820..e4930c8 100644 --- a/src/api/msg.rs +++ b/src/api/msg.rs @@ -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); diff --git a/src/handlers.rs b/src/handlers.rs index bc02abb..178bee5 100644 --- a/src/handlers.rs +++ b/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 BufferHandler for State { @@ -122,6 +124,12 @@ impl CompositorHandler for State { } }); } + // let states = self + // .windows + // .iter() + // .map(|win| win.with_state(|state| state.resize_state.clone())) + // .collect::>(); + // tracing::debug!("states: {states:?}"); } fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState { @@ -250,8 +258,67 @@ impl XdgShellHandler for State { 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::>(); + 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 XdgShellHandler for State { 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 XdgShellHandler for State { 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!(), diff --git a/src/state.rs b/src/state.rs index 770f772..25d4b8e 100644 --- a/src/state.rs +++ b/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,46 +676,59 @@ impl State { }) }) }); - 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); - } - }); - } - /// Schedule something to be done when windows have finished committing and have become - /// idle. - pub fn schedule_on_commit(&mut self, windows: Vec, on_commit: F) - where - F: FnOnce(&mut CalloopData) + 'static, - { - tracing::debug!("scheduling on_commit"); + let clone = render.clone(); self.loop_handle.insert_idle(|data| { - tracing::debug!("running idle cb"); - tracing::debug!("win len is {}", windows.len()); - for window in windows.iter() { - window.with_state(|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"); - data.state.loop_handle.insert_idle(|data| { - data.state.schedule_on_commit(windows, on_commit); - }); - return; + schedule_on_commit(data, clone, |dt| { + for win in do_not_render { + dt.state.space.unmap_elem(&win); } - } - - on_commit(data); + }) }); + + // 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::(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::(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(data: &mut CalloopData, windows: Vec, on_commit: F) + where + F: FnOnce(&mut CalloopData) + 'static, +{ + // 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); + }); + if window.with_state(|state| !matches!(state.resize_state, WindowResizeState::Idle)) + { + // tracing::debug!("some windows not idle"); + data.state.loop_handle.insert_idle(|data| { + schedule_on_commit(data, windows, on_commit); + }); + return; + } + } + + on_commit(data); +} impl State { pub fn init( diff --git a/src/window.rs b/src/window.rs index 6a47320..1571921 100644 --- a/src/window.rs +++ b/src/window.rs @@ -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(state: &mut State, 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 + } + } +} diff --git a/src/window/window_state.rs b/src/window/window_state.rs index 8c4c4c5..50c50b5 100644 --- a/src/window/window_state.rs +++ b/src/window/window_state.rs @@ -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), } +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, Size)>),