Skip to content

Commit

Permalink
tree: fix per-workspace capture tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Apr 20, 2024
1 parent 670588f commit c6864a6
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 145 deletions.
4 changes: 3 additions & 1 deletion src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ fn create_dummy_output(state: &Rc<State>) {
update_render_data_scheduled: Cell::new(false),
screencasts: Default::default(),
hardware_cursor_needs_render: Cell::new(false),
screencopies: Default::default(),
});
let dummy_workspace = Rc::new(WorkspaceNode {
id: state.node_ids.next(),
Expand All @@ -467,7 +468,8 @@ fn create_dummy_output(state: &Rc<State>) {
visible_on_desired_output: Default::default(),
desired_output: CloneCell::new(dummy_output.global.output_id.clone()),
jay_workspaces: Default::default(),
capture: Cell::new(false),
may_capture: Cell::new(false),
has_capture: Cell::new(false),
title_texture: Cell::new(None),
attention_requests: Default::default(),
});
Expand Down
5 changes: 3 additions & 2 deletions src/config/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ impl ConfigProxyHandler {
fn handle_get_workspace_capture(&self, workspace: Workspace) -> Result<(), CphError> {
let name = self.get_workspace(workspace)?;
let capture = match self.state.workspaces.get(name.as_str()) {
Some(ws) => ws.capture.get(),
Some(ws) => ws.may_capture.get(),
None => self.state.default_workspace_capture.get(),
};
self.respond(Response::GetWorkspaceCapture { capture });
Expand All @@ -669,7 +669,8 @@ impl ConfigProxyHandler {
) -> Result<(), CphError> {
let name = self.get_workspace(workspace)?;
if let Some(ws) = self.state.workspaces.get(name.as_str()) {
ws.capture.set(capture);
ws.may_capture.set(capture);
ws.update_has_captures();
ws.output.get().schedule_update_render_data();
self.state.damage();
}
Expand Down
33 changes: 24 additions & 9 deletions src/ifs/jay_screencast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use {
object::{Object, Version},
scale::Scale,
state::State,
tree::{OutputNode, ToplevelNode, WorkspaceNodeId},
tree::{OutputNode, ToplevelNode, WorkspaceNode, WorkspaceNodeId},
utils::{
clonecell::{CloneCell, UnsafeCellCloneSafe},
errorfmt::ErrorFmt,
Expand Down Expand Up @@ -106,6 +106,18 @@ struct ScreencastBuffer {
}

impl JayScreencast {
pub fn shows_ws(&self, ws: &WorkspaceNode) -> bool {
if self.show_all.get() {
return true;
}
for &id in &*self.show_workspaces.borrow() {
if id == ws.id {
return true;
}
}
false
}

pub fn new(id: JayScreencastId, client: &Rc<Client>) -> Self {
Self {
id,
Expand Down Expand Up @@ -309,10 +321,7 @@ impl JayScreencast {
if let Some(target) = self.target.take() {
match target {
Target::Output(output) => {
output.screencasts.remove(&(self.client.id, self.id));
if output.screencasts.is_empty() {
output.state.damage();
}
output.remove_screencast(self);
}
Target::Toplevel(tl) => {
let data = tl.tl_data();
Expand Down Expand Up @@ -514,10 +523,7 @@ impl JayScreencastRequestHandler for JayScreencast {
self.do_destroy();
return Ok(());
};
if o.screencasts.is_empty() {
o.state.damage();
}
o.screencasts.set((self.client.id, self.id), slf.clone());
o.add_screencast(slf);
new_target = Some(Target::Output(o));
}
PendingTarget::Toplevel(t) => {
Expand Down Expand Up @@ -546,11 +552,14 @@ impl JayScreencastRequestHandler for JayScreencast {
need_realloc = true;
}
}
let mut capture_rules_changed = false;
if let Some(show_all) = self.pending.show_all.take() {
self.show_all.set(show_all);
capture_rules_changed = true;
}
if let Some(new_workspaces) = self.pending.show_workspaces.borrow_mut().take() {
*self.show_workspaces.borrow_mut() = new_workspaces;
capture_rules_changed = true;
}
if let Some(running) = self.pending.running.take() {
self.running.set(running);
Expand All @@ -560,6 +569,12 @@ impl JayScreencastRequestHandler for JayScreencast {
slf.schedule_realloc();
}

if capture_rules_changed {
if let Some(Target::Output(o)) = self.target.get() {
o.screencast_changed();
}
}

Ok(())
}

Expand Down
99 changes: 2 additions & 97 deletions src/ifs/wl_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,21 @@ use {
crate::{
backend,
client::{Client, ClientError, ClientId},
gfx_api::GfxTexture,
globals::{Global, GlobalName},
ifs::{
wl_buffer::WlBufferStorage, wl_surface::WlSurface,
zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1, zxdg_output_v1::ZxdgOutputV1,
},
ifs::{wl_surface::WlSurface, zxdg_output_v1::ZxdgOutputV1},
leaks::Tracker,
object::{Object, Version},
rect::Rect,
state::{ConnectorData, State},
time::Time,
tree::{calculate_logical_size, OutputNode},
utils::{
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
linkedlist::LinkedList, transform_ext::TransformExt,
},
utils::{clonecell::CloneCell, copyhashmap::CopyHashMap, transform_ext::TransformExt},
wire::{wl_output::*, WlOutputId, ZxdgOutputV1Id},
},
ahash::AHashMap,
jay_config::video::Transform,
std::{
cell::{Cell, RefCell},
collections::hash_map::Entry,
ops::Deref,
rc::Rc,
},
thiserror::Error,
Expand Down Expand Up @@ -68,8 +59,6 @@ pub struct WlOutputGlobal {
pub width_mm: i32,
pub height_mm: i32,
pub bindings: RefCell<AHashMap<ClientId, AHashMap<WlOutputId, Rc<WlOutput>>>>,
pub unused_captures: LinkedList<Rc<ZwlrScreencopyFrameV1>>,
pub pending_captures: LinkedList<Rc<ZwlrScreencopyFrameV1>>,
pub destroyed: Cell<bool>,
pub legacy_scale: Cell<u32>,
pub persistent: Rc<PersistentOutputState>,
Expand Down Expand Up @@ -125,8 +114,6 @@ impl WlOutputGlobal {
width_mm,
height_mm,
bindings: Default::default(),
unused_captures: Default::default(),
pending_captures: Default::default(),
destroyed: Cell::new(false),
legacy_scale: Cell::new(scale.round_up()),
persistent: persistent_state.clone(),
Expand Down Expand Up @@ -210,88 +197,6 @@ impl WlOutputGlobal {
Ok(())
}

pub fn perform_screencopies(
&self,
tex: &Rc<dyn GfxTexture>,
render_hardware_cursors: bool,
x_off: i32,
y_off: i32,
size: Option<(i32, i32)>,
) {
if self.pending_captures.is_empty() {
return;
}
let now = Time::now().unwrap();
let mut captures = vec![];
for capture in self.pending_captures.iter() {
captures.push(capture.deref().clone());
let wl_buffer = match capture.buffer.take() {
Some(b) => b,
_ => {
log::warn!("Capture frame is pending but has no buffer attached");
capture.send_failed();
continue;
}
};
if wl_buffer.destroyed() {
capture.send_failed();
continue;
}
if let Some(WlBufferStorage::Shm { mem, stride }) =
wl_buffer.storage.borrow_mut().deref()
{
let res = self.state.perform_shm_screencopy(
tex,
self.pos.get(),
x_off,
y_off,
size,
&capture,
mem,
*stride,
wl_buffer.format,
Transform::None,
);
if let Err(e) = res {
log::warn!("Could not perform shm screencopy: {}", ErrorFmt(e));
capture.send_failed();
continue;
}
} else {
let fb = match wl_buffer.famebuffer.get() {
Some(fb) => fb,
_ => {
log::warn!("Capture buffer has no framebuffer");
capture.send_failed();
continue;
}
};
let res = self.state.perform_screencopy(
tex,
&fb,
self.pos.get(),
render_hardware_cursors,
x_off - capture.rect.x1(),
y_off - capture.rect.y1(),
size,
Transform::None,
);
if let Err(e) = res {
log::warn!("Could not perform screencopy: {}", ErrorFmt(e));
capture.send_failed();
continue;
}
}
if capture.with_damage.get() {
capture.send_damage();
}
capture.send_ready(now.0.tv_sec as _, now.0.tv_nsec as _);
}
for capture in captures {
capture.output_link.take();
}
}

pub fn pixel_size(&self) -> (i32, i32) {
let mode = self.mode.get();
self.persistent
Expand Down
37 changes: 20 additions & 17 deletions src/ifs/zwlr_screencopy_frame_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use {
leaks::Tracker,
object::{Object, Version},
rect::Rect,
utils::linkedlist::LinkedNode,
wire::{zwlr_screencopy_frame_v1::*, WlBufferId, ZwlrScreencopyFrameV1Id},
},
std::{cell::Cell, ops::Deref, rc::Rc},
Expand All @@ -28,7 +27,6 @@ pub struct ZwlrScreencopyFrameV1 {
pub overlay_cursor: bool,
pub used: Cell<bool>,
pub with_damage: Cell<bool>,
pub output_link: Cell<Option<LinkedNode<Rc<Self>>>>,
pub buffer: Cell<Option<Rc<WlBuffer>>>,
pub version: Version,
}
Expand Down Expand Up @@ -90,19 +88,16 @@ impl ZwlrScreencopyFrameV1 {
}

fn do_copy(
&self,
self: &Rc<Self>,
buffer_id: WlBufferId,
with_damage: bool,
) -> Result<(), ZwlrScreencopyFrameV1Error> {
if self.used.replace(true) {
return Err(ZwlrScreencopyFrameV1Error::AlreadyUsed);
}
let link = match self.output_link.take() {
Some(l) => l,
_ => {
self.send_failed();
return Ok(());
}
let Some(node) = self.output.node.get() else {
self.send_failed();
return Ok(());
};
let buffer = self.client.lookup(buffer_id)?;
if (buffer.rect.width(), buffer.rect.height()) != (self.rect.width(), self.rect.height()) {
Expand All @@ -122,27 +117,35 @@ impl ZwlrScreencopyFrameV1 {
self.output.connector.connector.damage();
}
self.with_damage.set(with_damage);
self.output.pending_captures.add_last_existing(&link);
self.output_link.set(Some(link));
node.screencopies
.set((self.client.id, self.id), self.clone());
node.screencast_changed();
Ok(())
}

fn detach(&self) {
if let Some(node) = self.output.node.get() {
node.screencopies.remove(&(self.client.id, self.id));
node.screencast_changed();
}
}
}

impl ZwlrScreencopyFrameV1RequestHandler for ZwlrScreencopyFrameV1 {
type Error = ZwlrScreencopyFrameV1Error;

fn copy(&self, req: Copy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.do_copy(req.buffer, false)
fn copy(&self, req: Copy, slf: &Rc<Self>) -> Result<(), Self::Error> {
slf.do_copy(req.buffer, false)
}

fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.detach();
self.client.remove_obj(self)?;
self.output_link.take();
Ok(())
}

fn copy_with_damage(&self, req: CopyWithDamage, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.do_copy(req.buffer, true)
fn copy_with_damage(&self, req: CopyWithDamage, slf: &Rc<Self>) -> Result<(), Self::Error> {
slf.do_copy(req.buffer, true)
}
}

Expand All @@ -155,7 +158,7 @@ simple_add_obj!(ZwlrScreencopyFrameV1);

impl Object for ZwlrScreencopyFrameV1 {
fn break_loops(&self) {
self.output_link.take();
self.detach();
}
}

Expand Down
4 changes: 0 additions & 4 deletions src/ifs/zwlr_screencopy_manager_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ impl ZwlrScreencopyManagerV1 {
overlay_cursor,
used: Cell::new(false),
with_damage: Cell::new(false),
output_link: Cell::new(None),
buffer: Cell::new(None),
version: self.version,
});
Expand All @@ -136,9 +135,6 @@ impl ZwlrScreencopyManagerV1 {
frame.send_linux_dmabuf();
frame.send_buffer_done();
}
frame
.output_link
.set(Some(output.global.unused_captures.add_last(frame.clone())));
Ok(())
}
}
Expand Down
9 changes: 2 additions & 7 deletions src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,9 @@ impl Renderer<'_> {
x,
y,
);
let has_captures =
!output.screencasts.is_empty() || !output.global.pending_captures.is_empty();
let rd = output.render_data.borrow_mut();
if let Some(aw) = &rd.active_workspace {
let c = match has_captures && aw.captured {
let c = match aw.captured {
true => theme.colors.captured_focused_title_background.get(),
false => theme.colors.focused_title_background.get(),
};
Expand All @@ -147,10 +145,7 @@ impl Renderer<'_> {
.fill_boxes2(slice::from_ref(&rd.underline), &c, x, y);
let c = theme.colors.unfocused_title_background.get();
self.base.fill_boxes2(&rd.inactive_workspaces, &c, x, y);
let c = match has_captures {
true => theme.colors.captured_unfocused_title_background.get(),
false => theme.colors.unfocused_title_background.get(),
};
let c = theme.colors.captured_unfocused_title_background.get();
self.base
.fill_boxes2(&rd.captured_inactive_workspaces, &c, x, y);
let c = theme.colors.attention_requested_background.get();
Expand Down
Loading

0 comments on commit c6864a6

Please sign in to comment.