Skip to content

Commit

Permalink
Merge pull request #170 from mahkoh/jorth/workspace-capture
Browse files Browse the repository at this point in the history
portal: implement workspace capture
  • Loading branch information
mahkoh authored Apr 20, 2024
2 parents 670588f + 33a0a40 commit 1566873
Show file tree
Hide file tree
Showing 29 changed files with 709 additions and 195 deletions.
6 changes: 6 additions & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ You can change this GPU at runtime.
## Screen Sharing

Jay supports screen sharing via xdg-desktop-portal.
There are three supported modes:

- Window capture
- Output capture
- Workspace capture which is like output capture except that only one workspace will be
shown.

## Screen Locking

Expand Down
1 change: 1 addition & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Unreleased

- Screencasts now support window capture.
- Screencasts now support workspace capture.
- Add support for wp-alpha-modifier.
- Add support for per-device keymaps.
- Add support for virtual-keyboard-unstable-v1.
Expand Down
5 changes: 4 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,9 +468,11 @@ 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(),
render_highlight: Default::default(),
});
*dummy_workspace.output_link.borrow_mut() =
Some(dummy_output.workspaces.add_last(dummy_workspace.clone()));
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
1 change: 1 addition & 0 deletions src/ifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod jay_screencast;
pub mod jay_screenshot;
pub mod jay_seat_events;
pub mod jay_select_toplevel;
pub mod jay_select_workspace;
pub mod jay_toplevel;
pub mod jay_workspace;
pub mod jay_workspace_watcher;
Expand Down
22 changes: 21 additions & 1 deletion src/ifs/jay_compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use {
jay_screenshot::JayScreenshot,
jay_seat_events::JaySeatEvents,
jay_select_toplevel::{JaySelectToplevel, JayToplevelSelector},
jay_select_workspace::{JaySelectWorkspace, JayWorkspaceSelector},
jay_workspace_watcher::JayWorkspaceWatcher,
},
leaks::Tracker,
Expand Down Expand Up @@ -85,13 +86,14 @@ pub struct Cap;
impl Cap {
pub const NONE: u16 = 0;
pub const WINDOW_CAPTURE: u16 = 1;
pub const SELECT_WORKSPACE: u16 = 2;
}

impl JayCompositor {
fn send_capabilities(&self) {
self.client.event(Capabilities {
self_id: self.id,
cap: &[Cap::NONE, Cap::WINDOW_CAPTURE],
cap: &[Cap::NONE, Cap::WINDOW_CAPTURE, Cap::SELECT_WORKSPACE],
});
}

Expand Down Expand Up @@ -362,6 +364,24 @@ impl JayCompositorRequestHandler for JayCompositor {
seat.global.select_toplevel(selector);
Ok(())
}

fn select_workspace(&self, req: SelectWorkspace, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let seat = self.client.lookup(req.seat)?;
let obj = Rc::new(JaySelectWorkspace {
id: req.id,
client: self.client.clone(),
tracker: Default::default(),
destroyed: Cell::new(false),
});
track!(self.client, obj);
self.client.add_client_obj(&obj)?;
let selector = JayWorkspaceSelector {
ws: Default::default(),
jsw: obj.clone(),
};
seat.global.select_workspace(selector);
Ok(())
}
}

object_base! {
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
105 changes: 105 additions & 0 deletions src/ifs/jay_select_workspace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use {
crate::{
client::{Client, ClientError},
ifs::{jay_workspace::JayWorkspace, wl_seat::WorkspaceSelector},
leaks::Tracker,
object::{Object, Version},
tree::WorkspaceNode,
utils::clonecell::CloneCell,
wire::{jay_select_workspace::*, JaySelectWorkspaceId, JayWorkspaceId},
},
std::{cell::Cell, rc::Rc},
thiserror::Error,
};

pub struct JaySelectWorkspace {
pub id: JaySelectWorkspaceId,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
pub destroyed: Cell<bool>,
}

pub struct JayWorkspaceSelector {
pub ws: CloneCell<Option<Rc<WorkspaceNode>>>,
pub jsw: Rc<JaySelectWorkspace>,
}

impl WorkspaceSelector for JayWorkspaceSelector {
fn set(&self, ws: Rc<WorkspaceNode>) {
self.ws.set(Some(ws));
}
}

impl Drop for JayWorkspaceSelector {
fn drop(&mut self) {
if self.jsw.destroyed.get() {
return;
}
match self.ws.take() {
None => {
self.jsw.send_cancelled();
}
Some(ws) => {
let id = match self.jsw.client.new_id() {
Ok(id) => id,
Err(e) => {
self.jsw.client.error(e);
return;
}
};
let jw = Rc::new(JayWorkspace {
id,
client: self.jsw.client.clone(),
workspace: CloneCell::new(Some(ws.clone())),
tracker: Default::default(),
});
track!(self.jsw.client, jw);
self.jsw.client.add_server_obj(&jw);
self.jsw
.send_selected(ws.output.get().global.name.raw(), id);
ws.jay_workspaces
.set((self.jsw.client.id, jw.id), jw.clone());
jw.send_initial_properties(&ws);
}
};
let _ = self.jsw.client.remove_obj(&*self.jsw);
}
}

impl JaySelectWorkspace {
fn send_cancelled(&self) {
self.client.event(Cancelled { self_id: self.id });
}

fn send_selected(&self, output: u32, id: JayWorkspaceId) {
self.client.event(Selected {
self_id: self.id,
output,
id,
});
}
}

impl JaySelectWorkspaceRequestHandler for JaySelectWorkspace {
type Error = JaySelectWorkspaceError;
}

object_base! {
self = JaySelectWorkspace;
version = Version(1);
}

impl Object for JaySelectWorkspace {
fn break_loops(&self) {
self.destroyed.set(true);
}
}

simple_add_obj!(JaySelectWorkspace);

#[derive(Debug, Error)]
pub enum JaySelectWorkspaceError {
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(JaySelectWorkspaceError, ClientError);
8 changes: 8 additions & 0 deletions src/ifs/jay_workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ pub struct JayWorkspace {
}

impl JayWorkspace {
pub fn send_initial_properties(&self, workspace: &WorkspaceNode) {
self.send_linear_id(workspace);
self.send_name(workspace);
self.send_output(&workspace.output.get());
self.send_visible(workspace.visible.get());
self.send_done();
}

pub fn send_linear_id(&self, ws: &WorkspaceNode) {
self.client.event(LinearId {
self_id: self.id,
Expand Down
6 changes: 1 addition & 5 deletions src/ifs/jay_workspace_watcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,7 @@ impl JayWorkspaceWatcher {
id: jw.id,
linear_id: workspace.id.raw(),
});
jw.send_linear_id(workspace);
jw.send_name(workspace);
jw.send_output(&workspace.output.get());
jw.send_visible(workspace.visible.get());
jw.send_done();
jw.send_initial_properties(workspace);
Ok(())
}

Expand Down
Loading

0 comments on commit 1566873

Please sign in to comment.