Skip to content

Commit

Permalink
Merge pull request #245 from mahkoh/jorth/toplevel-cast
Browse files Browse the repository at this point in the history
Fix toplevel screencasts with hardware cursors
  • Loading branch information
mahkoh authored Sep 1, 2024
2 parents 3eb539c + b28ea64 commit 2579834
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 37 deletions.
1 change: 1 addition & 0 deletions src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ fn create_dummy_output(state: &Rc<State>) {
screencopies: Default::default(),
title_visible: Cell::new(false),
schedule,
latch_event: Default::default(),
});
let dummy_workspace = Rc::new(WorkspaceNode {
id: state.node_ids.next(),
Expand Down
2 changes: 1 addition & 1 deletion src/ifs/jay_compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ impl JayCompositorRequestHandler for JayCompositor {
}

fn create_screencast(&self, req: CreateScreencast, _slf: &Rc<Self>) -> 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(())
Expand Down
33 changes: 29 additions & 4 deletions src/ifs/jay_screencast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand All @@ -29,7 +30,7 @@ use {
std::{
cell::{Cell, RefCell},
ops::DerefMut,
rc::Rc,
rc::{Rc, Weak},
},
thiserror::Error,
};
Expand Down Expand Up @@ -75,6 +76,7 @@ pub struct JayScreencast {
pending: Pending,
need_realloc: Cell<bool>,
realloc_scheduled: Cell<bool>,
latch_listener: EventListener<dyn LatchListener>,
}

#[derive(Clone)]
Expand All @@ -83,6 +85,12 @@ enum Target {
Toplevel(Rc<dyn ToplevelNode>),
}

impl LatchListener for JayScreencast {
fn after_latch(self: Rc<Self>) {
self.schedule_toplevel_screencast();
}
}

unsafe impl UnsafeCellCloneSafe for Target {}

enum PendingTarget {
Expand Down Expand Up @@ -119,7 +127,7 @@ impl JayScreencast {
false
}

pub fn new(id: JayScreencastId, client: &Rc<Client>) -> Self {
pub fn new(id: JayScreencastId, client: &Rc<Client>, slf: &Weak<Self>) -> Self {
Self {
id,
client: client.clone(),
Expand All @@ -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<Self>) {
fn schedule_toplevel_screencast(self: &Rc<Self>) {
if !self.running.get() {
return;
}
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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));
}
}
Expand Down
5 changes: 0 additions & 5 deletions src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions src/tasks/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ impl ConnectorHandler {
screencopies: Default::default(),
title_visible: Default::default(),
schedule,
latch_event: Default::default(),
});
on.update_visible();
on.update_rects();
Expand Down
16 changes: 13 additions & 3 deletions src/tree/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
},
Expand Down Expand Up @@ -80,6 +80,11 @@ pub struct OutputNode {
pub screencopies: CopyHashMap<(ClientId, ZwlrScreencopyFrameV1Id), Rc<ZwlrScreencopyFrameV1>>,
pub title_visible: Cell<bool>,
pub schedule: Rc<OutputSchedule>,
pub latch_event: EventSource<dyn LatchListener>,
}

pub trait LatchListener {
fn after_latch(self: Rc<Self>);
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -436,7 +444,9 @@ impl OutputNode {

pub fn ensure_workspace(self: &Rc<Self>) -> Rc<WorkspaceNode> {
if let Some(ws) = self.workspace.get() {
return ws;
if !ws.is_dummy {
return ws;
}
}
let name = 'name: {
for i in 1.. {
Expand Down
25 changes: 24 additions & 1 deletion src/tree/toplevel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub trait ToplevelNode: ToplevelNodeBase {
fn tl_set_parent(&self, parent: Rc<dyn ContainingNode>);
fn tl_extents_changed(&self);
fn tl_set_workspace(&self, ws: &Rc<WorkspaceNode>);
fn tl_workspace_output_changed(&self);
fn tl_change_extents(self: Rc<Self>, rect: &Rect);
fn tl_set_visible(&self, visible: bool);
fn tl_destroy(&self);
Expand Down Expand Up @@ -112,8 +113,20 @@ impl<T: ToplevelNodeBase> ToplevelNode for T {

fn tl_set_workspace(&self, ws: &Rc<WorkspaceNode>) {
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<Self>, rect: &Rect) {
Expand Down Expand Up @@ -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;
}
Expand All @@ -508,4 +524,11 @@ impl ToplevelData {
parent.cnode_child_attention_request_changed(node, true);
}
}

pub fn output(&self) -> Rc<OutputNode> {
match self.workspace.get() {
None => self.state.dummy_output.get().unwrap(),
Some(ws) => ws.output.get(),
}
}
}
26 changes: 24 additions & 2 deletions src/tree/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -102,6 +104,26 @@ impl WorkspaceNode {
fn visit_surface(&mut self, node: &Rc<WlSurface>) {
node.set_output(self.0);
}

fn visit_container(&mut self, node: &Rc<ContainerNode>) {
node.tl_workspace_output_changed();
node.node_visit_children(self);
}

fn visit_toplevel(&mut self, node: &Rc<XdgToplevel>) {
node.tl_workspace_output_changed();
node.node_visit_children(self);
}

fn visit_xwindow(&mut self, node: &Rc<Xwindow>) {
node.tl_workspace_output_changed();
node.node_visit_children(self);
}

fn visit_placeholder(&mut self, node: &Rc<PlaceholderNode>) {
node.tl_workspace_output_changed();
node.node_visit_children(self);
}
}
let mut visitor = OutputSetter(output);
self.node_visit_children(&mut visitor);
Expand Down
1 change: 1 addition & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod copyhashmap;
pub mod debug_fn;
pub mod double_click_state;
pub mod errorfmt;
pub mod event_listener;
pub mod fdcloser;
pub mod gfx_api_ext;
pub mod hash_map_ext;
Expand Down
69 changes: 69 additions & 0 deletions src/utils/event_listener.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use {
crate::utils::linkedlist::{LinkedList, LinkedListIter, LinkedNode},
std::{
cell::Cell,
rc::{Rc, Weak},
},
};

pub struct EventSource<T: ?Sized> {
listeners: LinkedList<Weak<T>>,
on_attach: Cell<Option<Box<dyn FnOnce()>>>,
}

pub struct EventListener<T: ?Sized> {
link: LinkedNode<Weak<T>>,
}

impl<T: ?Sized> Default for EventSource<T> {
fn default() -> Self {
Self {
listeners: Default::default(),
on_attach: Default::default(),
}
}
}

impl<T: ?Sized> EventSource<T> {
pub fn iter(&self) -> EventSourceIter<T> {
EventSourceIter {
iter: self.listeners.iter(),
}
}
}

pub struct EventSourceIter<T: ?Sized> {
iter: LinkedListIter<Weak<T>>,
}

impl<T: ?Sized> Iterator for EventSourceIter<T> {
type Item = Rc<T>;

fn next(&mut self) -> Option<Self::Item> {
for weak in self.iter.by_ref() {
if let Some(t) = weak.upgrade() {
return Some(t);
}
}
None
}
}

impl<T: ?Sized> EventListener<T> {
pub fn new(t: Weak<T>) -> Self {
Self {
link: LinkedNode::detached(t),
}
}

pub fn attach(&self, source: &EventSource<T>) {
source.listeners.add_last_existing(&self.link);
if let Some(on_attach) = source.on_attach.take() {
on_attach();
}
}

pub fn detach(&self) {
self.link.detach();
}
}
Loading

0 comments on commit 2579834

Please sign in to comment.