use std::borrow::Cow;
use std::ops::{Deref,DerefMut};
use dbus::{Connection, ConnectionItem, BusType, Message, MessageItem};
use super::Notification;
use error::*;
#[derive(Debug)]
pub struct NotificationHandle {
id: u32,
connection: Connection,
notification: Notification
}
impl NotificationHandle {
pub fn new(id: u32, connection: Connection, notification: Notification) -> NotificationHandle {
NotificationHandle {
id: id,
connection: connection,
notification: notification
}
}
pub fn wait_for_action<F>(self, invokation_closure:F) where F:FnOnce(&str) {
wait_for_action_signal(&self.connection, self.id, invokation_closure);
}
pub fn close(self) {
let mut message = build_message("CloseNotification");
message.append_items(&[ self.id.into() ]);
let _ = self.connection.send(message); }
pub fn on_close<F>(self, closure:F) where F: FnOnce(){
self.wait_for_action(|action|
if action == "__closed" { closure(); }
);
}
pub fn update(&mut self) {
self.id = self.notification._show(self.id, &self.connection).unwrap();
}
pub fn id(&self) -> u32{
self.id
}
}
impl Deref for NotificationHandle {
type Target = Notification;
fn deref(&self) -> &Notification {
&self.notification
}
}
impl DerefMut for NotificationHandle {
fn deref_mut(&mut self) -> &mut Notification {
&mut self.notification
}
}
pub fn get_capabilities() -> Result<Vec<String>> {
let mut capabilities = vec![];
let message = build_message("GetCapabilities");
let connection = try!(Connection::get_private(BusType::Session));
let reply = try!(connection.send_with_reply_and_block(message, 2000));
if let Some(&MessageItem::Array(ref items, Cow::Borrowed("s"))) = reply.get_items().get(0) {
for item in items.iter(){
if let MessageItem::Str(ref cap) = *item{
capabilities.push(cap.clone());
}
}
}
Ok(capabilities)
}
pub fn get_server_information() -> Result<ServerInformation> {
let message = build_message("GetServerInformation");
let connection = try!(Connection::get_private(BusType::Session));
let reply = try!(connection.send_with_reply_and_block(message, 2000));
let items = reply.get_items();
Ok( ServerInformation{
name: unwrap_message_string(items.get(0)),
vendor: unwrap_message_string(items.get(1)),
version: unwrap_message_string(items.get(2)),
spec_version: unwrap_message_string(items.get(3))
})
}
#[derive(Debug)]
pub struct ServerInformation {
pub name: String,
pub vendor: String,
pub version: String,
pub spec_version: String
}
pub fn stop_server() {
let message = build_message("Stop");
let connection = Connection::get_private(BusType::Session).unwrap();
let _reply = connection.send_with_reply_and_block(message, 2000).unwrap();
}
pub fn handle_actions<F>(id:u32, func:F) where F: FnOnce(&str) {
let connection = Connection::get_private(BusType::Session).unwrap();
wait_for_action_signal(&connection, id, func);
}
fn wait_for_action_signal<F>(connection: &Connection, id: u32, func: F) where F: FnOnce(&str) {
connection.add_match("interface='org.freedesktop.Notifications',member='ActionInvoked'").unwrap();
connection.add_match("interface='org.freedesktop.Notifications',member='ActionInvoked'").unwrap();
connection.add_match("interface='org.freedesktop.Notifications',member='NotificationClosed'").unwrap();
for item in connection.iter(1000) {
if let ConnectionItem::Signal(s) = item {
let (_, protocol, iface, member) = s.headers();
let items = s.get_items();
match (&*protocol.unwrap(), &*iface.unwrap(), &*member.unwrap()) {
("/org/freedesktop/Notifications", "org.freedesktop.Notifications", "ActionInvoked") => {
if let (&MessageItem::UInt32(nid), &MessageItem::Str(ref action)) = (&items[0], &items[1]) {
if nid == id { func(action); break; }
}
},
("/org/freedesktop/Notifications", "org.freedesktop.Notifications", "NotificationClosed") => {
if let (&MessageItem::UInt32(nid), &MessageItem::UInt32(_)) = (&items[0], &items[1]) {
if nid == id { func("__closed"); break; }
}
},
(_, _, _) => ()
}
}
}
}
pub fn build_message(method_name:&str) -> Message {
Message::new_method_call(
"org.freedesktop.Notifications",
"/org/freedesktop/Notifications",
"org.freedesktop.Notifications",
method_name).expect(&format!("Error building message call {:?}.", method_name))
}
fn unwrap_message_string(item: Option<&MessageItem>) -> String {
match item{
Some(&MessageItem::Str(ref value)) => value.to_owned(),
_ => "".to_owned()
}
}