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 pub fn close(self) {
139 match self.inner {
140 #[cfg(feature = "dbus")]
141 NotificationHandleInner::Dbus(inner) => inner.close(),
142 #[cfg(feature = "zbus")]
143 NotificationHandleInner::Zbus(inner) => block_on(inner.close()),
144 }
145 }
146
147 pub fn on_close<A>(self, handler: impl CloseHandler<A>) {
173 match self.inner {
174 #[cfg(feature = "dbus")]
175 NotificationHandleInner::Dbus(inner) => {
176 inner.wait_for_action(|action: &ActionResponse| {
177 if let ActionResponse::Closed(reason) = action {
178 handler.call(*reason);
179 }
180 });
181 }
182 #[cfg(feature = "zbus")]
183 NotificationHandleInner::Zbus(inner) => {
184 block_on(inner.wait_for_action(|action: &ActionResponse| {
185 if let ActionResponse::Closed(reason) = action {
186 handler.call(*reason);
187 }
188 }));
189 }
190 };
191 }
192
193 pub fn update(&mut self) {
214 match self.inner {
215 #[cfg(feature = "dbus")]
216 NotificationHandleInner::Dbus(ref mut inner) => inner.update(),
217 #[cfg(feature = "zbus")]
218 NotificationHandleInner::Zbus(ref mut inner) => inner.update(),
219 }
220 }
221
222 pub fn id(&self) -> u32 {
224 match self.inner {
225 #[cfg(feature = "dbus")]
226 NotificationHandleInner::Dbus(ref inner) => inner.id,
227 #[cfg(feature = "zbus")]
228 NotificationHandleInner::Zbus(ref inner) => inner.id,
229 }
230 }
231}
232
233impl Deref for NotificationHandle {
235 type Target = Notification;
236
237 fn deref(&self) -> &Notification {
238 match self.inner {
239 #[cfg(feature = "dbus")]
240 NotificationHandleInner::Dbus(ref inner) => &inner.notification,
241 #[cfg(feature = "zbus")]
242 NotificationHandleInner::Zbus(ref inner) => &inner.notification,
243 }
244 }
245}
246
247impl DerefMut for NotificationHandle {
249 fn deref_mut(&mut self) -> &mut Notification {
250 match self.inner {
251 #[cfg(feature = "dbus")]
252 NotificationHandleInner::Dbus(ref mut inner) => &mut inner.notification,
253 #[cfg(feature = "zbus")]
254 NotificationHandleInner::Zbus(ref mut inner) => &mut inner.notification,
255 }
256 }
257}
258
259#[cfg(feature = "dbus")]
260impl From<dbus_rs::DbusNotificationHandle> for NotificationHandleInner {
261 fn from(handle: dbus_rs::DbusNotificationHandle) -> NotificationHandleInner {
262 NotificationHandleInner::Dbus(handle)
263 }
264}
265
266#[cfg(feature = "zbus")]
267impl From<zbus_rs::ZbusNotificationHandle> for NotificationHandleInner {
268 fn from(handle: zbus_rs::ZbusNotificationHandle) -> NotificationHandleInner {
269 NotificationHandleInner::Zbus(handle)
270 }
271}
272
273#[cfg(feature = "dbus")]
274impl From<dbus_rs::DbusNotificationHandle> for NotificationHandle {
275 fn from(handle: dbus_rs::DbusNotificationHandle) -> NotificationHandle {
276 NotificationHandle {
277 inner: handle.into(),
278 }
279 }
280}
281
282#[cfg(feature = "zbus")]
283impl From<zbus_rs::ZbusNotificationHandle> for NotificationHandle {
284 fn from(handle: zbus_rs::ZbusNotificationHandle) -> NotificationHandle {
285 NotificationHandle {
286 inner: handle.into(),
287 }
288 }
289}
290
291#[cfg(all(
298 not(any(feature = "dbus", feature = "zbus")),
299 unix,
300 not(target_os = "macos")
301))]
302compile_error!("you have to build with either zbus or dbus turned on");
303
304#[derive(Copy, Clone, Debug)]
306pub enum DbusStack {
307 Dbus,
309 Zbus,
311}
312
313#[cfg(all(feature = "dbus", feature = "zbus"))]
314const DBUS_SWITCH_VAR: &str = "DBUSRS";
315
316#[cfg(all(feature = "zbus", not(feature = "dbus")))]
317pub(crate) fn show_notification(notification: &Notification) -> Result<NotificationHandle> {
318 block_on(zbus_rs::connect_and_send_notification(notification)).map(Into::into)
319}
320
321#[cfg(all(feature = "async", feature = "zbus"))]
322pub(crate) async fn show_notification_async(
323 notification: &Notification,
324) -> Result<NotificationHandle> {
325 zbus_rs::connect_and_send_notification(notification)
326 .await
327 .map(Into::into)
328}
329
330#[cfg(all(feature = "async", feature = "zbus"))]
331pub(crate) async fn show_notification_async_at_bus(
332 notification: &Notification,
333 bus: NotificationBus,
334) -> Result<NotificationHandle> {
335 zbus_rs::connect_and_send_notification_at_bus(notification, bus)
336 .await
337 .map(Into::into)
338}
339
340#[cfg(all(feature = "dbus", not(feature = "zbus")))]
341pub(crate) fn show_notification(notification: &Notification) -> Result<NotificationHandle> {
342 dbus_rs::connect_and_send_notification(notification).map(Into::into)
343}
344
345#[cfg(all(feature = "dbus", feature = "zbus"))]
346pub(crate) fn show_notification(notification: &Notification) -> Result<NotificationHandle> {
347 if std::env::var(DBUS_SWITCH_VAR).is_ok() {
348 dbus_rs::connect_and_send_notification(notification).map(Into::into)
349 } else {
350 block_on(zbus_rs::connect_and_send_notification(notification)).map(Into::into)
351 }
352}
353
354#[cfg(all(feature = "zbus", not(feature = "dbus")))]
358pub fn dbus_stack() -> Option<DbusStack> {
359 Some(DbusStack::Zbus)
360}
361
362#[cfg(all(feature = "dbus", not(feature = "zbus")))]
366pub fn dbus_stack() -> Option<DbusStack> {
367 Some(DbusStack::Dbus)
368}
369
370#[cfg(all(feature = "dbus", feature = "zbus"))]
374pub fn dbus_stack() -> Option<DbusStack> {
375 Some(if std::env::var(DBUS_SWITCH_VAR).is_ok() {
376 DbusStack::Dbus
377 } else {
378 DbusStack::Zbus
379 })
380}
381
382#[cfg(all(not(feature = "dbus"), not(feature = "zbus")))]
386pub fn dbus_stack() -> Option<DbusStack> {
387 None
388}
389
390#[cfg(all(feature = "zbus", not(feature = "dbus")))]
394pub fn get_capabilities() -> Result<Vec<String>> {
395 block_on(zbus_rs::get_capabilities())
396}
397
398#[cfg(all(feature = "dbus", not(feature = "zbus")))]
402pub fn get_capabilities() -> Result<Vec<String>> {
403 dbus_rs::get_capabilities()
404}
405
406#[cfg(all(feature = "dbus", feature = "zbus"))]
410pub fn get_capabilities() -> Result<Vec<String>> {
411 if std::env::var(DBUS_SWITCH_VAR).is_ok() {
412 dbus_rs::get_capabilities()
413 } else {
414 block_on(zbus_rs::get_capabilities())
415 }
416}
417
418#[cfg(all(feature = "zbus", not(feature = "dbus")))]
425pub fn get_server_information() -> Result<ServerInformation> {
426 block_on(zbus_rs::get_server_information())
427}
428
429#[cfg(all(feature = "dbus", not(feature = "zbus")))]
436pub fn get_server_information() -> Result<ServerInformation> {
437 dbus_rs::get_server_information()
438}
439
440#[cfg(all(feature = "dbus", feature = "zbus"))]
447pub fn get_server_information() -> Result<ServerInformation> {
448 if std::env::var(DBUS_SWITCH_VAR).is_ok() {
449 dbus_rs::get_server_information()
450 } else {
451 block_on(zbus_rs::get_server_information())
452 }
453}
454
455#[derive(Debug)]
457#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
458#[cfg_attr(feature = "zbus", derive(zvariant::Type))]
459pub struct ServerInformation {
460 pub name: String,
462 pub vendor: String,
464 pub version: String,
466 pub spec_version: String,
468}
469
470#[cfg(all(feature = "zbus", not(feature = "dbus")))]
485pub fn handle_action<F>(id: u32, func: F)
487where
488 F: FnOnce(&ActionResponse),
489{
490 block_on(zbus_rs::handle_action(id, func));
491}
492
493#[cfg(all(feature = "dbus", not(feature = "zbus")))]
498pub fn handle_action<F>(id: u32, func: F)
500where
501 F: FnOnce(&ActionResponse),
502{
503 dbus_rs::handle_action(id, func);
504}
505
506#[cfg(all(feature = "dbus", feature = "zbus"))]
511pub fn handle_action<F>(id: u32, func: F)
513where
514 F: FnOnce(&ActionResponse),
515{
516 if std::env::var(DBUS_SWITCH_VAR).is_ok() {
517 dbus_rs::handle_action(id, func);
518 } else {
519 block_on(zbus_rs::handle_action(id, func));
520 }
521}
522
523#[derive(Copy, Clone, Debug)]
528pub enum CloseReason {
529 Expired,
531 Dismissed,
533 CloseAction,
535 Other(u32),
537}
538
539impl From<u32> for CloseReason {
540 fn from(raw_reason: u32) -> Self {
541 match raw_reason {
542 1 => CloseReason::Expired,
543 2 => CloseReason::Dismissed,
544 3 => CloseReason::CloseAction,
545 other => CloseReason::Other(other),
546 }
547 }
548}
549
550pub trait ActionResponseHandler {
552 fn call(self, response: &ActionResponse);
553}
554
555impl<F> ActionResponseHandler for F
557where
558 F: FnOnce(&ActionResponse),
559{
560 fn call(self, res: &ActionResponse) {
561 (self)(res);
562 }
563}
564
565pub enum ActionResponse<'a> {
567 Custom(&'a str),
569
570 Closed(CloseReason),
572}
573
574impl<'a> From<&'a str> for ActionResponse<'a> {
575 fn from(raw: &'a str) -> Self {
576 Self::Custom(raw)
577 }
578}
579
580pub trait CloseHandler<T> {
585 fn call(&self, reason: CloseReason);
587}
588
589impl<F> CloseHandler<CloseReason> for F
590where
591 F: Fn(CloseReason),
592{
593 fn call(&self, reason: CloseReason) {
594 self(reason);
595 }
596}
597
598impl<F> CloseHandler<()> for F
599where
600 F: Fn(),
601{
602 fn call(&self, _: CloseReason) {
603 self();
604 }
605}