1#[cfg(feature = "dbus")]
6use dbus::ffidisp::Connection as DbusConnection;
7#[cfg(feature = "zbus")]
8use zbus::{block_on, zvariant};
9
10use crate::{error::*, notification::Notification};
11
12use std::ops::{Deref, DerefMut};
13
14#[cfg(feature = "dbus")]
15mod dbus_rs;
16#[cfg(all(feature = "dbus", not(feature = "zbus")))]
17use dbus_rs::bus;
18
19#[cfg(feature = "zbus")]
20mod zbus_rs;
21#[cfg(all(feature = "zbus", not(feature = "dbus")))]
22use zbus_rs::bus;
23
24#[cfg(all(feature = "dbus", feature = "zbus"))]
25mod bus;
26
27#[cfg(not(feature = "debug_namespace"))]
37#[doc(hidden)]
38pub static NOTIFICATION_DEFAULT_BUS: &str = "org.freedesktop.Notifications";
39
40#[cfg(feature = "debug_namespace")]
41#[doc(hidden)]
42pub static NOTIFICATION_DEFAULT_BUS: &str = "de.hoodie.Notifications";
44
45#[doc(hidden)]
46pub static NOTIFICATION_INTERFACE: &str = "org.freedesktop.Notifications";
47
48#[doc(hidden)]
49pub static NOTIFICATION_OBJECTPATH: &str = "/org/freedesktop/Notifications";
50
51pub(crate) use bus::NotificationBus;
52
53#[derive(Debug)]
54enum NotificationHandleInner {
55 #[cfg(feature = "dbus")]
56 Dbus(dbus_rs::DbusNotificationHandle),
57
58 #[cfg(feature = "zbus")]
59 Zbus(zbus_rs::ZbusNotificationHandle),
60}
61
62#[derive(Debug)]
66pub struct NotificationHandle {
67 inner: NotificationHandleInner,
68}
69
70#[allow(dead_code)]
71impl NotificationHandle {
72 #[cfg(feature = "dbus")]
73 pub(crate) fn for_dbus(
74 id: u32,
75 connection: DbusConnection,
76 notification: Notification,
77 ) -> NotificationHandle {
78 NotificationHandle {
79 inner: dbus_rs::DbusNotificationHandle::new(id, connection, notification).into(),
80 }
81 }
82
83 #[cfg(feature = "zbus")]
84 pub(crate) fn for_zbus(
85 id: u32,
86 connection: zbus::Connection,
87 notification: Notification,
88 ) -> NotificationHandle {
89 NotificationHandle {
90 inner: zbus_rs::ZbusNotificationHandle::new(id, connection, notification).into(),
91 }
92 }
93
94 pub fn wait_for_action<F>(self, invocation_closure: F)
97 where
98 F: FnOnce(&str),
99 {
100 match self.inner {
101 #[cfg(feature = "dbus")]
102 NotificationHandleInner::Dbus(inner) => {
103 inner.wait_for_action(|action: &ActionResponse| match action {
104 ActionResponse::Custom(action) => invocation_closure(action),
105 ActionResponse::Closed(_reason) => invocation_closure("__closed"), });
107 }
108
109 #[cfg(feature = "zbus")]
110 NotificationHandleInner::Zbus(inner) => {
111 block_on(
112 inner.wait_for_action(|action: &ActionResponse| match action {
113 ActionResponse::Custom(action) => invocation_closure(action),
114 ActionResponse::Closed(_reason) => invocation_closure("__closed"), }),
116 );
117 }
118 };
119 }
120
121 #[cfg(feature = "zbus")]
157 pub async fn wait_for_action_async<F>(&self, invocation_closure: F)
158 where
159 F: FnOnce(&ActionResponse),
160 {
161 match &self.inner {
162 #[cfg(feature = "dbus")]
163 NotificationHandleInner::Dbus(_) => {
164 unimplemented!("async methods are not supported with the `dbus` backend");
165 }
166 #[cfg(feature = "zbus")]
167 NotificationHandleInner::Zbus(inner) => inner.wait_for_action(invocation_closure).await,
168 }
169 }
170
171 pub fn close(self) {
189 match self.inner {
190 #[cfg(feature = "dbus")]
191 NotificationHandleInner::Dbus(inner) => inner.close(),
192 #[cfg(feature = "zbus")]
193 NotificationHandleInner::Zbus(inner) => block_on(inner.close()),
194 }
195 }
196
197 #[cfg(feature = "zbus")]
203 pub async fn close_async(&self) {
204 match &self.inner {
205 #[cfg(feature = "dbus")]
206 NotificationHandleInner::Dbus(_) => {
207 unimplemented!("async methods are not supported with the `dbus` backend");
208 }
209 #[cfg(feature = "zbus")]
210 NotificationHandleInner::Zbus(inner) => inner.close().await,
211 }
212 }
213
214 pub fn on_close<A>(self, handler: impl CloseHandler<A>) {
240 match self.inner {
241 #[cfg(feature = "dbus")]
242 NotificationHandleInner::Dbus(inner) => {
243 inner.wait_for_action(|action: &ActionResponse| {
244 if let ActionResponse::Closed(reason) = action {
245 handler.call(*reason);
246 }
247 });
248 }
249 #[cfg(feature = "zbus")]
250 NotificationHandleInner::Zbus(inner) => {
251 block_on(inner.wait_for_action(|action: &ActionResponse| {
252 if let ActionResponse::Closed(reason) = action {
253 handler.call(*reason);
254 }
255 }));
256 }
257 };
258 }
259
260 pub fn update(&mut self) {
281 match self.inner {
282 #[cfg(feature = "dbus")]
283 NotificationHandleInner::Dbus(ref mut inner) => inner.update(),
284 #[cfg(feature = "zbus")]
285 NotificationHandleInner::Zbus(ref mut inner) => inner.update(),
286 }
287 }
288
289 pub fn id(&self) -> u32 {
291 match self.inner {
292 #[cfg(feature = "dbus")]
293 NotificationHandleInner::Dbus(ref inner) => inner.id,
294 #[cfg(feature = "zbus")]
295 NotificationHandleInner::Zbus(ref inner) => inner.id,
296 }
297 }
298}
299
300impl Deref for NotificationHandle {
302 type Target = Notification;
303
304 fn deref(&self) -> &Notification {
305 match self.inner {
306 #[cfg(feature = "dbus")]
307 NotificationHandleInner::Dbus(ref inner) => &inner.notification,
308 #[cfg(feature = "zbus")]
309 NotificationHandleInner::Zbus(ref inner) => &inner.notification,
310 }
311 }
312}
313
314impl DerefMut for NotificationHandle {
316 fn deref_mut(&mut self) -> &mut Notification {
317 match self.inner {
318 #[cfg(feature = "dbus")]
319 NotificationHandleInner::Dbus(ref mut inner) => &mut inner.notification,
320 #[cfg(feature = "zbus")]
321 NotificationHandleInner::Zbus(ref mut inner) => &mut inner.notification,
322 }
323 }
324}
325
326#[cfg(feature = "dbus")]
327impl From<dbus_rs::DbusNotificationHandle> for NotificationHandleInner {
328 fn from(handle: dbus_rs::DbusNotificationHandle) -> NotificationHandleInner {
329 NotificationHandleInner::Dbus(handle)
330 }
331}
332
333#[cfg(feature = "zbus")]
334impl From<zbus_rs::ZbusNotificationHandle> for NotificationHandleInner {
335 fn from(handle: zbus_rs::ZbusNotificationHandle) -> NotificationHandleInner {
336 NotificationHandleInner::Zbus(handle)
337 }
338}
339
340#[cfg(feature = "dbus")]
341impl From<dbus_rs::DbusNotificationHandle> for NotificationHandle {
342 fn from(handle: dbus_rs::DbusNotificationHandle) -> NotificationHandle {
343 NotificationHandle {
344 inner: handle.into(),
345 }
346 }
347}
348
349#[cfg(feature = "zbus")]
350impl From<zbus_rs::ZbusNotificationHandle> for NotificationHandle {
351 fn from(handle: zbus_rs::ZbusNotificationHandle) -> NotificationHandle {
352 NotificationHandle {
353 inner: handle.into(),
354 }
355 }
356}
357
358#[cfg(all(
365 not(any(feature = "dbus", feature = "zbus")),
366 unix,
367 not(target_os = "macos")
368))]
369compile_error!("you have to build with either zbus or dbus turned on");
370
371#[derive(Copy, Clone, Debug)]
373pub enum DbusStack {
374 Dbus,
376 Zbus,
378}
379
380#[cfg(all(feature = "dbus", feature = "zbus"))]
381const DBUS_SWITCH_VAR: &str = "DBUSRS";
382
383#[cfg(all(feature = "zbus", not(feature = "dbus")))]
384pub(crate) fn show_notification(notification: &Notification) -> Result<NotificationHandle> {
385 block_on(zbus_rs::connect_and_send_notification(notification)).map(Into::into)
386}
387
388#[cfg(feature = "zbus")]
389pub(crate) async fn show_notification_async(
390 notification: &Notification,
391) -> Result<NotificationHandle> {
392 zbus_rs::connect_and_send_notification(notification)
393 .await
394 .map(Into::into)
395}
396
397#[cfg(feature = "zbus")]
398pub(crate) async fn show_notification_async_at_bus(
399 notification: &Notification,
400 bus: NotificationBus,
401) -> Result<NotificationHandle> {
402 zbus_rs::connect_and_send_notification_at_bus(notification, bus)
403 .await
404 .map(Into::into)
405}
406
407#[cfg(all(feature = "dbus", not(feature = "zbus")))]
408pub(crate) fn show_notification(notification: &Notification) -> Result<NotificationHandle> {
409 dbus_rs::connect_and_send_notification(notification).map(Into::into)
410}
411
412#[cfg(all(feature = "dbus", feature = "zbus"))]
413pub(crate) fn show_notification(notification: &Notification) -> Result<NotificationHandle> {
414 if std::env::var(DBUS_SWITCH_VAR).is_ok() {
415 dbus_rs::connect_and_send_notification(notification).map(Into::into)
416 } else {
417 block_on(zbus_rs::connect_and_send_notification(notification)).map(Into::into)
418 }
419}
420
421#[cfg(all(feature = "zbus", not(feature = "dbus")))]
425pub fn dbus_stack() -> Option<DbusStack> {
426 Some(DbusStack::Zbus)
427}
428
429#[cfg(all(feature = "dbus", not(feature = "zbus")))]
433pub fn dbus_stack() -> Option<DbusStack> {
434 Some(DbusStack::Dbus)
435}
436
437#[cfg(all(feature = "dbus", feature = "zbus"))]
441pub fn dbus_stack() -> Option<DbusStack> {
442 Some(if std::env::var(DBUS_SWITCH_VAR).is_ok() {
443 DbusStack::Dbus
444 } else {
445 DbusStack::Zbus
446 })
447}
448
449#[cfg(all(not(feature = "dbus"), not(feature = "zbus")))]
453pub fn dbus_stack() -> Option<DbusStack> {
454 None
455}
456
457#[cfg(all(feature = "zbus", not(feature = "dbus")))]
461pub fn get_capabilities() -> Result<Vec<String>> {
462 block_on(zbus_rs::get_capabilities())
463}
464
465#[cfg(all(feature = "dbus", not(feature = "zbus")))]
469pub fn get_capabilities() -> Result<Vec<String>> {
470 dbus_rs::get_capabilities()
471}
472
473#[cfg(all(feature = "dbus", feature = "zbus"))]
477pub fn get_capabilities() -> Result<Vec<String>> {
478 if std::env::var(DBUS_SWITCH_VAR).is_ok() {
479 dbus_rs::get_capabilities()
480 } else {
481 block_on(zbus_rs::get_capabilities())
482 }
483}
484
485#[cfg(all(feature = "zbus", not(feature = "dbus")))]
492pub fn get_server_information() -> Result<ServerInformation> {
493 block_on(zbus_rs::get_server_information())
494}
495
496#[cfg(all(feature = "dbus", not(feature = "zbus")))]
503pub fn get_server_information() -> Result<ServerInformation> {
504 dbus_rs::get_server_information()
505}
506
507#[cfg(all(feature = "dbus", feature = "zbus"))]
514pub fn get_server_information() -> Result<ServerInformation> {
515 if std::env::var(DBUS_SWITCH_VAR).is_ok() {
516 dbus_rs::get_server_information()
517 } else {
518 block_on(zbus_rs::get_server_information())
519 }
520}
521
522#[derive(Debug)]
524#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
525#[cfg_attr(feature = "zbus", derive(zvariant::Type))]
526pub struct ServerInformation {
527 pub name: String,
529 pub vendor: String,
531 pub version: String,
533 pub spec_version: String,
535}
536
537#[cfg(all(feature = "zbus", not(feature = "dbus")))]
552pub fn handle_action<F>(id: u32, func: F)
554where
555 F: FnOnce(&ActionResponse),
556{
557 block_on(zbus_rs::handle_action(id, func));
558}
559
560#[cfg(all(feature = "dbus", not(feature = "zbus")))]
565pub fn handle_action<F>(id: u32, func: F)
567where
568 F: FnOnce(&ActionResponse),
569{
570 dbus_rs::handle_action(id, func);
571}
572
573#[cfg(all(feature = "dbus", feature = "zbus"))]
578pub fn handle_action<F>(id: u32, func: F)
580where
581 F: FnOnce(&ActionResponse),
582{
583 if std::env::var(DBUS_SWITCH_VAR).is_ok() {
584 dbus_rs::handle_action(id, func);
585 } else {
586 block_on(zbus_rs::handle_action(id, func));
587 }
588}
589
590#[derive(Copy, Clone, Debug)]
595pub enum CloseReason {
596 Expired,
598 Dismissed,
600 CloseAction,
602 Other(u32),
604}
605
606impl From<u32> for CloseReason {
607 fn from(raw_reason: u32) -> Self {
608 match raw_reason {
609 1 => CloseReason::Expired,
610 2 => CloseReason::Dismissed,
611 3 => CloseReason::CloseAction,
612 other => CloseReason::Other(other),
613 }
614 }
615}
616
617pub trait ActionResponseHandler {
619 fn call(self, response: &ActionResponse);
620}
621
622impl<F> ActionResponseHandler for F
624where
625 F: FnOnce(&ActionResponse),
626{
627 fn call(self, res: &ActionResponse) {
628 (self)(res);
629 }
630}
631
632#[derive(Clone, Debug)]
634pub enum ActionResponse<'a> {
635 Custom(&'a str),
637
638 Closed(CloseReason),
640}
641
642impl<'a> From<&'a str> for ActionResponse<'a> {
643 fn from(raw: &'a str) -> Self {
644 Self::Custom(raw)
645 }
646}
647
648pub trait CloseHandler<T> {
653 fn call(&self, reason: CloseReason);
655}
656
657impl<F> CloseHandler<CloseReason> for F
658where
659 F: Fn(CloseReason),
660{
661 fn call(&self, reason: CloseReason) {
662 self(reason);
663 }
664}
665
666impl<F> CloseHandler<()> for F
667where
668 F: Fn(),
669{
670 fn call(&self, _: CloseReason) {
671 self();
672 }
673}