169 lines
6.1 KiB
Rust
169 lines
6.1 KiB
Rust
use {
|
|
crate::{
|
|
dbus::{DbusObject, DictEntry, DynamicType, FALSE, PendingReply, prelude::Variant},
|
|
pipewire::pw_con::PwCon,
|
|
portal::{
|
|
PORTAL_SUCCESS, PortalState,
|
|
ptl_remote_desktop::{DeviceTypes, RemoteDesktopPhase},
|
|
ptl_screencast::{ScreencastPhase, ScreencastTarget},
|
|
},
|
|
utils::{clonecell::CloneCell, hash_map_ext::HashMapExt},
|
|
wire_dbus::org::freedesktop::impl_::portal::{
|
|
remote_desktop::StartReply as RdStartReply, screen_cast::StartReply as ScStartReply,
|
|
session::Closed,
|
|
},
|
|
},
|
|
std::{borrow::Cow, cell::Cell, ops::Deref, rc::Rc},
|
|
};
|
|
|
|
shared_ids!(SessionId);
|
|
pub struct PortalSession {
|
|
pub _id: SessionId,
|
|
pub state: Rc<PortalState>,
|
|
pub pw_con: Option<Rc<PwCon>>,
|
|
pub app: String,
|
|
pub session_obj: DbusObject,
|
|
pub sc_phase: CloneCell<ScreencastPhase>,
|
|
pub rd_phase: CloneCell<RemoteDesktopPhase>,
|
|
pub start_reply: Cell<Option<PortalSessionReply>>,
|
|
}
|
|
|
|
pub enum PortalSessionReply {
|
|
RemoteDesktop(PendingReply<RdStartReply<'static>>),
|
|
ScreenCast(PendingReply<ScStartReply<'static>>),
|
|
}
|
|
|
|
impl PortalSession {
|
|
pub(super) fn kill(&self) {
|
|
self.session_obj.emit_signal(&Closed);
|
|
self.state.sessions.remove(self.session_obj.path());
|
|
self.reply_err("Session has been terminated");
|
|
match self.rd_phase.set(RemoteDesktopPhase::Terminated) {
|
|
RemoteDesktopPhase::Init => {}
|
|
RemoteDesktopPhase::DevicesSelected => {}
|
|
RemoteDesktopPhase::Terminated => {}
|
|
RemoteDesktopPhase::Selecting(s) => {
|
|
for gui in s.guis.lock().drain_values() {
|
|
gui.kill(false);
|
|
}
|
|
}
|
|
RemoteDesktopPhase::Starting(s) => {
|
|
s.ei_session.con.remove_obj(s.ei_session.deref());
|
|
s.dpy.sessions.remove(self.session_obj.path());
|
|
}
|
|
RemoteDesktopPhase::Started(s) => {
|
|
s.ei_session.con.remove_obj(s.ei_session.deref());
|
|
s.dpy.sessions.remove(self.session_obj.path());
|
|
}
|
|
}
|
|
match self.sc_phase.set(ScreencastPhase::Terminated) {
|
|
ScreencastPhase::Init => {}
|
|
ScreencastPhase::SourcesSelected(_) => {}
|
|
ScreencastPhase::Terminated => {}
|
|
ScreencastPhase::Selecting(s) => {
|
|
for gui in s.guis.lock().drain_values() {
|
|
gui.kill(false);
|
|
}
|
|
}
|
|
ScreencastPhase::SelectingWindow(s) => {
|
|
s.dpy.con.remove_obj(&*s.selector);
|
|
}
|
|
ScreencastPhase::SelectingWorkspace(s) => {
|
|
s.dpy.con.remove_obj(&*s.selector);
|
|
}
|
|
ScreencastPhase::Starting(s) => {
|
|
s.node.con.destroy_obj(s.node.deref());
|
|
s.dpy.sessions.remove(self.session_obj.path());
|
|
match &s.target {
|
|
ScreencastTarget::Output(_) => {}
|
|
ScreencastTarget::Workspace(_, w, true) => {
|
|
s.dpy.con.remove_obj(&**w);
|
|
}
|
|
ScreencastTarget::Workspace(_, _, false) => {}
|
|
ScreencastTarget::Toplevel(t) => {
|
|
s.dpy.con.remove_obj(&**t);
|
|
}
|
|
}
|
|
}
|
|
ScreencastPhase::Started(s) => {
|
|
s.jay_screencast.con.remove_obj(s.jay_screencast.deref());
|
|
s.node.con.destroy_obj(s.node.deref());
|
|
s.dpy.sessions.remove(self.session_obj.path());
|
|
for buffer in s.pending_buffers.borrow_mut().drain(..) {
|
|
s.dpy.con.remove_obj(&*buffer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn send_start_reply(
|
|
&self,
|
|
pw_node_id: Option<u32>,
|
|
restore_data: Option<Variant<'static>>,
|
|
mapping_id: Option<&str>,
|
|
) {
|
|
let inner_type = DynamicType::DictEntry(
|
|
Box::new(DynamicType::String),
|
|
Box::new(DynamicType::Variant),
|
|
);
|
|
let kt = DynamicType::Struct(vec![
|
|
DynamicType::U32,
|
|
DynamicType::Array(Box::new(inner_type.clone())),
|
|
]);
|
|
let mut streams = vec![];
|
|
if let Some(node_id) = pw_node_id {
|
|
streams = vec![Variant::U32(node_id), Variant::Array(inner_type, vec![])];
|
|
}
|
|
let mut variants = vec![
|
|
DictEntry {
|
|
key: "devices".into(),
|
|
value: Variant::U32(DeviceTypes::all().0),
|
|
},
|
|
DictEntry {
|
|
key: "clipboard_enabled".into(),
|
|
value: Variant::Bool(FALSE),
|
|
},
|
|
DictEntry {
|
|
key: "streams".into(),
|
|
value: Variant::Array(kt, streams),
|
|
},
|
|
];
|
|
if let Some(rd) = restore_data {
|
|
variants.push(DictEntry {
|
|
key: "restore_data".into(),
|
|
value: rd,
|
|
});
|
|
}
|
|
if let Some(mapping_id) = mapping_id {
|
|
variants.push(DictEntry {
|
|
key: "mapping_id".into(),
|
|
value: Variant::String(mapping_id.into()),
|
|
});
|
|
}
|
|
if let Some(reply) = self.start_reply.take() {
|
|
match reply {
|
|
PortalSessionReply::RemoteDesktop(reply) => {
|
|
reply.ok(&RdStartReply {
|
|
response: PORTAL_SUCCESS,
|
|
results: Cow::Borrowed(&variants),
|
|
});
|
|
}
|
|
PortalSessionReply::ScreenCast(reply) => {
|
|
reply.ok(&ScStartReply {
|
|
response: PORTAL_SUCCESS,
|
|
results: Cow::Borrowed(&variants),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn reply_err(&self, err: &str) {
|
|
if let Some(reply) = self.start_reply.take() {
|
|
match reply {
|
|
PortalSessionReply::RemoteDesktop(r) => r.err(err),
|
|
PortalSessionReply::ScreenCast(r) => r.err(err),
|
|
}
|
|
}
|
|
}
|
|
}
|