#[cfg(feature = "dbus")]
use dbus::ffidisp::Connection as DbusConnection;
#[cfg(feature = "zbus")]
use zbus::{block_on, zvariant};
use crate::{error::*, notification::Notification};
use std::ops::{Deref, DerefMut};
#[cfg(feature = "dbus")]
mod dbus_rs;
#[cfg(all(feature = "dbus", not(feature = "zbus")))]
use dbus_rs::bus;
#[cfg(feature = "zbus")]
mod zbus_rs;
#[cfg(all(feature = "zbus", not(feature = "dbus")))]
use zbus_rs::bus;
#[cfg(all(feature = "dbus", feature = "zbus"))]
mod bus;
#[cfg(not(feature = "debug_namespace"))]
#[doc(hidden)]
pub static NOTIFICATION_DEFAULT_BUS: &str = "org.freedesktop.Notifications";
#[cfg(feature = "debug_namespace")]
#[doc(hidden)]
pub static NOTIFICATION_DEFAULT_BUS: &str = "de.hoodie.Notifications";
#[doc(hidden)]
pub static NOTIFICATION_INTERFACE: &str = "org.freedesktop.Notifications";
#[doc(hidden)]
pub static NOTIFICATION_OBJECTPATH: &str = "/org/freedesktop/Notifications";
pub(crate) use bus::NotificationBus;
#[derive(Debug)]
enum NotificationHandleInner {
#[cfg(feature = "dbus")]
Dbus(dbus_rs::DbusNotificationHandle),
#[cfg(feature = "zbus")]
Zbus(zbus_rs::ZbusNotificationHandle),
}
#[derive(Debug)]
pub struct NotificationHandle {
inner: NotificationHandleInner,
}
#[allow(dead_code)]
impl NotificationHandle {
#[cfg(feature = "dbus")]
pub(crate) fn for_dbus(
id: u32,
connection: DbusConnection,
notification: Notification,
) -> NotificationHandle {
NotificationHandle {
inner: dbus_rs::DbusNotificationHandle::new(id, connection, notification).into(),
}
}
#[cfg(feature = "zbus")]
pub(crate) fn for_zbus(
id: u32,
connection: zbus::Connection,
notification: Notification,
) -> NotificationHandle {
NotificationHandle {
inner: zbus_rs::ZbusNotificationHandle::new(id, connection, notification).into(),
}
}
pub fn wait_for_action<F>(self, invocation_closure: F)
where
F: FnOnce(&str),
{
match self.inner {
#[cfg(feature = "dbus")]
NotificationHandleInner::Dbus(inner) => {
inner.wait_for_action(|action: &ActionResponse| match action {
ActionResponse::Custom(action) => invocation_closure(action),
ActionResponse::Closed(_reason) => invocation_closure("__closed"), });
}
#[cfg(feature = "zbus")]
NotificationHandleInner::Zbus(inner) => {
block_on(
inner.wait_for_action(|action: &ActionResponse| match action {
ActionResponse::Custom(action) => invocation_closure(action),
ActionResponse::Closed(_reason) => invocation_closure("__closed"), }),
);
}
};
}
pub fn close(self) {
match self.inner {
#[cfg(feature = "dbus")]
NotificationHandleInner::Dbus(inner) => inner.close(),
#[cfg(feature = "zbus")]
NotificationHandleInner::Zbus(inner) => block_on(inner.close()),
}
}
pub fn on_close<A>(self, handler: impl CloseHandler<A>) {
match self.inner {
#[cfg(feature = "dbus")]
NotificationHandleInner::Dbus(inner) => {
inner.wait_for_action(|action: &ActionResponse| {
if let ActionResponse::Closed(reason) = action {
handler.call(*reason);
}
});
}
#[cfg(feature = "zbus")]
NotificationHandleInner::Zbus(inner) => {
block_on(inner.wait_for_action(|action: &ActionResponse| {
if let ActionResponse::Closed(reason) = action {
handler.call(*reason);
}
}));
}
};
}
pub fn update(&mut self) {
match self.inner {
#[cfg(feature = "dbus")]
NotificationHandleInner::Dbus(ref mut inner) => inner.update(),
#[cfg(feature = "zbus")]
NotificationHandleInner::Zbus(ref mut inner) => inner.update(),
}
}
pub fn id(&self) -> u32 {
match self.inner {
#[cfg(feature = "dbus")]
NotificationHandleInner::Dbus(ref inner) => inner.id,
#[cfg(feature = "zbus")]
NotificationHandleInner::Zbus(ref inner) => inner.id,
}
}
}
impl Deref for NotificationHandle {
type Target = Notification;
fn deref(&self) -> &Notification {
match self.inner {
#[cfg(feature = "dbus")]
NotificationHandleInner::Dbus(ref inner) => &inner.notification,
#[cfg(feature = "zbus")]
NotificationHandleInner::Zbus(ref inner) => &inner.notification,
}
}
}
impl DerefMut for NotificationHandle {
fn deref_mut(&mut self) -> &mut Notification {
match self.inner {
#[cfg(feature = "dbus")]
NotificationHandleInner::Dbus(ref mut inner) => &mut inner.notification,
#[cfg(feature = "zbus")]
NotificationHandleInner::Zbus(ref mut inner) => &mut inner.notification,
}
}
}
#[cfg(feature = "dbus")]
impl From<dbus_rs::DbusNotificationHandle> for NotificationHandleInner {
fn from(handle: dbus_rs::DbusNotificationHandle) -> NotificationHandleInner {
NotificationHandleInner::Dbus(handle)
}
}
#[cfg(feature = "zbus")]
impl From<zbus_rs::ZbusNotificationHandle> for NotificationHandleInner {
fn from(handle: zbus_rs::ZbusNotificationHandle) -> NotificationHandleInner {
NotificationHandleInner::Zbus(handle)
}
}
#[cfg(feature = "dbus")]
impl From<dbus_rs::DbusNotificationHandle> for NotificationHandle {
fn from(handle: dbus_rs::DbusNotificationHandle) -> NotificationHandle {
NotificationHandle {
inner: handle.into(),
}
}
}
#[cfg(feature = "zbus")]
impl From<zbus_rs::ZbusNotificationHandle> for NotificationHandle {
fn from(handle: zbus_rs::ZbusNotificationHandle) -> NotificationHandle {
NotificationHandle {
inner: handle.into(),
}
}
}
#[cfg(all(
not(any(feature = "dbus", feature = "zbus")),
unix,
not(target_os = "macos")
))]
compile_error!("you have to build with either zbus or dbus turned on");
#[derive(Copy, Clone, Debug)]
pub enum DbusStack {
Dbus,
Zbus,
}
#[cfg(all(feature = "dbus", feature = "zbus"))]
const DBUS_SWITCH_VAR: &str = "DBUSRS";
#[cfg(all(feature = "zbus", not(feature = "dbus")))]
pub(crate) fn show_notification(notification: &Notification) -> Result<NotificationHandle> {
block_on(zbus_rs::connect_and_send_notification(notification)).map(Into::into)
}
#[cfg(all(feature = "async", feature = "zbus"))]
pub(crate) async fn show_notification_async(
notification: &Notification,
) -> Result<NotificationHandle> {
zbus_rs::connect_and_send_notification(notification)
.await
.map(Into::into)
}
#[cfg(all(feature = "async", feature = "zbus"))]
pub(crate) async fn show_notification_async_at_bus(
notification: &Notification,
bus: NotificationBus,
) -> Result<NotificationHandle> {
zbus_rs::connect_and_send_notification_at_bus(notification, bus)
.await
.map(Into::into)
}
#[cfg(all(feature = "dbus", not(feature = "zbus")))]
pub(crate) fn show_notification(notification: &Notification) -> Result<NotificationHandle> {
dbus_rs::connect_and_send_notification(notification).map(Into::into)
}
#[cfg(all(feature = "dbus", feature = "zbus"))]
pub(crate) fn show_notification(notification: &Notification) -> Result<NotificationHandle> {
if std::env::var(DBUS_SWITCH_VAR).is_ok() {
dbus_rs::connect_and_send_notification(notification).map(Into::into)
} else {
block_on(zbus_rs::connect_and_send_notification(notification)).map(Into::into)
}
}
#[cfg(all(feature = "zbus", not(feature = "dbus")))]
pub fn dbus_stack() -> Option<DbusStack> {
Some(DbusStack::Zbus)
}
#[cfg(all(feature = "dbus", not(feature = "zbus")))]
pub fn dbus_stack() -> Option<DbusStack> {
Some(DbusStack::Dbus)
}
#[cfg(all(feature = "dbus", feature = "zbus"))]
pub fn dbus_stack() -> Option<DbusStack> {
Some(if std::env::var(DBUS_SWITCH_VAR).is_ok() {
DbusStack::Dbus
} else {
DbusStack::Zbus
})
}
#[cfg(all(not(feature = "dbus"), not(feature = "zbus")))]
pub fn dbus_stack() -> Option<DbusStack> {
None
}
#[cfg(all(feature = "zbus", not(feature = "dbus")))]
pub fn get_capabilities() -> Result<Vec<String>> {
block_on(zbus_rs::get_capabilities())
}
#[cfg(all(feature = "dbus", not(feature = "zbus")))]
pub fn get_capabilities() -> Result<Vec<String>> {
dbus_rs::get_capabilities()
}
#[cfg(all(feature = "dbus", feature = "zbus"))]
pub fn get_capabilities() -> Result<Vec<String>> {
if std::env::var(DBUS_SWITCH_VAR).is_ok() {
dbus_rs::get_capabilities()
} else {
block_on(zbus_rs::get_capabilities())
}
}
#[cfg(all(feature = "zbus", not(feature = "dbus")))]
pub fn get_server_information() -> Result<ServerInformation> {
block_on(zbus_rs::get_server_information())
}
#[cfg(all(feature = "dbus", not(feature = "zbus")))]
pub fn get_server_information() -> Result<ServerInformation> {
dbus_rs::get_server_information()
}
#[cfg(all(feature = "dbus", feature = "zbus"))]
pub fn get_server_information() -> Result<ServerInformation> {
if std::env::var(DBUS_SWITCH_VAR).is_ok() {
dbus_rs::get_server_information()
} else {
block_on(zbus_rs::get_server_information())
}
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[cfg_attr(feature = "zbus", derive(zvariant::Type))]
pub struct ServerInformation {
pub name: String,
pub vendor: String,
pub version: String,
pub spec_version: String,
}
#[cfg(all(feature = "zbus", not(feature = "dbus")))]
pub fn handle_action<F>(id: u32, func: F)
where
F: FnOnce(&ActionResponse),
{
block_on(zbus_rs::handle_action(id, func));
}
#[cfg(all(feature = "dbus", not(feature = "zbus")))]
pub fn handle_action<F>(id: u32, func: F)
where
F: FnOnce(&ActionResponse),
{
dbus_rs::handle_action(id, func);
}
#[cfg(all(feature = "dbus", feature = "zbus"))]
pub fn handle_action<F>(id: u32, func: F)
where
F: FnOnce(&ActionResponse),
{
if std::env::var(DBUS_SWITCH_VAR).is_ok() {
dbus_rs::handle_action(id, func);
} else {
block_on(zbus_rs::handle_action(id, func));
}
}
#[derive(Copy, Clone, Debug)]
pub enum CloseReason {
Expired,
Dismissed,
CloseAction,
Other(u32),
}
impl From<u32> for CloseReason {
fn from(raw_reason: u32) -> Self {
match raw_reason {
1 => CloseReason::Expired,
2 => CloseReason::Dismissed,
3 => CloseReason::CloseAction,
other => CloseReason::Other(other),
}
}
}
pub trait ActionResponseHandler {
fn call(self, response: &ActionResponse);
}
impl<F> ActionResponseHandler for F
where
F: FnOnce(&ActionResponse),
{
fn call(self, res: &ActionResponse) {
(self)(res);
}
}
pub enum ActionResponse<'a> {
Custom(&'a str),
Closed(CloseReason),
}
impl<'a> From<&'a str> for ActionResponse<'a> {
fn from(raw: &'a str) -> Self {
Self::Custom(raw)
}
}
pub trait CloseHandler<T> {
fn call(&self, reason: CloseReason);
}
impl<F> CloseHandler<CloseReason> for F
where
F: Fn(CloseReason),
{
fn call(&self, reason: CloseReason) {
self(reason);
}
}
impl<F> CloseHandler<()> for F
where
F: Fn(),
{
fn call(&self, _: CloseReason) {
self();
}
}