diff --git a/Cargo.toml b/Cargo.toml index 8ca42fc..fe26c3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" authors = ["candifloss "] [dependencies] -dbus = "0.9.7" +zbus = "4.4.0" # rson_rs = "0.2.1" diff --git a/src/main.rs b/src/main.rs index a095e58..a87009a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,143 +1,29 @@ -use dbus::arg::{RefArg, Variant}; -use dbus::blocking::Connection; -use dbus::message::MatchRule; -use dbus::strings::Interface; -use dbus::MessageType::Signal; -use dbus::{Message, Path}; -use std::collections::HashMap; -use std::fmt; -use std::time::Duration; +use zbus::blocking::Connection; +use zbus::fdo::Result; +use zbus::Message; +use zbus::MatchRule; -// Structure of a notification -struct Notif { - app_name: String, - replace_id: Option, - ico: String, - summary: String, - body: String, - actions: Vec<(String, String)>, - hints: HashMap, - expir_timeout: Option, -} +fn main() -> Result<()> { + // Establish a connection to the session bus + let connection = Connection::session()?; -// Function to print the contents of the notification -impl fmt::Display for Notif { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "AppName: {}", &self.app_name)?; - match self.replace_id { - Some(notif_id) => writeln!(f, "ReplaceId: {notif_id}")?, - None => writeln!(f, "None")?, - } - write!( - f, - "Icon: {}\nSummary: {}\nBody: {}\nActions:\n", - &self.ico, &self.summary, &self.body - )?; - for (key, label) in &self.actions { - writeln!(f, "\t{key}: {label}")?; - } - writeln!(f, "Hints:")?; - for (key, value) in &self.hints { - writeln!(f, "\t{key}: {value}")?; - } - match self.expir_timeout { - Some(millisec) => writeln!(f, "Expiration Timeout: {millisec}")?, - None => writeln!(f, "None")?, - } - Ok(()) // Return Ok to indicate success - } -} - -// Summary should be generally <= 40 chars, as per the specification. -fn truncate_summary(notif: &mut Notif) { - if notif.summary.len() > 40 { - notif.summary.truncate(39); - notif.summary.push('…'); - } -} - -// Callback function -fn handle_notif(signal: &dbus::Message) -> Result<(), dbus::Error> { - // Extract all items as variants - let items = signal.get_items(); - - // Helper functions to safely extract data - let get_string = |item: &dyn RefArg| item.as_str().unwrap_or_default().to_string(); - let get_u32 = |item: &dyn RefArg| item.as_u64().unwrap_or_default() as u32; - let get_i32 = |item: &dyn RefArg| item.as_i64().unwrap_or_default() as i32; - - // Extract the fields from the message - let app_name = get_string(&items[0]); - let replace_id = get_u32(&items[1]); - let ico = get_string(&items[2]); - let summary = get_string(&items[3]); - let body = get_string(&items[4]); - - // Extract actions as Vec - let actions = items[5].as_array().unwrap_or(&[]).iter() - .filter_map(|v| v.as_str().map(|s| s.to_string())) - .collect(); - - // Extract hints as HashMap - let hints = items[6].as_dict().unwrap_or(&[]).iter() - .map(|(k, v)| (get_string(k), get_string(v))) - .collect(); - - let expir_timeout = get_i32(&items[7]); - - // Convert actions from Vec to Vec<(String, String)> - let notif_actions = actions.chunks(2) - .map(|chunk| if chunk.len() == 2 { (chunk[0].clone(), chunk[1].clone()) } else { (chunk[0].clone(), "".to_string()) }) - .collect(); - - let mut notif = Notif { - app_name, - replace_id: Some(replace_id), - ico, - summary, - body, - actions: notif_actions, - hints: notif_hints, - expir_timeout: if expir_timeout >= 0 { - Some(expir_timeout as u32) - } else { - None - }, - }; - - truncate_summary(&mut notif); - - println!("{}", notif); - - Ok(()) -} - -fn main() -> Result<(), dbus::Error> { - // Connect to the system bus - let conn = Connection::new_session()?; - - // Get the object path of the notification service - //let object_path = "/org/freedesktop/Notifications"; - //let member = "Notify"; - - // Get the interface name of the notification service - //let interface_name = "org.freedesktop.Notifications".to_string(); - - // Create a match rule to listen for the notifications - let match_rule = MatchRule::new_signal("org.freedesktop.Notifications".into(), "Notify".into()); + // Define a match rule for the notifications + let match_rule = MatchRule::builder() + .msg_type(zbus::MessageType::Signal) + .interface("org.freedesktop.Notifications")? + .path("/org/freedesktop/Notifications")? + .build(); // Add the match rule to the connection - conn.add_match(match_rule, |msg, _conn, _| { - if let Err(e) = handle_notif(&msg) { - eprintln!("Error handling notification: {:?}", e); - } - true // Returning true keeps the callback active - })?; + connection.add_match(match_rule)?; - // Wait for signals + // Process notifications loop { - conn.process(Duration::from_millis(1000))?; + let message = connection.receive_message()?; + if let Some(member) = message.member() { + if member.as_str() == "Notify" { + println!("Received a notification: {:?}", message); + } + } } - - Ok(()) } diff --git a/src/unused.txt b/src/unused.txt index 3ab0c27..71a8f3b 100644 --- a/src/unused.txt +++ b/src/unused.txt @@ -79,4 +79,54 @@ fn handle_notification_added(message: Message) { match_rule.path_is_namespace = false; match_rule.interface = Some(Interface::from(interface_name)); match_rule.eavesdrop = true; - conn.add_match( match_rule, handle_notif)?; */ \ No newline at end of file + conn.add_match( match_rule, handle_notif)?; */ + + + +// Structure of a notification +struct Notif { + app_name: String, + replace_id: Option, + ico: String, + summary: String, + body: String, + actions: Vec<(String, String)>, + hints: HashMap, + expir_timeout: Option, +} + +// Function to print the contents of the notification +impl fmt::Display for Notif { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "AppName: {}", &self.app_name)?; + match self.replace_id { + Some(notif_id) => writeln!(f, "ReplaceId: {notif_id}")?, + None => writeln!(f, "None")?, + } + write!( + f, + "Icon: {}\nSummary: {}\nBody: {}\nActions:\n", + &self.ico, &self.summary, &self.body + )?; + for (key, label) in &self.actions { + writeln!(f, "\t{key}: {label}")?; + } + writeln!(f, "Hints:")?; + for (key, value) in &self.hints { + writeln!(f, "\t{key}: {value}")?; + } + match self.expir_timeout { + Some(millisec) => writeln!(f, "Expiration Timeout: {millisec}")?, + None => writeln!(f, "None")?, + } + Ok(()) // Return Ok to indicate success + } +} + +// Summary should be generally <= 40 chars, as per the specification. +fn truncate_summary(notif: &mut Notif) { + if notif.summary.len() > 40 { + notif.summary.truncate(39); + notif.summary.push('…'); + } +} \ No newline at end of file