Skip to content

Commit

Permalink
portal: implement workspace capture
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Apr 20, 2024
1 parent c6864a6 commit 33a0a40
Show file tree
Hide file tree
Showing 23 changed files with 518 additions and 50 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
1 change: 1 addition & 0 deletions src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ fn create_dummy_output(state: &Rc<State>) {
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
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
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
10 changes: 8 additions & 2 deletions src/ifs/wl_seat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ use {
thiserror::Error,
uapi::OwnedFd,
};
pub use {event_handling::NodeSeatState, pointer_owner::ToplevelSelector};
pub use {
event_handling::NodeSeatState,
pointer_owner::{ToplevelSelector, WorkspaceSelector},
};

pub const POINTER: u32 = 1;
const KEYBOARD: u32 = 2;
Expand Down Expand Up @@ -1153,10 +1156,13 @@ impl WlSeatGlobal {
self.forward.set(forward);
}

#[allow(dead_code)]
pub fn select_toplevel(self: &Rc<Self>, selector: impl ToplevelSelector) {
self.pointer_owner.select_toplevel(self, selector);
}

pub fn select_workspace(self: &Rc<Self>, selector: impl WorkspaceSelector) {
self.pointer_owner.select_workspace(self, selector);
}
}

global_base!(WlSeatGlobal, WlSeat, WlSeatError);
Expand Down
Loading

0 comments on commit 33a0a40

Please sign in to comment.