use super::{HandleToken, SessionProxy, DESTINATION, PATH};
use crate::{
helpers::{call_basic_response_method, call_method, call_request_method},
Error, WindowIdentifier,
};
use enumflags2::BitFlags;
use futures::TryFutureExt;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use std::{
collections::HashMap,
os::unix::prelude::{AsRawFd, RawFd},
};
use zvariant::{Fd, Value};
use zvariant_derive::{DeserializeDict, SerializeDict, Type, TypeDict};
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Copy, Clone, Debug, Type, BitFlags)]
#[repr(u32)]
pub enum SourceType {
Monitor = 1,
Window = 2,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, Copy, Clone, Type, BitFlags)]
#[repr(u32)]
pub enum CursorMode {
Hidden = 1,
Embedded = 2,
Metadata = 4,
}
#[derive(SerializeDict, DeserializeDict, TypeDict, Debug, Default)]
struct CreateSessionOptions {
handle_token: HandleToken,
session_handle_token: HandleToken,
}
#[derive(SerializeDict, DeserializeDict, TypeDict, Debug, Default)]
struct SelectSourcesOptions {
handle_token: HandleToken,
types: Option<BitFlags<SourceType>>,
multiple: Option<bool>,
cursor_mode: Option<BitFlags<CursorMode>>,
}
impl SelectSourcesOptions {
pub fn multiple(mut self, multiple: bool) -> Self {
self.multiple = Some(multiple);
self
}
pub fn cursor_mode(mut self, cursor_mode: BitFlags<CursorMode>) -> Self {
self.cursor_mode = Some(cursor_mode);
self
}
pub fn types(mut self, types: BitFlags<SourceType>) -> Self {
self.types = Some(types);
self
}
}
#[derive(SerializeDict, DeserializeDict, TypeDict, Debug, Default)]
struct StartCastOptions {
handle_token: HandleToken,
}
#[derive(SerializeDict, DeserializeDict, TypeDict, Debug)]
struct CreateSession {
session_handle: String,
}
#[derive(SerializeDict, DeserializeDict, TypeDict, Debug)]
struct Streams {
pub streams: Vec<Stream>,
}
#[derive(Serialize, Deserialize, Type, Debug, Clone)]
pub struct Stream(u32, StreamProperties);
impl Stream {
pub fn pipe_wire_node_id(&self) -> u32 {
self.0
}
pub fn position(&self) -> Option<(i32, i32)> {
self.1.position
}
pub fn size(&self) -> (i32, i32) {
self.1.size
}
}
#[derive(SerializeDict, DeserializeDict, TypeDict, Debug, Clone)]
struct StreamProperties {
position: Option<(i32, i32)>,
size: (i32, i32),
}
#[derive(Debug)]
#[doc(alias = "org.freedesktop.portal.ScreenCast")]
pub struct ScreenCastProxy<'a>(zbus::azync::Proxy<'a>);
impl<'a> ScreenCastProxy<'a> {
pub async fn new(connection: &zbus::azync::Connection) -> Result<ScreenCastProxy<'a>, Error> {
let proxy = zbus::ProxyBuilder::new_bare(connection)
.interface("org.freedesktop.portal.ScreenCast")
.path(PATH)?
.destination(DESTINATION)
.build_async()
.await?;
Ok(Self(proxy))
}
pub fn inner(&self) -> &zbus::azync::Proxy<'_> {
&self.0
}
#[doc(alias = "CreateSession")]
pub async fn create_session(&self) -> Result<SessionProxy<'a>, Error> {
let options = CreateSessionOptions::default();
let (session, proxy) = futures::try_join!(
call_request_method::<CreateSession, CreateSessionOptions>(
&self.0,
&options.handle_token,
"CreateSession",
&(&options)
)
.into_future(),
SessionProxy::from_unique_name(self.0.connection(), &options.session_handle_token)
.into_future(),
)?;
assert_eq!(proxy.inner().path().to_string(), session.session_handle);
Ok(proxy)
}
#[doc(alias = "OpenPipeWireRemote")]
pub async fn open_pipe_wire_remote(&self, session: &SessionProxy<'_>) -> Result<RawFd, Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
let fd: Fd = call_method(&self.0, "OpenPipeWireRemote", &(session, options)).await?;
Ok(fd.as_raw_fd())
}
#[doc(alias = "SelectSources")]
pub async fn select_sources(
&self,
session: &SessionProxy<'_>,
cursor_mode: BitFlags<CursorMode>,
types: BitFlags<SourceType>,
multiple: bool,
) -> Result<(), Error> {
let options = SelectSourcesOptions::default()
.cursor_mode(cursor_mode)
.multiple(multiple)
.types(types);
call_basic_response_method(
&self.0,
&options.handle_token,
"SelectSources",
&(session, &options),
)
.await
}
#[doc(alias = "Start")]
pub async fn start(
&self,
session: &SessionProxy<'_>,
identifier: WindowIdentifier,
) -> Result<Vec<Stream>, Error> {
let options = StartCastOptions::default();
let streams: Streams = call_request_method(
&self.0,
&options.handle_token,
"Start",
&(session, identifier, &options),
)
.await?;
Ok(streams.streams.to_vec())
}
#[doc(alias = "AvailableCursorModes")]
pub async fn available_cursor_modes(&self) -> Result<BitFlags<CursorMode>, Error> {
self.inner()
.get_property::<BitFlags<CursorMode>>("AvailableCursorModes")
.await
.map_err(From::from)
}
#[doc(alias = "AvailableSourceTypes")]
pub async fn available_source_types(&self) -> Result<BitFlags<SourceType>, Error> {
self.inner()
.get_property::<BitFlags<SourceType>>("AvailableSourceTypes")
.await
.map_err(From::from)
}
}