diff --git a/src/compositor.rs b/src/compositor.rs index ee3d617a..f854ead1 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -494,6 +494,7 @@ fn create_dummy_output(state: &Rc) { screencopies: Default::default(), title_visible: Cell::new(false), schedule, + latch_event: Default::default(), }); let dummy_workspace = Rc::new(WorkspaceNode { id: state.node_ids.next(), diff --git a/src/ifs/jay_compositor.rs b/src/ifs/jay_compositor.rs index dd778d0c..51d011ae 100644 --- a/src/ifs/jay_compositor.rs +++ b/src/ifs/jay_compositor.rs @@ -325,7 +325,7 @@ impl JayCompositorRequestHandler for JayCompositor { } fn create_screencast(&self, req: CreateScreencast, _slf: &Rc) -> Result<(), Self::Error> { - let sc = Rc::new(JayScreencast::new(req.id, &self.client)); + let sc = Rc::new_cyclic(|slf| JayScreencast::new(req.id, &self.client, slf)); track!(self.client, sc); self.client.add_client_obj(&sc)?; Ok(()) diff --git a/src/ifs/jay_screencast.rs b/src/ifs/jay_screencast.rs index 9c4d7301..91811100 100644 --- a/src/ifs/jay_screencast.rs +++ b/src/ifs/jay_screencast.rs @@ -8,10 +8,11 @@ use { object::{Object, Version}, scale::Scale, state::State, - tree::{OutputNode, ToplevelNode, WorkspaceNode, WorkspaceNodeId}, + tree::{LatchListener, OutputNode, ToplevelNode, WorkspaceNode, WorkspaceNodeId}, utils::{ clonecell::{CloneCell, UnsafeCellCloneSafe}, errorfmt::ErrorFmt, + event_listener::EventListener, numcell::NumCell, option_ext::OptionExt, }, @@ -29,7 +30,7 @@ use { std::{ cell::{Cell, RefCell}, ops::DerefMut, - rc::Rc, + rc::{Rc, Weak}, }, thiserror::Error, }; @@ -75,6 +76,7 @@ pub struct JayScreencast { pending: Pending, need_realloc: Cell, realloc_scheduled: Cell, + latch_listener: EventListener, } #[derive(Clone)] @@ -83,6 +85,12 @@ enum Target { Toplevel(Rc), } +impl LatchListener for JayScreencast { + fn after_latch(self: Rc) { + self.schedule_toplevel_screencast(); + } +} + unsafe impl UnsafeCellCloneSafe for Target {} enum PendingTarget { @@ -119,7 +127,7 @@ impl JayScreencast { false } - pub fn new(id: JayScreencastId, client: &Rc) -> Self { + pub fn new(id: JayScreencastId, client: &Rc, slf: &Weak) -> Self { Self { id, client: client.clone(), @@ -139,10 +147,11 @@ impl JayScreencast { pending: Default::default(), need_realloc: Cell::new(false), realloc_scheduled: Cell::new(false), + latch_listener: EventListener::new(slf.clone()), } } - pub fn schedule_toplevel_screencast(self: &Rc) { + fn schedule_toplevel_screencast(self: &Rc) { if !self.running.get() { return; } @@ -319,6 +328,7 @@ impl JayScreencast { } fn detach(&self) { + self.latch_listener.detach(); if let Some(target) = self.target.take() { match target { Target::Output(output) => { @@ -427,6 +437,18 @@ impl JayScreencast { self.client.state.damage(rect); } } + + pub fn update_latch_listener(&self) { + let Some(Target::Toplevel(tl)) = self.target.get() else { + return; + }; + let data = tl.tl_data(); + if data.visible.get() { + self.latch_listener.attach(&data.output().latch_event); + } else { + self.latch_listener.detach(); + } + } } impl JayScreencastRequestHandler for JayScreencast { @@ -540,6 +562,9 @@ impl JayScreencastRequestHandler for JayScreencast { let data = t.tl_data(); data.jay_screencasts .set((self.client.id, self.id), slf.clone()); + if data.visible.get() { + self.latch_listener.attach(&data.output().latch_event); + } new_target = Some(Target::Toplevel(t)); } } diff --git a/src/renderer.rs b/src/renderer.rs index f9353103..e1445d03 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -360,11 +360,6 @@ impl Renderer<'_> { bounds: Option<&Rect>, render_highlight: bool, ) { - if self.result.is_some() { - for screencast in tl_data.jay_screencasts.lock().values() { - screencast.schedule_toplevel_screencast(); - } - } if render_highlight { self.render_highlight(tl_data, bounds); } diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index db1cc6f6..ff1c839c 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -185,6 +185,7 @@ impl ConnectorHandler { screencopies: Default::default(), title_visible: Default::default(), schedule, + latch_event: Default::default(), }); on.update_visible(); on.update_rects(); diff --git a/src/tree/output.rs b/src/tree/output.rs index 0df37498..0f157482 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -37,8 +37,8 @@ use { }, utils::{ clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, - hash_map_ext::HashMapExt, linkedlist::LinkedList, scroller::Scroller, - transform_ext::TransformExt, + event_listener::EventSource, hash_map_ext::HashMapExt, linkedlist::LinkedList, + scroller::Scroller, transform_ext::TransformExt, }, wire::{JayOutputId, JayScreencastId, ZwlrScreencopyFrameV1Id}, }, @@ -80,6 +80,11 @@ pub struct OutputNode { pub screencopies: CopyHashMap<(ClientId, ZwlrScreencopyFrameV1Id), Rc>, pub title_visible: Cell, pub schedule: Rc, + pub latch_event: EventSource, +} + +pub trait LatchListener { + fn after_latch(self: Rc); } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -148,6 +153,9 @@ impl OutputNode { y_off: i32, size: Option<(i32, i32)>, ) { + for listener in self.latch_event.iter() { + listener.after_latch(); + } if let Some(workspace) = self.workspace.get() { if !workspace.may_capture.get() { return; diff --git a/src/tree/toplevel.rs b/src/tree/toplevel.rs index 5f9ccbaf..725f220e 100644 --- a/src/tree/toplevel.rs +++ b/src/tree/toplevel.rs @@ -42,6 +42,7 @@ pub trait ToplevelNode: ToplevelNodeBase { fn tl_set_parent(&self, parent: Rc); fn tl_extents_changed(&self); fn tl_set_workspace(&self, ws: &Rc); + fn tl_workspace_output_changed(&self); fn tl_change_extents(self: Rc, rect: &Rect); fn tl_set_visible(&self, visible: bool); fn tl_destroy(&self); @@ -112,8 +113,20 @@ impl ToplevelNode for T { fn tl_set_workspace(&self, ws: &Rc) { let data = self.tl_data(); - data.workspace.set(Some(ws.clone())); + let prev = data.workspace.set(Some(ws.clone())); self.tl_set_workspace_ext(ws); + let prev_id = prev.map(|p| p.output.get().id); + let new_id = Some(ws.output.get().id); + if prev_id != new_id { + self.tl_workspace_output_changed(); + } + } + + fn tl_workspace_output_changed(&self) { + let data = self.tl_data(); + for sc in data.jay_screencasts.lock().values() { + sc.update_latch_listener(); + } } fn tl_change_extents(self: Rc, rect: &Rect) { @@ -484,6 +497,9 @@ impl ToplevelData { pub fn set_visible(&self, node: &dyn Node, visible: bool) { self.visible.set(visible); self.seat_state.set_visible(node, visible); + for sc in self.jay_screencasts.lock().values() { + sc.update_latch_listener(); + } if !visible { return; } @@ -508,4 +524,11 @@ impl ToplevelData { parent.cnode_child_attention_request_changed(node, true); } } + + pub fn output(&self) -> Rc { + match self.workspace.get() { + None => self.state.dummy_output.get().unwrap(), + Some(ws) => ws.output.get(), + } + } } diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index 7daf641f..5f77afcb 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -7,7 +7,9 @@ use { jay_workspace::JayWorkspace, wl_output::OutputId, wl_seat::{tablet::TabletTool, NodeSeatState, WlSeatGlobal}, - wl_surface::WlSurface, + wl_surface::{ + x_surface::xwindow::Xwindow, xdg_surface::xdg_toplevel::XdgToplevel, WlSurface, + }, }, rect::Rect, renderer::Renderer, @@ -16,7 +18,7 @@ use { tree::{ container::ContainerNode, walker::NodeVisitor, ContainingNode, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitorBase, OutputNode, - StackedNode, ToplevelNode, + PlaceholderNode, StackedNode, ToplevelNode, }, utils::{ clonecell::CloneCell, @@ -102,6 +104,26 @@ impl WorkspaceNode { fn visit_surface(&mut self, node: &Rc) { node.set_output(self.0); } + + fn visit_container(&mut self, node: &Rc) { + node.tl_workspace_output_changed(); + node.node_visit_children(self); + } + + fn visit_toplevel(&mut self, node: &Rc) { + node.tl_workspace_output_changed(); + node.node_visit_children(self); + } + + fn visit_xwindow(&mut self, node: &Rc) { + node.tl_workspace_output_changed(); + node.node_visit_children(self); + } + + fn visit_placeholder(&mut self, node: &Rc) { + node.tl_workspace_output_changed(); + node.node_visit_children(self); + } } let mut visitor = OutputSetter(output); self.node_visit_children(&mut visitor);