use std::{collections::HashMap, num::NonZeroU32, os::fd::OwnedFd};
use enumflags2::{BitFlags, bitflags};
use futures_util::Stream;
use serde::{Deserialize, de::Visitor};
use serde_repr::{Deserialize_repr, Serialize_repr};
use zbus::zvariant::{
self, DeserializeDict, ObjectPath, OwnedObjectPath, OwnedValue, SerializeDict, Type, Value,
};
use super::{HandleToken, Request, Session, session::SessionPortal};
use crate::{Error, WindowIdentifier, proxy::Proxy, window_identifier::MaybeWindowIdentifierExt};
#[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<ActivatedBarrier>,
}
#[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<ActivatedBarrier> {
self.1.barrier_id
}
}
#[derive(Clone, Copy, Debug, Type)]
#[zvariant(signature = "u")]
pub enum ActivatedBarrier {
Barrier(BarrierID),
UnknownBarrier,
}
impl<'de> Deserialize<'de> for ActivatedBarrier {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let visitor = ActivatedBarrierVisitor {};
deserializer.deserialize_u32(visitor)
}
}
struct ActivatedBarrierVisitor {}
impl Visitor<'_> for ActivatedBarrierVisitor {
type Value = ActivatedBarrier;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "an unsigned 32bit integer (u32)")
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match BarrierID::new(v) {
Some(v) => Ok(ActivatedBarrier::Barrier(v)),
None => Ok(ActivatedBarrier::UnknownBarrier),
}
}
}
#[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 = NonZeroU32;
#[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(Proxy<'static>);
impl InputCapture {
pub async fn new() -> Result<InputCapture, Error> {
let proxy = Proxy::new_desktop("org.freedesktop.portal.InputCapture").await?;
Ok(Self(proxy))
}
pub async fn with_connection(connection: zbus::Connection) -> Result<InputCapture, Error> {
let proxy =
Proxy::new_desktop_with_connection(connection, "org.freedesktop.portal.InputCapture")
.await?;
Ok(Self(proxy))
}
#[doc(alias = "CreateSession")]
pub async fn create_session(
&self,
identifier: Option<&WindowIdentifier>,
capabilities: BitFlags<Capabilities>,
) -> Result<(Session<Self>, BitFlags<Capabilities>), Error> {
let options = CreateSessionOptions {
handle_token: Default::default(),
session_handle_token: Default::default(),
capabilities,
};
let identifier = identifier.to_string_or_empty();
let (request, proxy) = futures_util::try_join!(
self.0.request::<CreateSessionResponse>(
&options.handle_token,
"CreateSession",
(identifier, &options)
),
Session::from_unique_name(self.0.connection().clone(), &options.session_handle_token),
)?;
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
}
#[doc(alias = "Enable")]
pub async fn enable(&self, session: &Session<Self>) -> Result<(), Error> {
let options = EnableOptions::default();
self.0.call("Enable", &(session, &options)).await
}
#[doc(alias = "Disable")]
pub async fn disable(&self, session: &Session<Self>) -> Result<(), Error> {
let options = DisableOptions::default();
self.0.call("Disable", &(session, &options)).await
}
#[doc(alias = "Release")]
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 std::ops::Deref for InputCapture {
type Target = zbus::Proxy<'static>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl crate::Sealed for InputCapture {}
impl SessionPortal for InputCapture {}