use std::collections::HashSet;
use std::cell::Cell;
use dbus::{Connection, BusType, NameFlag, ConnectionItem, Message, MessageItem};
use dbus::obj::{ObjectPath, Argument, Method, Interface};
use super::{Notification,NotificationHint};
use util::*;
static DBUS_ERROR_FAILED: &'static str = "org.freedesktop.DBus.Error.Failed";
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
#[derive(Debug,Default)]
pub struct NotificationServer {
pub counter: Cell<u32>,
pub stop: Cell<bool>
}
impl NotificationServer {
fn count_up(&self) {
self.counter.set( self.counter.get() + 1);
}
pub fn new() -> NotificationServer {
NotificationServer::default()
}
pub fn start<F>(&mut self, closure: F) where F: Fn(&Notification) {
let connection = Connection::get_private(BusType::Session).unwrap();
connection.release_name("org.freedesktop.Notifications").unwrap();
connection.register_name("org.freedesktop.Notifications", NameFlag::ReplaceExisting as u32).expect("Was not able to register name.");
let mut objpath = ObjectPath::new(&connection, "/org/freedesktop/Notifications", false);
connection.register_object_path( "/org/freedesktop/Notifications").expect("could not register object path");
let server_interface = Interface::new(
vec![
Method::new("Notify",
vec![ Argument::new("app_name", "s"),
Argument::new("replaces_id", "u"),
Argument::new("app_icon", "s"),
Argument::new("summary", "s"),
Argument::new("body", "s"),
Argument::new("actions", "as"),
Argument::new("hints", "a{sv}"),
Argument::new("timeout", "i")
],
vec![Argument::new("arg_0", "u")],
Box::new(|msg| {
let hint_items = msg.get_items().get(6).unwrap().clone();
let hint_items:&Vec<MessageItem> = hint_items.inner().unwrap();
let hints = hint_items.iter().map(|item|item.into()).collect::<HashSet<NotificationHint>>();
let action_items = msg.get_items().get(5).unwrap().clone();
let action_items:&Vec<MessageItem> = action_items.inner().unwrap();
let actions:Vec<String> = action_items.iter().map(|action|action.inner::<&String>().unwrap().to_owned()).collect();
let notification = Notification{
appname: unwrap_message_str(msg.get_items().get(0).unwrap()),
summary: unwrap_message_string(msg.get_items().get(3)),
body: unwrap_message_string(msg.get_items().get(4)),
icon: unwrap_message_string(msg.get_items().get(2)),
timeout: msg.get_items().get(7).unwrap().inner().unwrap(),
subtitle: None,
hints: hints,
actions: actions,
id: Some(self.counter.get())
};
closure(¬ification);
self.count_up();
Ok(vec!(MessageItem::Int32(42)))
})
),
Method::new("CloseNotification",
vec![Argument::new("id", "u")], vec![],
Box::new(|msg| {
println!("{:?}", msg);
Ok( vec![])}
)
),
Method::new("Stop",
vec![], vec![],
Box::new(|_msg| {
self.stop.set(true);
Ok( vec![])}
)
),
Method::new("GetCapabilities",
vec![], vec![Argument::new("caps", "{s}")],
Box::new(|_msg| Ok( vec![
MessageItem::new_array( vec![ "body".into(), ]).unwrap()
]))
),
Method::new("GetServerInformation",
vec![], vec![
Argument::new("name", "s"),
Argument::new("vendor", "s"),
Argument::new("version", "s"),
Argument::new("spec_version", "s"),
],
Box::new(|_msg| Ok( vec![
"notify-rust daemon".into(), "notify-rust".into(), VERSION.into(), "1.1".into()
]))
)
],
vec![], vec![] );
objpath.insert_interface("org.freedesktop.Notifications", server_interface);
for n in connection.iter(10) {
match n {
ConnectionItem::MethodCall(mut m) =>
if objpath.handle_message(&mut m).is_none() {
connection.send(Message::new_error(&m, DBUS_ERROR_FAILED, "Object path not found").unwrap()).unwrap();
}
,
ConnectionItem::Signal(_m) => { },
_ => (),
}
if self.stop.get() {
println!("stopping server");
break;
}
}
}
}