use std::{collections::HashMap, os::fd::OwnedFd};
use enumflags2::{BitFlags, bitflags};
use serde_repr::{Deserialize_repr, Serialize_repr};
use zbus::zvariant::{self, DeserializeDict, SerializeDict, Type, Value};
use super::{
HandleToken, PersistMode, Request, Session, screencast::Stream, session::SessionPortal,
};
use crate::{
Error, WindowIdentifier, desktop::session::CreateSessionResponse, proxy::Proxy,
window_identifier::MaybeWindowIdentifierExt,
};
#[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(SerializeDict, Type, Debug, Default)]
#[zvariant(signature = "dict")]
struct SelectDevicesOptions {
handle_token: HandleToken,
types: Option<BitFlags<DeviceType>>,
restore_token: Option<String>,
persist_mode: Option<PersistMode>,
}
impl SelectDevicesOptions {
pub fn types(mut self, types: impl Into<Option<BitFlags<DeviceType>>>) -> Self {
self.types = types.into();
self
}
pub fn persist_mode(mut self, persist_mode: impl Into<Option<PersistMode>>) -> Self {
self.persist_mode = persist_mode.into();
self
}
pub fn restore_token<'a>(mut self, token: impl Into<Option<&'a str>>) -> Self {
self.restore_token = token.into().map(ToOwned::to_owned);
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>>,
restore_token: Option<String>,
}
impl SelectedDevices {
pub fn devices(&self) -> BitFlags<DeviceType> {
self.devices
}
pub fn streams(&self) -> Option<&[Stream]> {
self.streams.as_deref()
}
pub fn restore_token(&self) -> Option<&str> {
self.restore_token.as_deref()
}
}
#[derive(Debug)]
#[doc(alias = "org.freedesktop.portal.RemoteDesktop")]
pub struct RemoteDesktop(Proxy<'static>);
impl RemoteDesktop {
pub async fn new() -> Result<Self, Error> {
let proxy = Proxy::new_desktop("org.freedesktop.portal.RemoteDesktop").await?;
Ok(Self(proxy))
}
pub async fn with_connection(connection: zbus::Connection) -> Result<Self, Error> {
let proxy =
Proxy::new_desktop_with_connection(connection, "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<Self>, Error> {
let options = CreateRemoteOptions::default();
let (request, proxy) = futures_util::try_join!(
self.0.request::<CreateSessionResponse>(
&options.handle_token,
"CreateSession",
&options
),
Session::from_unique_name(self.0.connection().clone(), &options.session_handle_token)
)?;
assert_eq!(proxy.path(), &request.response()?.session_handle.as_ref());
Ok(proxy)
}
#[doc(alias = "SelectDevices")]
pub async fn select_devices(
&self,
session: &Session<Self>,
types: BitFlags<DeviceType>,
restore_token: Option<&str>,
persist_mode: PersistMode,
) -> Result<Request<()>, Error> {
let options = SelectDevicesOptions::default()
.types(types)
.persist_mode(persist_mode)
.restore_token(restore_token);
self.0
.empty_request(&options.handle_token, "SelectDevices", &(session, &options))
.await
}
#[doc(alias = "Start")]
pub async fn start(
&self,
session: &Session<Self>,
identifier: Option<&WindowIdentifier>,
) -> Result<Request<SelectedDevices>, Error> {
let options = StartRemoteOptions::default();
let identifier = identifier.to_string_or_empty();
self.0
.request(
&options.handle_token,
"Start",
&(session, &identifier, &options),
)
.await
}
#[doc(alias = "NotifyKeyboardKeycode")]
pub async fn notify_keyboard_keycode(
&self,
session: &Session<Self>,
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<Self>,
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<Self>, 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<Self>,
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<Self>,
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<Self>,
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<Self>,
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<Self>,
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<Self>,
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<Self>,
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<Self>) -> 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 std::ops::Deref for RemoteDesktop {
type Target = zbus::Proxy<'static>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl crate::Sealed for RemoteDesktop {}
impl SessionPortal for RemoteDesktop {}