ashpd/desktop/device.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
//! Request access to specific devices such as camera, speakers or microphone.
//!
//! **Note** This portal doesn't work for sandboxed applications.
//!
//! ### Examples
//!
//! Access a [`Device`]
//!
//! ```rust,no_run
//! use ashpd::desktop::device::{Device, DeviceProxy};
//!
//! async fn run() -> ashpd::Result<()> {
//! let proxy = DeviceProxy::new().await?;
//! proxy.access_device(6879, &[Device::Speakers]).await?;
//! Ok(())
//! }
//! ```
use std::{fmt, str::FromStr};
use serde::{Deserialize, Serialize};
use zbus::zvariant::{SerializeDict, Type};
use super::{HandleToken, Request};
use crate::{proxy::Proxy, Error, Pid};
#[derive(SerializeDict, Type, Debug, Default)]
/// Specified options for a [`DeviceProxy::access_device`] request.
#[zvariant(signature = "dict")]
struct AccessDeviceOptions {
/// A string that will be used as the last element of the handle.
handle_token: HandleToken,
}
#[cfg_attr(feature = "glib", derive(glib::Enum))]
#[cfg_attr(feature = "glib", enum_type(name = "AshpdDevice"))]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Type)]
#[zvariant(signature = "s")]
#[serde(rename_all = "lowercase")]
/// The possible device to request access to.
pub enum Device {
/// A microphone.
Microphone,
/// Speakers.
Speakers,
/// A Camera.
Camera,
}
impl fmt::Display for Device {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Microphone => write!(f, "Microphone"),
Self::Speakers => write!(f, "Speakers"),
Self::Camera => write!(f, "Camera"),
}
}
}
impl AsRef<str> for Device {
fn as_ref(&self) -> &str {
match self {
Self::Microphone => "Microphone",
Self::Speakers => "Speakers",
Self::Camera => "Camera",
}
}
}
impl From<Device> for &'static str {
fn from(d: Device) -> Self {
match d {
Device::Microphone => "Microphone",
Device::Speakers => "Speakers",
Device::Camera => "Camera",
}
}
}
impl FromStr for Device {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Microphone" | "microphone" => Ok(Device::Microphone),
"Speakers" | "speakers" => Ok(Device::Speakers),
"Camera" | "camera" => Ok(Device::Camera),
_ => Err(Error::ParseError("Failed to parse device, invalid value")),
}
}
}
/// The interface lets services ask if an application should get access to
/// devices such as microphones, speakers or cameras.
///
/// Not a portal in the strict sense, since the API is not directly
/// accessible to applications inside the sandbox.
///
/// Wrapper of the DBus interface:
/// [`org.freedesktop.portal.Device`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Device.html).
#[derive(Debug)]
#[doc(alias = "org.freedesktop.portal.Device")]
pub struct DeviceProxy<'a>(Proxy<'a>);
impl<'a> DeviceProxy<'a> {
/// Create a new instance of [`DeviceProxy`].
pub async fn new() -> Result<DeviceProxy<'a>, Error> {
let proxy = Proxy::new_desktop("org.freedesktop.portal.Device").await?;
Ok(Self(proxy))
}
/// Asks for access to a device.
///
/// # Arguments
///
/// * `pid` - The pid of the application on whose behalf the request is
/// made.
/// * `devices` - A list of devices to request access to.
///
/// *Note* Asking for multiple devices at the same time may or may not be
/// supported
///
/// # Specifications
///
/// See also [`AccessDevice`](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Device.html#org-freedesktop-portal-device-accessdevice).
#[doc(alias = "AccessDevice")]
pub async fn access_device(&self, pid: Pid, devices: &[Device]) -> Result<Request<()>, Error> {
let options = AccessDeviceOptions::default();
self.0
.empty_request(
&options.handle_token,
"AccessDevice",
&(pid, devices, &options),
)
.await
}
}
impl<'a> std::ops::Deref for DeviceProxy<'a> {
type Target = zbus::Proxy<'a>;
fn deref(&self) -> &Self::Target {
&self.0
}
}