diff --git a/Cargo.toml b/Cargo.toml index 2d07319..8ca42fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" authors = ["candifloss "] [dependencies] -dbus = "0.9.77" -rson_rs = "0.2.1" +dbus = "0.9.7" +# rson_rs = "0.2.1" diff --git a/src/main.rs b/src/main.rs index 468fe88..a095e58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,12 @@ +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 dbus::blocking::{Connection, Message, MessageType, Sender}; -use dbus::message::{MatchRule, MessageType::MethodCall}; -use dbus::prelude::*; +use std::time::Duration; // Structure of a notification struct Notif { @@ -16,7 +20,6 @@ struct Notif { 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 { @@ -54,78 +57,87 @@ fn truncate_summary(notif: &mut Notif) { } // Callback function -fn handle_notification_added(message: Message) { - if message.get_type() == MessageType::Signal { - let signal_name = message.get_signature().unwrap(); +fn handle_notif(signal: &dbus::Message) -> Result<(), dbus::Error> { + // Extract all items as variants + let items = signal.get_items(); - if signal_name == "notification_added" { - let (id, app_name, icon, summary, body, actions, hints, timeout) = - message.get_arguments::<(u32, String, String, String, String, Vec, HashMap, i32)>().unwrap(); + // 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; - let notif = Notif { - app_name, - replace_id: Some(id), // Assuming you want to use the ID for replacement - ico: icon, - summary, - body, - actions: actions.iter().map(|(key, value)| (key.clone(), value.clone())).collect(), - hints: hints.iter().map(|(key, value)| (key.clone(), value.to_string())).collect(), - expir_timeout: if timeout < 0 { None } else { Some(timeout as u32) }, - }; + // 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]); - // Print or process the notification object - println!("{notification}"); - } - } + // 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> { - /* - // Example notif - let mut not = Notif { - app_name: "snot".to_string(), - replace_id: Some(0), - ico: "alert.png".to_string(), - summary: "This is a very long suuummmaaarrryyy! Don't you believe me????".to_string(), - body: "short body(hehe)".to_string(), - actions: vec![ - ("reply".to_string(), "Reply".to_string()), - ("close".to_string(), "Close".to_string()), - ], - hints: HashMap::new(), // Create an empty HashMap for hints, add the hints later - expir_timeout: Some(0), - }; - not.hints - .insert("urgency".to_string(), "critical".to_string()); - not.hints - .insert("category".to_string(), "network.error".to_string()); - // End of eg. notif - truncate_summary(&mut not); //Limit the summary length - */ - // 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 object_path = "/org/freedesktop/Notifications"; + //let member = "Notify"; // Get the interface name of the notification service - let interface_name = "org.freedesktop.Notifications"; + //let interface_name = "org.freedesktop.Notifications".to_string(); - // Subscribe to the "handle_notification_added" signal - let match_rule = MatchRule::new_for_signal(object_path, interface_name, "handle_notification_added"); - conn.add_match(match_rule)?; + // Create a match rule to listen for the notifications + let match_rule = MatchRule::new_signal("org.freedesktop.Notifications".into(), "Notify".into()); - // Create a sender to send messages - let sender = conn.sender(object_path, interface_name)?; + // 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 + })?; - // Add the callback to the connection - conn.add_signal_handler(handle_notification_added)?; - // Wait for signals - conn.process_incoming(None)?; + loop { + conn.process(Duration::from_millis(1000))?; + } - //println!("{not}"); Ok(()) } diff --git a/src/unused.txt b/src/unused.txt new file mode 100644 index 0000000..3ab0c27 --- /dev/null +++ b/src/unused.txt @@ -0,0 +1,82 @@ +fn main() -> Result<(), dbus::Error> { + /* + // Example notif + let mut not = Notif { + app_name: "snot".to_string(), + replace_id: Some(0), + ico: "alert.png".to_string(), + summary: "This is a very long suuummmaaarrryyy! Don't you believe me????".to_string(), + body: "short body(hehe)".to_string(), + actions: vec![ + ("reply".to_string(), "Reply".to_string()), + ("close".to_string(), "Close".to_string()), + ], + hints: HashMap::new(), // Create an empty HashMap for hints, add the hints later + expir_timeout: Some(0), + }; + not.hints + .insert("urgency".to_string(), "critical".to_string()); + not.hints + .insert("category".to_string(), "network.error".to_string()); + // End of eg. notif + truncate_summary(&mut not); //Limit the summary length + */ + } + //println!("{not}"); + + +fn handle_notification_added(message: Message) { + if message.get_type() == MessageType::Signal { + let signal_name = message.get_signature().unwrap(); + + if signal_name == "notification_added" { + let (id, app_name, icon, summary, body, actions, hints, timeout) = message + .get_arguments::<( + u32, + String, + String, + String, + String, + Vec, + HashMap, + i32, + )>() + .unwrap(); + + let notif = Notif { + app_name, + replace_id: Some(id), // Assuming you want to use the ID for replacement + ico: icon, + summary, + body, + actions: actions + .iter() + .map(|(key, value)| (key.clone(), value.clone())) + .collect(), + hints: hints + .iter() + .map(|(key, value)| (key.clone(), value.to_string())) + .collect(), + expir_timeout: if timeout < 0 { + None + } else { + Some(timeout as u32) + }, + }; + + // Print or process the notification object + println!("{notif}"); + } + } +} + + + + /* Subscribe to the "notification added" signal + let mut match_rule: MatchRule = MatchRule::new(); + match_rule.msg_type = Some(Signal); + match_rule.path = Some(Path::new(object_path).expect("Failed to create path")); + 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