use enumflags2::{BitFlags, bitflags};
use futures_util::Stream;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use zbus::zvariant::{
ObjectPath, Optional, OwnedObjectPath, Type,
as_value::{self, optional},
};
use super::{HandleToken, Request, Session, session::SessionPortal};
use crate::{Error, WindowIdentifier, desktop::session::CreateSessionResponse, proxy::Proxy};
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct CreateMonitorOptions {
#[serde(with = "as_value")]
handle_token: HandleToken,
#[serde(with = "as_value")]
session_handle_token: HandleToken,
}
#[derive(Serialize, Type, Debug, Default)]
#[zvariant(signature = "dict")]
pub struct InhibitOptions {
#[serde(with = "as_value")]
handle_token: HandleToken,
#[serde(with = "optional", skip_serializing_if = "Option::is_none")]
reason: Option<String>,
}
impl InhibitOptions {
#[must_use]
pub fn set_reason<'a>(mut self, reason: impl Into<Option<&'a str>>) -> Self {
self.reason = reason.into().map(ToOwned::to_owned);
self
}
}
#[bitflags]
#[derive(Serialize_repr, PartialEq, Eq, Debug, Clone, Copy, Type)]
#[repr(u32)]
#[doc(alias = "XdpInhibitFlags")]
pub enum InhibitFlags {
#[doc(alias = "XDP_INHIBIT_FLAG_LOGOUT")]
Logout,
#[doc(alias = "XDP_INHIBIT_FLAG_USER_SWITCH")]
UserSwitch,
#[doc(alias = "XDP_INHIBIT_FLAG_SUSPEND")]
Suspend,
#[doc(alias = "XDP_INHIBIT_FLAG_IDLE")]
Idle,
}
#[derive(Debug, Deserialize, Type)]
#[zvariant(signature = "dict")]
#[serde(rename_all = "kebab-case")]
struct State {
#[serde(with = "as_value")]
screensaver_active: bool,
#[serde(with = "as_value")]
session_state: SessionState,
}
#[derive(Debug, Deserialize, Type)]
pub struct InhibitState(OwnedObjectPath, State);
impl InhibitState {
pub fn session_handle(&self) -> ObjectPath<'_> {
self.0.as_ref()
}
pub fn screensaver_active(&self) -> bool {
self.1.screensaver_active
}
pub fn session_state(&self) -> SessionState {
self.1.session_state
}
}
#[cfg_attr(feature = "glib", derive(glib::Enum))]
#[cfg_attr(feature = "glib", enum_type(name = "AshpdSessionState"))]
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Eq, Debug, Clone, Copy, Type)]
#[doc(alias = "XdpLoginSessionState")]
#[repr(u32)]
pub enum SessionState {
#[doc(alias = "XDP_LOGIN_SESSION_RUNNING")]
Running = 1,
#[doc(alias = "XDP_LOGIN_SESSION_QUERY_END")]
QueryEnd = 2,
#[doc(alias = "XDP_LOGIN_SESSION_ENDING")]
Ending = 3,
}
#[derive(Debug)]
#[doc(alias = "org.freedesktop.portal.Inhibit")]
pub struct InhibitProxy(Proxy<'static>);
impl InhibitProxy {
pub async fn new() -> Result<Self, Error> {
let proxy = Proxy::new_desktop("org.freedesktop.portal.Inhibit").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.Inhibit")
.await?;
Ok(Self(proxy))
}
pub fn version(&self) -> u32 {
self.0.version()
}
#[doc(alias = "CreateMonitor")]
#[doc(alias = "xdp_portal_session_monitor_start")]
pub async fn create_monitor(
&self,
identifier: Option<&WindowIdentifier>,
options: CreateMonitorOptions,
) -> Result<Session<Self>, Error> {
let identifier = Optional::from(identifier);
let body = &(identifier, &options);
let (monitor, proxy) = futures_util::try_join!(
self.0
.request::<CreateSessionResponse>(&options.handle_token, "CreateMonitor", body),
Session::from_unique_name(self.0.connection().clone(), &options.session_handle_token),
)?;
assert_eq!(proxy.path(), &monitor.response()?.session_handle.as_ref());
Ok(proxy)
}
#[doc(alias = "Inhibit")]
#[doc(alias = "xdp_portal_session_inhibit")]
pub async fn inhibit(
&self,
identifier: Option<&WindowIdentifier>,
flags: BitFlags<InhibitFlags>,
options: InhibitOptions,
) -> Result<Request<()>, Error> {
let identifier = Optional::from(identifier);
self.0
.empty_request(
&options.handle_token,
"Inhibit",
&(identifier, flags, &options),
)
.await
}
#[doc(alias = "StateChanged")]
#[doc(alias = "XdpPortal::session-state-changed")]
pub async fn receive_state_changed(
&self,
) -> Result<impl Stream<Item = InhibitState> + use<>, Error> {
self.0.signal("StateChanged").await
}
#[doc(alias = "QueryEndResponse")]
#[doc(alias = "xdp_portal_session_monitor_query_end_response")]
pub async fn query_end_response(&self, session: &Session<Self>) -> Result<(), Error> {
self.0.call("QueryEndResponse", &(session)).await
}
}
impl std::ops::Deref for InhibitProxy {
type Target = zbus::Proxy<'static>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl crate::Sealed for InhibitProxy {}
impl SessionPortal for InhibitProxy {}