use zbus::DBusError;
use crate::desktop::{dynamic_launcher::UnexpectedIconError, request::ResponseError};
#[allow(missing_docs)]
#[derive(DBusError, Debug)]
#[zbus(prefix = "org.freedesktop.portal.Error")]
pub enum PortalError {
#[zbus(error)]
ZBus(zbus::Error),
Failed(String),
InvalidArgument(String),
NotFound(String),
Exist(String),
NotAllowed(String),
Cancelled(String),
WindowDestroyed(String),
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Response(ResponseError),
Portal(PortalError),
Zbus(zbus::Error),
NoResponse,
ParseError(&'static str),
IO(std::io::Error),
#[cfg(feature = "pipewire")]
Pipewire(pipewire::Error),
InvalidAppID,
NulTerminated(usize),
RequiresVersion(u32, u32),
PortalNotFound(zbus::names::OwnedInterfaceName),
UnexpectedIcon,
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Response(e) => f.write_str(&format!("Portal request didn't succeed: {e}")),
Self::Zbus(e) => f.write_str(&format!("ZBus Error: {e}")),
Self::Portal(e) => f.write_str(&format!("Portal request failed: {e}")),
Self::NoResponse => f.write_str("Portal error: no response"),
Self::IO(e) => f.write_str(&format!("IO: {e}")),
#[cfg(feature = "pipewire")]
Self::Pipewire(e) => f.write_str(&format!("Pipewire: {e}")),
Self::ParseError(e) => f.write_str(e),
Self::InvalidAppID => f.write_str("Invalid app id"),
Self::NulTerminated(u) => write!(f, "Nul byte found in provided data at position {u}"),
Self::RequiresVersion(required, current) => write!(
f,
"This interface requires version {required}, but {current} is available"
),
Self::PortalNotFound(portal) => {
write!(f, "A portal frontend implementing `{portal}` was not found")
}
Self::UnexpectedIcon => write!(
f,
"Expected icon of type Icon::Bytes but a different type was used."
),
}
}
}
impl From<ResponseError> for Error {
fn from(e: ResponseError) -> Self {
Self::Response(e)
}
}
impl From<PortalError> for Error {
fn from(e: PortalError) -> Self {
Self::Portal(e)
}
}
#[cfg(feature = "pipewire")]
impl From<pipewire::Error> for Error {
fn from(e: pipewire::Error) -> Self {
Self::Pipewire(e)
}
}
impl From<zbus::fdo::Error> for Error {
fn from(e: zbus::fdo::Error) -> Self {
Self::Zbus(zbus::Error::FDO(Box::new(e)))
}
}
impl From<zbus::Error> for Error {
fn from(e: zbus::Error) -> Self {
match &e {
zbus::Error::MethodError(_name, Some(details), _reply) => {
let iface = details
.trim_start_matches("No such interface")
.trim_end_matches("on object at path /org/freedesktop/portal/desktop")
.trim()
.trim_matches('`')
.trim_matches('“')
.trim_matches('”');
match zbus::names::OwnedInterfaceName::try_from(iface) {
Ok(iface) => Self::PortalNotFound(iface),
Err(_err) => {
#[cfg(feature = "tracing")]
{
tracing::warn!("Hack! The parsing of the iface name has failed: iface {iface}, error details {details}")
};
Self::Zbus(e)
}
}
}
_ => Self::Zbus(e),
}
}
}
impl From<zbus::zvariant::Error> for Error {
fn from(e: zbus::zvariant::Error) -> Self {
Self::Zbus(zbus::Error::Variant(e))
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Self::IO(e)
}
}
impl From<UnexpectedIconError> for Error {
fn from(_: UnexpectedIconError) -> Self {
Self::UnexpectedIcon
}
}