diff --git a/src/compositor.rs b/src/compositor.rs index c02bcb4c..5f6f3cbd 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -68,7 +68,7 @@ use { clone3::ensure_reaper, clonecell::CloneCell, errorfmt::ErrorFmt, - event_listener::handle_lazy_event_sources, + event_listener::{handle_lazy_event_sources, handle_post_layout_event_sources}, fdcloser::FdCloser, nice::{did_elevate_scheduler, elevate_scheduler}, numcell::NumCell, @@ -393,6 +393,7 @@ fn start_compositor2( supports_presentation_feedback: Default::default(), eventfd_cache, lazy_event_sources: Default::default(), + post_layout_event_sources: Default::default(), bo_drop_queue: Rc::new(ObjectDropQueue::new(&ring)), virtual_outputs: Default::default(), clean_logs_older_than: Default::default(), @@ -602,6 +603,11 @@ fn start_global_event_handlers(state: &Rc) -> Vec> { "lazy event sources", handle_lazy_event_sources(state.clone()), ), + eng.spawn2( + "post layout event sources", + Phase::PostLayout, + handle_post_layout_event_sources(state.clone()), + ), eng.spawn( "warp mouse to focus", handle_warp_mouse_to_focus(state.clone()), @@ -799,6 +805,7 @@ fn create_dummy_output(state: &Rc) { pinned: Default::default(), tearing: Default::default(), active_zwlr_gamma_control: Default::default(), + workspace_switched: state.lazy_event_sources.create_source(), }); let dummy_workspace = WorkspaceNode::new(&dummy_output, "dummy", true); dummy_workspace.may_capture.set(false); diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index 2e9a47b3..9cf4667a 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -536,6 +536,7 @@ impl XdgToplevel { } } self.state.tree_changed(); + self.toplevel_data.unmapped_source.trigger(); } else { self.map(self.parent.get().as_deref(), pos); self.extents_changed(); @@ -550,6 +551,7 @@ impl XdgToplevel { // } // } self.state.tree_changed(); + self.toplevel_data.mapped_source.trigger(); self.toplevel_data.broadcast(self.clone()); } self.toplevel_data diff --git a/src/state.rs b/src/state.rs index 7bcac2b6..c39c717e 100644 --- a/src/state.rs +++ b/src/state.rs @@ -298,6 +298,7 @@ pub struct State { pub supports_presentation_feedback: Cell, pub eventfd_cache: Rc, pub lazy_event_sources: Rc, + pub post_layout_event_sources: Rc, pub bo_drop_queue: Rc>>, pub virtual_outputs: VirtualOutputs, pub clean_logs_older_than: Cell>, @@ -936,6 +937,7 @@ impl State { if !output.is_dummy { output.schedule_update_render_data(); self.tree_changed(); + output.workspace_switched.trigger(); } } @@ -1169,6 +1171,7 @@ impl State { self.wait_for_syncobj.clear(); self.xdg_surface_configure_events.clear(); self.lazy_event_sources.clear(); + self.post_layout_event_sources.clear(); self.bo_drop_queue.kill(); self.virtual_outputs.clear(); } diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index aaab66aa..aef06d91 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -233,6 +233,7 @@ impl ConnectorHandler { pinned: Default::default(), tearing: Default::default(), active_zwlr_gamma_control: Default::default(), + workspace_switched: self.state.lazy_event_sources.create_source(), }); on.update_visible(); on.update_rects(); diff --git a/src/tree/container.rs b/src/tree/container.rs index ce8c8223..09b881b4 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -29,6 +29,7 @@ use { clonecell::CloneCell, double_click_state::DoubleClickState, errorfmt::ErrorFmt, + event_listener::LazyEventSource, hash_map_ext::HashMapExt, linkedlist::{LinkedList, LinkedNode, NodeRef}, numcell::NumCell, @@ -140,6 +141,10 @@ pub struct ContainerNode { attention_requests: ThresholdCounter, pending_layout_damage: Cell, layout_damage_timeout: Cell>>, + pub layout_complete: Rc, + pub child_added: Rc, + pub child_removed: Rc, + pub all_children_resized: Rc, } impl Debug for ContainerNode { @@ -258,6 +263,10 @@ impl ContainerNode { attention_requests: Default::default(), pending_layout_damage: Cell::new(false), layout_damage_timeout: Cell::new(None), + layout_complete: state.post_layout_event_sources.create_source(), + child_added: state.lazy_event_sources.create_source(), + child_removed: state.lazy_event_sources.create_source(), + all_children_resized: state.post_layout_event_sources.create_source(), }); child.tl_set_parent(slf.clone()); slf.pull_child_properties(&child_node_ref); @@ -368,6 +377,7 @@ impl ContainerNode { // log::info!("add_child"); self.schedule_layout(); self.cancel_seat_ops(); + self.child_added.trigger(); } fn cancel_seat_ops(&self) { @@ -461,6 +471,22 @@ impl ContainerNode { } } + fn all_children_match_body(&self) -> bool { + if let Some(mono) = self.mono_child.get() { + let body = self.mono_body.get(); + let content = mono.content.get(); + return content.width() == body.width() && content.height() == body.height(); + } + for child in self.children.iter() { + let body = child.body.get(); + let content = child.content.get(); + if content.width() != body.width() || content.height() != body.height() { + return false; + } + } + true + } + fn perform_layout(self: &Rc) { if self.num_children.get() == 0 { return; @@ -475,6 +501,7 @@ impl ContainerNode { // log::info!("perform_layout"); self.schedule_render_titles(); self.schedule_compute_render_positions(); + self.layout_complete.trigger(); if self.pending_layout_damage.get() { let slf = self.clone(); let timeout = self.state.eng.spawn("layout damage timeout", async move { @@ -1832,6 +1859,9 @@ impl Node for ContainerNode { if let Some(node) = cn.get(&child.node_id()) { self.update_child_size(node, width, height); } + if self.pending_layout_damage.get() && self.all_children_match_body() { + self.all_children_resized.trigger(); + } self.flush_layout_damage(); } @@ -2115,6 +2145,7 @@ impl ContainingNode for ContainerNode { // log::info!("cnode_remove_child2"); self.schedule_layout(); self.cancel_seat_ops(); + self.child_removed.trigger(); } fn cnode_accepts_child(&self, _node: &dyn Node) -> bool { diff --git a/src/tree/float.rs b/src/tree/float.rs index b2eb8689..f8bd1585 100644 --- a/src/tree/float.rs +++ b/src/tree/float.rs @@ -20,8 +20,8 @@ use { }, utils::{ asyncevent::AsyncEvent, clonecell::CloneCell, double_click_state::DoubleClickState, - errorfmt::ErrorFmt, linkedlist::LinkedNode, on_drop_event::OnDropEvent, - smallmap::SmallMapMut, + errorfmt::ErrorFmt, event_listener::LazyEventSource, linkedlist::LinkedNode, + on_drop_event::OnDropEvent, smallmap::SmallMapMut, }, }, ahash::AHashMap, @@ -56,6 +56,7 @@ pub struct FloatNode { pub title_textures: RefCell>, cursors: RefCell>, pub attention_requested: Cell, + pub layout_complete: Rc, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -136,6 +137,7 @@ impl FloatNode { title_textures: Default::default(), cursors: Default::default(), attention_requested: Cell::new(false), + layout_complete: state.post_layout_event_sources.create_source(), }); floater.pull_child_properties(); *floater.display_link.borrow_mut() = Some(state.root.stacked.add_last(floater.clone())); @@ -190,6 +192,7 @@ impl FloatNode { self.title_rect.set(tr); self.layout_scheduled.set(false); self.schedule_render_titles(); + self.layout_complete.trigger(); } pub fn schedule_render_titles(self: &Rc) { diff --git a/src/tree/output.rs b/src/tree/output.rs index 80b524e8..611eb822 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -56,7 +56,7 @@ use { clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, - event_listener::EventSource, + event_listener::{EventSource, LazyEventSource}, hash_map_ext::HashMapExt, linkedlist::{LinkedList, NodeRef}, on_drop_event::OnDropEvent, @@ -127,6 +127,7 @@ pub struct OutputNode { pub pinned: LinkedList>, pub tearing: Cell, pub active_zwlr_gamma_control: CloneCell>>, + pub workspace_switched: Rc, } #[derive(Copy, Clone, Debug, PartialEq)] diff --git a/src/tree/toplevel.rs b/src/tree/toplevel.rs index bf9c7060..a196286d 100644 --- a/src/tree/toplevel.rs +++ b/src/tree/toplevel.rs @@ -415,6 +415,8 @@ pub struct ToplevelData { pub seat_foci: CopyHashMap, pub content_type: Cell>, pub property_changed_source: OnceCell>, + pub mapped_source: Rc, + pub unmapped_source: Rc, } impl ToplevelData { @@ -469,6 +471,8 @@ impl ToplevelData { seat_foci: Default::default(), content_type: Default::default(), property_changed_source: Default::default(), + mapped_source: state.lazy_event_sources.create_source(), + unmapped_source: state.lazy_event_sources.create_source(), } } diff --git a/src/utils/event_listener.rs b/src/utils/event_listener.rs index 55385ae5..95820b95 100644 --- a/src/utils/event_listener.rs +++ b/src/utils/event_listener.rs @@ -14,8 +14,16 @@ use { }; pub async fn handle_lazy_event_sources(state: Rc) { + handle_lazy_event_sources_of(&state.lazy_event_sources).await; +} + +pub async fn handle_post_layout_event_sources(state: Rc) { + handle_lazy_event_sources_of(&state.post_layout_event_sources).await; +} + +async fn handle_lazy_event_sources_of(sources: &LazyEventSources) { loop { - let source = state.lazy_event_sources.queue.pop().await; + let source = sources.queue.pop().await; source.queued.set(false); for listener in source.listeners.iter() { listener.triggered();