Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

portal: implement workspace capture #170

Merged
merged 2 commits into from
Apr 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading