use std::os::fd::OwnedFd;
use enumflags2::{BitFlags, bitflags};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use zbus::zvariant::{
self, Optional, Type,
as_value::{self, optional},
};
use super::{
HandleToken, PersistMode, Request, Session, screencast::Stream, session::SessionPortal,
};
use crate::{
Error, WindowIdentifier,
desktop::session::{CreateSessionOptions, CreateSessionResponse},
proxy::Proxy,
};
#[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(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct NotifyKeyboardKeycodeOptions {}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct NotifyKeyboardKeysymOptions {}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct NotifyPointerAxisDiscreteOptions {}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct NotifyTouchUpOptions {}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct NotifyTouchDownOptions {}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct NotifyTouchMotionOptions {}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct NotifyPointerButtonOptions {}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct NotifyPointerMotionOptions {}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct NotifyPointerMotionAbsoluteOptions {}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct NotifyPointerAxisOptions {
#[serde(with = "as_value")]
finish: bool,
}
impl NotifyPointerAxisOptions {
pub fn set_finish(mut self, finish: bool) -> Self {
self.finish = finish;
self
}
}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct SelectDevicesOptions {
#[serde(with = "as_value")]
handle_token: HandleToken,
#[serde(with = "optional", skip_serializing_if = "Option::is_none")]
types: Option<BitFlags<DeviceType>>,
#[serde(with = "optional", skip_serializing_if = "Option::is_none")]
restore_token: Option<String>,
#[serde(with = "optional", skip_serializing_if = "Option::is_none")]
persist_mode: Option<PersistMode>,
}
impl SelectDevicesOptions {
pub fn set_devices(mut self, types: impl Into<Option<BitFlags<DeviceType>>>) -> Self {
self.types = types.into();
self
}
pub fn set_persist_mode(mut self, persist_mode: impl Into<Option<PersistMode>>) -> Self {
self.persist_mode = persist_mode.into();
self
}
pub fn set_restore_token<'a>(mut self, token: impl Into<Option<&'a str>>) -> Self {
self.restore_token = token.into().map(ToOwned::to_owned);
self
}
}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct StartOptions {
#[serde(with = "as_value")]
handle_token: HandleToken,
}
#[derive(Deserialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct SelectedDevices {
#[serde(default, with = "as_value")]
devices: BitFlags<DeviceType>,
#[serde(default, with = "as_value")]
streams: Vec<Stream>,
#[serde(default, with = "optional")]
restore_token: Option<String>,
#[serde(default, with = "optional")]
clipboard_enabled: Option<bool>,
}
impl SelectedDevices {
pub fn devices(&self) -> BitFlags<DeviceType> {
self.devices
}
pub fn streams(&self) -> &[Stream] {
&self.streams
}
pub fn restore_token(&self) -> Option<&str> {
self.restore_token.as_deref()
}
pub fn is_clipboard_enabled(&self) -> bool {
self.clipboard_enabled.unwrap_or(false)
}
}
#[derive(Default, Debug, Serialize, Type)]
#[zvariant(signature = "dict")]
pub struct ConnectToEISOptions {}
#[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))
}
pub fn version(&self) -> u32 {
self.0.version()
}
#[doc(alias = "CreateSession")]
#[doc(alias = "xdp_portal_create_remote_desktop_session")]
pub async fn create_session(
&self,
options: CreateSessionOptions,
) -> Result<Session<Self>, Error> {
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>,
options: SelectDevicesOptions,
) -> Result<Request<()>, Error> {
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>,
options: StartOptions,
) -> Result<Request<SelectedDevices>, Error> {
let identifier = Optional::from(identifier);
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,
options: NotifyKeyboardKeycodeOptions,
) -> Result<(), Error> {
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,
options: NotifyKeyboardKeysymOptions,
) -> Result<(), Error> {
self.0
.call("NotifyKeyboardKeysym", &(session, options, keysym, state))
.await
}
#[doc(alias = "NotifyTouchUp")]
pub async fn notify_touch_up(
&self,
session: &Session<Self>,
slot: u32,
options: NotifyTouchUpOptions,
) -> Result<(), Error> {
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,
options: NotifyTouchDownOptions,
) -> Result<(), Error> {
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,
options: NotifyTouchMotionOptions,
) -> Result<(), Error> {
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,
options: NotifyPointerMotionAbsoluteOptions,
) -> Result<(), Error> {
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,
options: NotifyPointerMotionOptions,
) -> Result<(), Error> {
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,
options: NotifyPointerButtonOptions,
) -> Result<(), Error> {
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,
options: NotifyPointerAxisDiscreteOptions,
) -> Result<(), Error> {
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,
options: NotifyPointerAxisOptions,
) -> Result<(), Error> {
self.0
.call("NotifyPointerAxis", &(session, options, dx, dy))
.await
}
#[doc(alias = "ConnectToEIS")]
pub async fn connect_to_eis(
&self,
session: &Session<Self>,
options: ConnectToEISOptions,
) -> Result<OwnedFd, Error> {
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 {}
#[cfg(feature = "clipboard")]
impl crate::desktop::clipboard::IsClipboardSession for RemoteDesktop {}
#[cfg(feature = "screencast")]
impl crate::desktop::screencast::IsScreencastSession for RemoteDesktop {}