diff --git a/src/main.rs b/src/main.rs
index 0f275970..dbde99d2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,6 +3,7 @@ use gtk4::{gdk, glib, prelude::*};
mod deref_cell;
mod mpris;
mod mpris_player;
+mod notifications;
mod status_area;
mod status_menu;
mod status_notifier_watcher;
@@ -39,6 +40,7 @@ fn main() {
});
status_notifier_watcher::start();
+ let _notificiations = notifications::Notifications::new();
glib::MainLoop::new(None, false).run();
}
diff --git a/src/notifications.rs b/src/notifications.rs
new file mode 100644
index 00000000..10e7c87d
--- /dev/null
+++ b/src/notifications.rs
@@ -0,0 +1,166 @@
+use gtk4::{
+ gio,
+ glib::{self, clone},
+ prelude::*,
+};
+use std::{
+ collections::HashMap,
+ num::NonZeroU32,
+ sync::{Arc, Mutex},
+};
+
+static NOTIFICATIONS_XML: &str = "
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+";
+
+pub struct Notifications {
+ next_id: Mutex,
+}
+
+impl Notifications {
+ pub fn new() -> Arc {
+ let notifications = Arc::new(Notifications {
+ next_id: Mutex::new(NonZeroU32::new(1).unwrap()),
+ });
+
+ gio::bus_own_name(
+ gio::BusType::Session,
+ "org.freedesktop.Notifications",
+ gio::BusNameOwnerFlags::NONE,
+ clone!(@strong notifications => move |connection, name| notifications.bus_acquired(connection, name)),
+ clone!(@strong notifications => move |connection, name| notifications.name_acquired(connection, name)),
+ clone!(@strong notifications => move |connection, name| notifications.name_lost(connection, name)),
+ );
+
+ notifications
+ }
+
+ fn notify(
+ &self,
+ _app_name: String,
+ replaces_id: Option,
+ _app_icon: String,
+ _summary: String,
+ _body: String,
+ _actions: Vec,
+ _hints: HashMap,
+ _expire_timeout: i32,
+ ) -> NonZeroU32 {
+ let id = replaces_id.unwrap_or_else(|| {
+ let mut next_id = self.next_id.lock().unwrap();
+ let id = *next_id;
+ *next_id = NonZeroU32::new(u32::from(*next_id).wrapping_add(1))
+ .unwrap_or(NonZeroU32::new(1).unwrap());
+ id
+ });
+
+ // TODO
+
+ id
+ }
+
+ fn close_notification(&self, _id: u32) {}
+
+ fn bus_acquired(self: &Arc, _connection: gio::DBusConnection, _name: &str) {}
+
+ fn name_acquired(self: &Arc, connection: gio::DBusConnection, _name: &str) {
+ let introspection_data = gio::DBusNodeInfo::for_xml(NOTIFICATIONS_XML).unwrap();
+ let interface_info = introspection_data
+ .lookup_interface("org.freedesktop.Notifications")
+ .unwrap();
+ let method_call = clone!(@strong self as self_ => move |_connection: gio::DBusConnection,
+ _sender: &str,
+ _path: &str,
+ _interface: &str,
+ method: &str,
+ args: glib::Variant,
+ invocation: gio::DBusMethodInvocation| {
+ match method {
+ "Notify" => {
+ let (app_name, replaces_id, app_icon, summary, body, actions, hints, expire_timeout) = args.get().unwrap();
+ let replaces_id = NonZeroU32::new(replaces_id);
+ let res = self_.notify(app_name, replaces_id, app_icon, summary, body, actions, hints, expire_timeout);
+ invocation.return_value(Some(&(u32::from(res),).to_variant()));
+ // TODO error?
+ }
+ "CloseNotification" => {
+ let (id,) = args.get::<(u32,)>().unwrap();
+ self_.close_notification(id);
+ invocation.return_value(None);
+ // TODO error?
+ }
+ "GetCapabilities" => {
+ // TODO: body-markup, sound
+ let capabilities = vec!["actions", "body", "icon-static", "persistence"];
+ invocation.return_value(Some(&(capabilities,).to_variant()));
+ }
+ "GetServerInformation" => {
+ let information = ("cosmic-panel", "system76", env!("CARGO_PKG_VERSION"), "1.2");
+ invocation.return_value(Some(&information.to_variant()));
+ }
+ _ => unreachable!()
+ }
+ });
+ let get_property = |_: gio::DBusConnection,
+ _sender: &str,
+ _path: &str,
+ _interface: &str,
+ _prop: &str| { unreachable!() };
+ let set_property = |_: gio::DBusConnection,
+ _sender: &str,
+ _path: &str,
+ _interface: &str,
+ _prop: &str,
+ _value: glib::Variant| { unreachable!() };
+ if let Err(err) = connection.register_object(
+ "/org/freedesktop/Notifications",
+ &interface_info,
+ method_call,
+ get_property,
+ set_property,
+ ) {
+ eprintln!("Failed to register object: {}", err);
+ }
+ }
+
+ fn name_lost(self: &Arc, _connection: Option, _name: &str) {}
+}
diff --git a/src/status_notifier_watcher.rs b/src/status_notifier_watcher.rs
index 46fc9ef6..54dee592 100644
--- a/src/status_notifier_watcher.rs
+++ b/src/status_notifier_watcher.rs
@@ -102,4 +102,5 @@ fn name_acquired(connection: gio::DBusConnection, _name: &str) {
eprintln!("Failed to register object: {}", err);
}
}
+
fn name_lost(_connection: Option, _name: &str) {}