use std::{collections::HashMap, os::fd::OwnedFd};
use enumflags2::{bitflags, BitFlags};
use futures_util::TryFutureExt;
use serde_repr::{Deserialize_repr, Serialize_repr};
use zbus::zvariant::{self, DeserializeDict, SerializeDict, Type, Value};
use super::{screencast::Stream, HandleToken, Request, Session};
use crate::{proxy::Proxy, Error, WindowIdentifier};
#[cfg_attr(feature = "glib", derive(glib::Enum))]
#[cfg_attr(feature = "glib", enum_type(name = "AshpdKeyState"))]
#[derive(Serialize_repr, Deserialize_repr, Copy, Clone, PartialEq, Eq, Debug, Type)]
#[doc(alias = "XdpKeyState")]
#[repr(u32)]
pub enum KeyState {
#[doc(alias = "XDP_KEY_PRESSED")]
Pressed = 1,
#[doc(alias = "XDP_KEY_RELEASED")]
Released = 0,
}
#[bitflags]
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Eq, 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,
}
#[cfg_attr(feature = "glib", derive(glib::Enum))]
#[cfg_attr(feature = "glib", enum_type(name = "AshpdAxis"))]
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Eq, Debug, Clone, Copy, Type)]
#[doc(alias = "XdpDiscreteAxis")]
#[repr(u32)]
pub enum Axis {
#[doc(alias = "XDP_AXIS_VERTICAL_SCROLL")]
Vertical = 0,
#[doc(alias = "XDP_AXIS_HORIZONTAL_SCROLL")]
Horizontal = 1,
}
#[derive(SerializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
struct CreateRemoteOptions {
handle_token: HandleToken,
session_handle_token: HandleToken,
}
#[derive(DeserializeDict, Type, Debug)]
#[zvariant(signature = "dict")]
struct CreateSession {
session_handle: String,
}
#[derive(SerializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
struct SelectDevicesOptions {
handle_token: HandleToken,
types: Option<BitFlags<DeviceType>>,
}
impl SelectDevicesOptions {
pub fn types(mut self, types: impl Into<Option<BitFlags<DeviceType>>>) -> Self {
self.types = types.into();
self
}
}
#[derive(SerializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
struct StartRemoteOptions {
handle_token: HandleToken,
}
#[derive(DeserializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct SelectedDevices {
devices: BitFlags<DeviceType>,
streams: Option<Vec<Stream>>,
}
impl SelectedDevices {
pub fn devices(&self) -> BitFlags<DeviceType> {
self.devices
}
pub fn streams(&self) -> Option<&[Stream]> {
self.streams.as_deref()
}
}
#[derive(Debug)]
#[doc(alias = "org.freedesktop.portal.RemoteDesktop")]
pub struct RemoteDesktop<'a>(Proxy<'a>);
impl<'a> RemoteDesktop<'a> {
pub async fn new() -> Result<RemoteDesktop<'a>, Error> {
let proxy = Proxy::new_desktop("org.freedesktop.portal.RemoteDesktop").await?;
Ok(Self(proxy))
}
#[doc(alias = "CreateSession")]
#[doc(alias = "xdp_portal_create_remote_desktop_session")]
pub async fn create_session(&self) -> Result<Session<'a>, Error> {
let options = CreateRemoteOptions::default();
let (request, proxy) = futures_util::try_join!(
self.0
.request::<CreateSession>(&options.handle_token, "CreateSession", &options)
.into_future(),
Session::from_unique_name(&options.session_handle_token).into_future()
)?;
assert_eq!(proxy.path().as_str(), &request.response()?.session_handle);
Ok(proxy)
}
#[doc(alias = "SelectDevices")]
pub async fn select_devices(
&self,
session: &Session<'_>,
types: BitFlags<DeviceType>,
) -> Result<Request<()>, Error> {
let options = SelectDevicesOptions::default().types(types);
self.0
.empty_request(&options.handle_token, "SelectDevices", &(session, &options))
.await
}
#[doc(alias = "Start")]
pub async fn start(
&self,
session: &Session<'_>,
identifier: &WindowIdentifier,
) -> Result<Request<SelectedDevices>, Error> {
let options = StartRemoteOptions::default();
self.0
.request(
&options.handle_token,
"Start",
&(session, &identifier, &options),
)
.await
}
#[doc(alias = "NotifyKeyboardKeycode")]
pub async fn notify_keyboard_keycode(
&self,
session: &Session<'_>,
keycode: i32,
state: KeyState,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
self.0
.call("NotifyKeyboardKeycode", &(session, options, keycode, state))
.await
}
#[doc(alias = "NotifyKeyboardKeysym")]
pub async fn notify_keyboard_keysym(
&self,
session: &Session<'_>,
keysym: i32,
state: KeyState,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
self.0
.call("NotifyKeyboardKeysym", &(session, options, keysym, state))
.await
}
#[doc(alias = "NotifyTouchUp")]
pub async fn notify_touch_up(&self, session: &Session<'_>, slot: u32) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
self.0
.call("NotifyTouchUp", &(session, options, slot))
.await
}
#[doc(alias = "NotifyTouchDown")]
pub async fn notify_touch_down(
&self,
session: &Session<'_>,
stream: u32,
slot: u32,
x: f64,
y: f64,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
self.0
.call("NotifyTouchDown", &(session, options, stream, slot, x, y))
.await
}
#[doc(alias = "NotifyTouchMotion")]
pub async fn notify_touch_motion(
&self,
session: &Session<'_>,
stream: u32,
slot: u32,
x: f64,
y: f64,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
self.0
.call("NotifyTouchMotion", &(session, options, stream, slot, x, y))
.await
}
#[doc(alias = "NotifyPointerMotionAbsolute")]
pub async fn notify_pointer_motion_absolute(
&self,
session: &Session<'_>,
stream: u32,
x: f64,
y: f64,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
self.0
.call(
"NotifyPointerMotionAbsolute",
&(session, options, stream, x, y),
)
.await
}
#[doc(alias = "NotifyPointerMotion")]
pub async fn notify_pointer_motion(
&self,
session: &Session<'_>,
dx: f64,
dy: f64,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
self.0
.call("NotifyPointerMotion", &(session, options, dx, dy))
.await
}
#[doc(alias = "NotifyPointerButton")]
pub async fn notify_pointer_button(
&self,
session: &Session<'_>,
button: i32,
state: KeyState,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
self.0
.call("NotifyPointerButton", &(session, options, button, state))
.await
}
#[doc(alias = "NotifyPointerAxisDiscrete")]
pub async fn notify_pointer_axis_discrete(
&self,
session: &Session<'_>,
axis: Axis,
steps: i32,
) -> Result<(), Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
self.0
.call(
"NotifyPointerAxisDiscrete",
&(session, options, axis, steps),
)
.await
}
#[doc(alias = "NotifyPointerAxis")]
pub async fn notify_pointer_axis(
&self,
session: &Session<'_>,
dx: f64,
dy: f64,
finish: bool,
) -> Result<(), Error> {
let mut options: HashMap<&str, Value<'_>> = HashMap::new();
options.insert("finish", Value::Bool(finish));
self.0
.call("NotifyPointerAxis", &(session, options, dx, dy))
.await
}
#[doc(alias = "ConnectToEIS")]
pub async fn connect_to_eis(&self, session: &Session<'_>) -> Result<OwnedFd, Error> {
let options: HashMap<&str, Value<'_>> = HashMap::new();
let fd = self
.0
.call_versioned::<zvariant::OwnedFd>("ConnectToEIS", &(session, options), 2)
.await?;
Ok(fd.into())
}
#[doc(alias = "AvailableDeviceTypes")]
pub async fn available_device_types(&self) -> Result<BitFlags<DeviceType>, Error> {
self.0.property("AvailableDeviceTypes").await
}
}
impl<'a> std::ops::Deref for RemoteDesktop<'a> {
type Target = zbus::Proxy<'a>;
fn deref(&self) -> &Self::Target {
&self.0
}
}