use std::{collections::HashMap, os::fd::OwnedFd};
use enumflags2::{bitflags, BitFlags};
use futures_util::{Stream, TryFutureExt};
use serde::Deserialize;
use serde_repr::{Deserialize_repr, Serialize_repr};
use zbus::zvariant::{
self, DeserializeDict, ObjectPath, OwnedObjectPath, OwnedValue, SerializeDict, Type, Value,
};
use super::{session::SessionPortal, HandleToken, Request, Session};
use crate::{proxy::Proxy, Error, WindowIdentifier};
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Eq, Debug, Copy, Clone, Type)]
#[bitflags]
#[repr(u32)]
pub enum Capabilities {
Keyboard,
Pointer,
Touchscreen,
}
#[derive(Debug, SerializeDict, Type)]
#[zvariant(signature = "dict")]
struct CreateSessionOptions {
handle_token: HandleToken,
session_handle_token: HandleToken,
capabilities: BitFlags<Capabilities>,
}
#[derive(Debug, DeserializeDict, Type)]
#[zvariant(signature = "dict")]
struct CreateSessionResponse {
session_handle: OwnedObjectPath,
capabilities: BitFlags<Capabilities>,
}
#[derive(Default, Debug, SerializeDict, Type)]
#[zvariant(signature = "dict")]
struct GetZonesOptions {
handle_token: HandleToken,
}
#[derive(Default, Debug, SerializeDict, Type)]
#[zvariant(signature = "dict")]
struct SetPointerBarriersOptions {
handle_token: HandleToken,
}
#[derive(Default, Debug, SerializeDict, Type)]
#[zvariant(signature = "dict")]
struct EnableOptions {}
#[derive(Default, Debug, SerializeDict, Type)]
#[zvariant(signature = "dict")]
struct DisableOptions {}
#[derive(Default, Debug, SerializeDict, Type)]
#[zvariant(signature = "dict")]
struct ReleaseOptions {
activation_id: Option<u32>,
cursor_position: Option<(f64, f64)>,
}
#[derive(Debug, Deserialize, Type)]
#[zvariant(signature = "(oa{sv})")]
pub struct Disabled(OwnedObjectPath, HashMap<String, OwnedValue>);
impl Disabled {
pub fn session_handle(&self) -> ObjectPath<'_> {
self.0.as_ref()
}
pub fn options(&self) -> &HashMap<String, OwnedValue> {
&self.1
}
}
#[derive(Debug, DeserializeDict, Type)]
#[zvariant(signature = "dict")]
struct DeactivatedOptions {
activation_id: Option<u32>,
}
#[derive(Debug, Deserialize, Type)]
#[zvariant(signature = "(oa{sv})")]
pub struct Deactivated(OwnedObjectPath, DeactivatedOptions);
impl Deactivated {
pub fn session_handle(&self) -> ObjectPath<'_> {
self.0.as_ref()
}
pub fn activation_id(&self) -> Option<u32> {
self.1.activation_id
}
}
#[derive(Debug, DeserializeDict, Type)]
#[zvariant(signature = "dict")]
struct ActivatedOptions {
activation_id: Option<u32>,
cursor_position: Option<(f32, f32)>,
barrier_id: Option<BarrierID>,
}
#[derive(Debug, Deserialize, Type)]
#[zvariant(signature = "(oa{sv})")]
pub struct Activated(OwnedObjectPath, ActivatedOptions);
impl Activated {
pub fn session_handle(&self) -> ObjectPath<'_> {
self.0.as_ref()
}
pub fn activation_id(&self) -> Option<u32> {
self.1.activation_id
}
pub fn cursor_position(&self) -> Option<(f32, f32)> {
self.1.cursor_position
}
pub fn barrier_id(&self) -> Option<BarrierID> {
self.1.barrier_id
}
}
#[derive(Debug, DeserializeDict, Type)]
#[zvariant(signature = "dict")]
struct ZonesChangedOptions {
zone_set: Option<u32>,
}
#[derive(Debug, Deserialize, Type)]
#[zvariant(signature = "(oa{sv})")]
pub struct ZonesChanged(OwnedObjectPath, ZonesChangedOptions);
impl ZonesChanged {
pub fn session_handle(&self) -> ObjectPath<'_> {
self.0.as_ref()
}
pub fn zone_set(&self) -> Option<u32> {
self.1.zone_set
}
}
#[derive(Debug, Clone, Copy, Deserialize, Type)]
#[zvariant(signature = "(uuii)")]
pub struct Region(u32, u32, i32, i32);
impl Region {
pub fn width(self) -> u32 {
self.0
}
pub fn height(self) -> u32 {
self.1
}
pub fn x_offset(self) -> i32 {
self.2
}
pub fn y_offset(self) -> i32 {
self.3
}
}
#[derive(Debug, Type, DeserializeDict)]
#[zvariant(signature = "dict")]
pub struct Zones {
zones: Vec<Region>,
zone_set: u32,
}
impl Zones {
pub fn regions(&self) -> &[Region] {
&self.zones
}
pub fn zone_set(&self) -> u32 {
self.zone_set
}
}
pub type BarrierID = u32;
#[derive(Debug, SerializeDict, Type)]
#[zvariant(signature = "dict")]
pub struct Barrier {
barrier_id: BarrierID,
position: (i32, i32, i32, i32),
}
impl Barrier {
pub fn new(barrier_id: BarrierID, position: (i32, i32, i32, i32)) -> Self {
Self {
barrier_id,
position,
}
}
}
#[derive(Debug, DeserializeDict, Type)]
#[zvariant(signature = "dict")]
pub struct SetPointerBarriersResponse {
failed_barriers: Vec<BarrierID>,
}
impl SetPointerBarriersResponse {
pub fn failed_barriers(&self) -> &[BarrierID] {
&self.failed_barriers
}
}
#[doc(alias = "org.freedesktop.portal.InputCapture")]
pub struct InputCapture<'a>(Proxy<'a>);
impl<'a> InputCapture<'a> {
pub async fn new() -> Result<InputCapture<'a>, Error> {
let proxy = Proxy::new_desktop("org.freedesktop.portal.InputCapture").await?;
Ok(Self(proxy))
}
pub async fn create_session(
&self,
parent_window: &WindowIdentifier,
capabilities: BitFlags<Capabilities>,
) -> Result<(Session<'_, Self>, BitFlags<Capabilities>), Error> {
let options = CreateSessionOptions {
handle_token: Default::default(),
session_handle_token: Default::default(),
capabilities,
};
let (request, proxy) = futures_util::try_join!(
self.0
.request::<CreateSessionResponse>(
&options.handle_token,
"CreateSession",
(parent_window, &options)
)
.into_future(),
Session::from_unique_name(&options.session_handle_token).into_future(),
)?;
let response = request.response()?;
assert_eq!(proxy.path(), &response.session_handle.as_ref());
Ok((proxy, response.capabilities))
}
#[doc(alias = "GetZones")]
pub async fn zones(&self, session: &Session<'_, Self>) -> Result<Request<Zones>, Error> {
let options = GetZonesOptions::default();
self.0
.request(&options.handle_token, "GetZones", (session, &options))
.await
}
#[doc(alias = "SetPointerBarriers")]
pub async fn set_pointer_barriers(
&self,
session: &Session<'_, Self>,
barriers: &[Barrier],
zone_set: u32,
) -> Result<Request<SetPointerBarriersResponse>, Error> {
let options = SetPointerBarriersOptions::default();
self.0
.request(
&options.handle_token,
"SetPointerBarriers",
&(session, &options, barriers, zone_set),
)
.await
}
pub async fn enable(&self, session: &Session<'_, Self>) -> Result<(), Error> {
let options = EnableOptions::default();
self.0.call("Enable", &(session, &options)).await
}
pub async fn disable(&self, session: &Session<'_, Self>) -> Result<(), Error> {
let options = DisableOptions::default();
self.0.call("Disable", &(session, &options)).await
}
pub async fn release(
&self,
session: &Session<'_, Self>,
activation_id: Option<u32>,
cursor_position: Option<(f64, f64)>,
) -> Result<(), Error> {
let options = ReleaseOptions {
activation_id,
cursor_position,
};
self.0.call("Release", &(session, &options)).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::<zvariant::OwnedFd>("ConnectToEIS", &(session, options))
.await?;
Ok(fd.into())
}
#[doc(alias = "Disabled")]
pub async fn receive_disabled(&self) -> Result<impl Stream<Item = Disabled>, Error> {
self.0.signal("Disabled").await
}
#[doc(alias = "Activated")]
pub async fn receive_activated(&self) -> Result<impl Stream<Item = Activated>, Error> {
self.0.signal("Activated").await
}
#[doc(alias = "Deactivated")]
pub async fn receive_deactivated(&self) -> Result<impl Stream<Item = Deactivated>, Error> {
self.0.signal("Deactivated").await
}
#[doc(alias = "ZonesChanged")]
pub async fn receive_zones_changed(&self) -> Result<impl Stream<Item = ZonesChanged>, Error> {
self.0.signal("ZonesChanged").await
}
#[doc(alias = "SupportedCapabilities")]
pub async fn supported_capabilities(&self) -> Result<BitFlags<Capabilities>, Error> {
self.0.property("SupportedCapabilities").await
}
}
impl<'a> std::ops::Deref for InputCapture<'a> {
type Target = zbus::Proxy<'a>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl crate::Sealed for InputCapture<'_> {}
impl SessionPortal for InputCapture<'_> {}