2024-08-11 14:27:37 +00:00
|
|
|
use std::collections::HashMap;
|
2024-08-20 04:56:36 +00:00
|
|
|
use std::fmt;
|
2024-08-23 02:18:27 +00:00
|
|
|
use dbus::blocking::{Connection, Message, MessageType, Sender};
|
|
|
|
use dbus::message::{MatchRule, MessageType::MethodCall};
|
|
|
|
use dbus::prelude::*;
|
2024-08-11 14:27:37 +00:00
|
|
|
|
2024-08-11 19:12:21 +00:00
|
|
|
// Structure of a notification
|
2024-08-11 11:31:05 +00:00
|
|
|
struct Notif {
|
|
|
|
app_name: String,
|
2024-08-11 19:12:21 +00:00
|
|
|
replace_id: Option<u32>,
|
|
|
|
ico: String,
|
2024-08-11 11:31:05 +00:00
|
|
|
summary: String,
|
|
|
|
body: String,
|
2024-08-11 14:27:37 +00:00
|
|
|
actions: Vec<(String, String)>,
|
|
|
|
hints: HashMap<String, String>,
|
2024-08-11 19:12:21 +00:00
|
|
|
expir_timeout: Option<u32>,
|
|
|
|
}
|
|
|
|
|
2024-08-23 02:18:27 +00:00
|
|
|
|
2024-08-11 19:12:21 +00:00
|
|
|
// Function to print the contents of the notification
|
|
|
|
impl fmt::Display for Notif {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2024-08-20 04:56:36 +00:00
|
|
|
writeln!(f, "AppName: {}", &self.app_name)?;
|
2024-08-11 19:12:21 +00:00
|
|
|
match self.replace_id {
|
2024-08-20 04:56:36 +00:00
|
|
|
Some(notif_id) => writeln!(f, "ReplaceId: {notif_id}")?,
|
|
|
|
None => writeln!(f, "None")?,
|
2024-08-11 19:12:21 +00:00
|
|
|
}
|
2024-08-20 04:56:36 +00:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Icon: {}\nSummary: {}\nBody: {}\nActions:\n",
|
|
|
|
&self.ico, &self.summary, &self.body
|
2024-08-11 19:12:21 +00:00
|
|
|
)?;
|
|
|
|
for (key, label) in &self.actions {
|
2024-08-20 04:56:36 +00:00
|
|
|
writeln!(f, "\t{key}: {label}")?;
|
2024-08-11 19:12:21 +00:00
|
|
|
}
|
2024-08-20 04:56:36 +00:00
|
|
|
writeln!(f, "Hints:")?;
|
2024-08-11 19:12:21 +00:00
|
|
|
for (key, value) in &self.hints {
|
2024-08-20 04:56:36 +00:00
|
|
|
writeln!(f, "\t{key}: {value}")?;
|
2024-08-11 19:12:21 +00:00
|
|
|
}
|
|
|
|
match self.expir_timeout {
|
2024-08-20 04:56:36 +00:00
|
|
|
Some(millisec) => writeln!(f, "Expiration Timeout: {millisec}")?,
|
|
|
|
None => writeln!(f, "None")?,
|
2024-08-11 19:12:21 +00:00
|
|
|
}
|
|
|
|
Ok(()) // Return Ok to indicate success
|
|
|
|
}
|
2024-08-10 21:29:13 +00:00
|
|
|
}
|
|
|
|
|
2024-08-11 11:31:05 +00:00
|
|
|
// 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);
|
2024-08-20 04:56:36 +00:00
|
|
|
notif.summary.push('…');
|
2024-08-10 21:29:13 +00:00
|
|
|
}
|
2024-08-11 11:31:05 +00:00
|
|
|
}
|
2024-08-10 21:29:13 +00:00
|
|
|
|
2024-08-23 02:18:27 +00:00
|
|
|
// Callback function
|
|
|
|
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<String>, HashMap<String, dbus::Value>, 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!("{notification}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn main() -> Result<(), dbus::Error> {
|
|
|
|
/*
|
2024-08-11 19:12:21 +00:00
|
|
|
// Example notif
|
2024-08-11 11:31:05 +00:00
|
|
|
let mut not = Notif {
|
|
|
|
app_name: "snot".to_string(),
|
2024-08-11 19:12:21 +00:00
|
|
|
replace_id: Some(0),
|
2024-08-11 14:27:37 +00:00
|
|
|
ico: "alert.png".to_string(),
|
2024-08-11 11:31:05 +00:00
|
|
|
summary: "This is a very long suuummmaaarrryyy! Don't you believe me????".to_string(),
|
|
|
|
body: "short body(hehe)".to_string(),
|
2024-08-11 14:27:37 +00:00
|
|
|
actions: vec![
|
|
|
|
("reply".to_string(), "Reply".to_string()),
|
|
|
|
("close".to_string(), "Close".to_string()),
|
|
|
|
],
|
2024-08-11 19:12:21 +00:00
|
|
|
hints: HashMap::new(), // Create an empty HashMap for hints, add the hints later
|
2024-08-20 04:56:36 +00:00
|
|
|
expir_timeout: Some(0),
|
2024-08-11 11:31:05 +00:00
|
|
|
};
|
2024-08-20 04:56:36 +00:00
|
|
|
not.hints
|
|
|
|
.insert("urgency".to_string(), "critical".to_string());
|
|
|
|
not.hints
|
|
|
|
.insert("category".to_string(), "network.error".to_string());
|
2024-08-20 21:02:06 +00:00
|
|
|
// End of eg. notif
|
2024-08-11 11:32:35 +00:00
|
|
|
truncate_summary(&mut not); //Limit the summary length
|
2024-08-23 02:18:27 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
// Connect to the system bus
|
|
|
|
let conn = Connection::new_session()?;
|
|
|
|
|
|
|
|
// Get the object path of the notification service
|
|
|
|
let object_path = "/org/freedesktop/Notifications";
|
|
|
|
|
|
|
|
// Get the interface name of the notification service
|
|
|
|
let interface_name = "org.freedesktop.Notifications";
|
|
|
|
|
|
|
|
// 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 sender to send messages
|
|
|
|
let sender = conn.sender(object_path, interface_name)?;
|
2024-08-20 04:56:36 +00:00
|
|
|
|
2024-08-23 02:18:27 +00:00
|
|
|
// Add the callback to the connection
|
|
|
|
conn.add_signal_handler(handle_notification_added)?;
|
2024-08-20 21:02:06 +00:00
|
|
|
|
2024-08-23 02:18:27 +00:00
|
|
|
// Wait for signals
|
|
|
|
conn.process_incoming(None)?;
|
2024-08-20 21:02:06 +00:00
|
|
|
|
2024-08-23 02:18:27 +00:00
|
|
|
//println!("{not}");
|
|
|
|
Ok(())
|
2024-08-11 19:12:21 +00:00
|
|
|
}
|