use std::collections::HashMap;
use enumflags2::{bitflags, BitFlags};
use futures::TryFutureExt;
use serde_repr::{Deserialize_repr, Serialize_repr};
use zbus::zvariant::{DeserializeDict, SerializeDict, Type, Value};
use super::{screencast::Stream, HandleToken, SessionProxy, DESTINATION, PATH};
use crate::{
helpers::{call_basic_response_method, call_method, call_request_method},
Error, WindowIdentifier,
};
#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Debug, Type)]
#[doc(alias = "XdpKeyState")]
#[repr(u8)]
pub enum KeyState {
#[doc(alias = "XDP_KEY_PRESSED")]
Pressed = 0,
#[doc(alias = "XDP_KEY_RELEASED")]
Released = 1,
}
#[bitflags]
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, Clone, Copy, Type)]
#[repr(u32)]
#[doc(alias = "XdpDeviceType")]
pub enum DeviceType {
#[doc(alias = "XDP_DEVICE_KEYBOARD")]
Keyboard,
#[doc(alias = "XDP_DEVICE_POINTER")]
Pointer,
#[doc(alias = "XDP_DEVICE_TOUCHSCREEN")]
Touchscreen,
}
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, Type)]
#[doc(alias = "XdpDiscreteAxis")]
#[repr(u8)]
pub enum Axis {
#[doc(alias = "XDP_AXIS_VERTICAL_SCROLL")]
Vertical = 0,
#[doc(alias = "XDP_AXIS_HORIZONTAL_SCROLL")]
Horizontal = 1,
}
#[derive(SerializeDict, DeserializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
struct CreateRemoteOptions {
handle_token: HandleToken,
session_handle_token: HandleToken,
}
#[derive(SerializeDict, DeserializeDict, Type, Debug)]
#[zvariant(signature = "dict")]
struct CreateSession {
session_handle: String,
}
#[derive(SerializeDict, DeserializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
struct SelectDevicesOptions {
handle_token: HandleToken,
types: Option<BitFlags<DeviceType>>,
}
impl SelectDevicesOptions {
pub fn types(mut self, types: BitFlags<DeviceType>) -> Self {
self.types = Some(types);
self
}
}
#[derive(SerializeDict, DeserializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
struct StartRemoteOptions {
handle_token: HandleToken,
}
#[derive(SerializeDict, DeserializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
struct SelectedDevices {
devices: BitFlags<DeviceType>,
streams: Option<Vec<Stream>>,
}
#[derive(Debug)]
#[doc(alias = "org.freedesktop.portal.RemoteDesktop")]
pub struct RemoteDesktopProxy<'a>(zbus::Proxy<'a>);
impl<'a> RemoteDesktopProxy<'a> {
pub async fn new(connection: &zbus::Connection) -> Result<RemoteDesktopProxy<'a>, Error> {
let proxy = zbus::ProxyBuilder::new_bare(connection)
.interface("org.freedesktop.portal.RemoteDesktop")?
.path(PATH)?
.destination(DESTINATION)?
.build()
.await?;
Ok(Self(proxy))
}
pub fn inner(&self) -> &zbus::Proxy<'_> {
&self.0
}
#[doc(alias = "CreateSession")]
#[doc(alias = "xdp_portal_create_remote_desktop_session")]
pub async fn create_session(&self) -> Result<SessionProxy<'a>, Error> {
let options = CreateRemoteOptions::default();
let (session, proxy) = futures::try_join!(
call_request_method::<CreateSession, _>(
self.inner(),
&options.handle_token,
"CreateSession",
&options
)
.into_future(),
SessionProxy::from_unique_name(
self.inner().connection(),
&options.session_handle_token
)
.into_future()
)?;
assert_eq!(proxy.inner().path().as_str(), &session.session_handle);
Ok(proxy)
}
#[doc(alias = "SelectDevices")]
pub async fn select_devices(
&self,
session: &SessionProxy<'_>,
types: BitFlags<DeviceType>,
) -> Result<(), Error> {
let options = SelectDevicesOptions::default().types(types);
call_basic_response_method(
self.inner(),
&options.handle_token,
"SelectDevices",
&(session, &options),
)
.await
}
#[doc(alias = "Start")]
pub async fn start(
&self,
session: &SessionProxy<'_>,
identifier: &WindowIdentifier,
) -> Result<(BitFlags<DeviceType>, Vec<Stream>), Error> {
let options = StartRemoteOptions::default();
let response: SelectedDevices = call_request_method(
self.inner(),
&options.handle_token,
"Start",
&(session, &identifier, &options),
)
.await?;
Ok((response.devices, response.streams.unwrap_or_default()))
}
#[doc(alias = "NotifyKeyboardKeycode")]
pub async fn notify_keyboard_keycode(
&self,
session: &SessionProxy<'_>,
keycode: i32,
state: KeyState,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
call_method(
self.inner(),
"NotifyKeyboardKeycode",
&(session, options, keycode, state),
)
.await
}
#[doc(alias = "NotifyKeyboardKeysym")]
pub async fn notify_keyboard_keysym(
&self,
session: &SessionProxy<'_>,
keysym: i32,
state: KeyState,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
call_method(
self.inner(),
"NotifyKeyboardKeysym",
&(session, options, keysym, state),
)
.await
}
#[doc(alias = "NotifyTouchUp")]
pub async fn notify_touch_up(
&self,
session: &SessionProxy<'_>,
slot: u32,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
call_method(self.inner(), "NotifyTouchUp", &(session, options, slot)).await
}
#[doc(alias = "NotifyTouchDown")]
pub async fn notify_touch_down(
&self,
session: &SessionProxy<'_>,
stream: u32,
slot: u32,
x: f64,
y: f64,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
call_method(
self.inner(),
"NotifyTouchDown",
&(session, options, stream, slot, x, y),
)
.await
}
#[doc(alias = "NotifyTouchMotion")]
pub async fn notify_touch_motion(
&self,
session: &SessionProxy<'_>,
stream: u32,
slot: u32,
x: f64,
y: f64,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
call_method(
self.inner(),
"NotifyTouchMotion",
&(session, options, stream, slot, x, y),
)
.await
}
#[doc(alias = "NotifyPointerMotionAbsolute")]
pub async fn notify_pointer_motion_absolute(
&self,
session: &SessionProxy<'_>,
stream: u32,
x: f64,
y: f64,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
call_method(
self.inner(),
"NotifyPointerMotionAbsolute",
&(session, options, stream, x, y),
)
.await
}
#[doc(alias = "NotifyPointerMotion")]
pub async fn notify_pointer_motion(
&self,
session: &SessionProxy<'_>,
dx: f64,
dy: f64,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
call_method(
self.inner(),
"NotifyPointerMotion",
&(session, options, dx, dy),
)
.await
}
#[doc(alias = "NotifyPointerButton")]
pub async fn notify_pointer_button(
&self,
session: &SessionProxy<'_>,
button: i32,
state: KeyState,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
call_method(
self.inner(),
"NotifyPointerButton",
&(session, options, button, state),
)
.await
}
#[doc(alias = "NotifyPointerAxisDiscrete")]
pub async fn notify_pointer_axis_discrete(
&self,
session: &SessionProxy<'_>,
axis: Axis,
steps: i32,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
call_method(
self.inner(),
"NotifyPointerAxisDiscrete",
&(session, options, axis, steps),
)
.await
}
#[doc(alias = "NotifyPointerAxis")]
pub async fn notify_pointer_axis(
&self,
session: &SessionProxy<'_>,
dx: f64,
dy: f64,
finish: bool,
) -> Result<(), Error> {
let mut options: HashMap<&str, Value<'_>> = HashMap::new();
options.insert("finish", Value::Bool(finish));
call_method(
self.inner(),
"NotifyPointerAxis",
&(session, options, dx, dy),
)
.await
}
#[doc(alias = "AvailableDeviceTypes")]
pub async fn available_device_types(&self) -> Result<BitFlags<DeviceType>, Error> {
self.inner()
.get_property::<BitFlags<DeviceType>>("AvailableDeviceTypes")
.await
.map_err(From::from)
}
}