use std::ops::{Deref, DerefMut};
use std::time::Duration;
use std::thread;
use super::Notification;
use dbus::{BusType, Connection, ConnectionItem, Message, MessageItem};
use error::*;
#[cfg(not(feature = "debug_namespace"))] pub static NOTIFICATION_NAMESPACE: &str = "org.freedesktop.Notifications";
#[cfg(not(feature = "debug_namespace"))] pub static NOTIFICATION_OBJECTPATH: &str = "/org/freedesktop/Notifications";
#[cfg(feature = "debug_namespace")] pub static NOTIFICATION_NAMESPACE: &str = "de.hoodie.Notifications";
#[cfg(feature = "debug_namespace")] pub static NOTIFICATION_OBJECTPATH: &str = "/de/hoodie/Notifications";
#[derive(Debug)]
pub struct NotificationHandle {
id: u32,
connection: Connection,
notification: Notification
}
impl NotificationHandle {
pub(crate) fn new(id: u32, connection: Connection, notification: Notification) -> NotificationHandle {
NotificationHandle { id, connection, 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 = Connection::get_private(BusType::Session)?;
let reply = connection.send_with_reply_and_block(message, 2000)?;
if let Some(&MessageItem::Array(ref items)) = 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 = Connection::get_private(BusType::Session)?;
let reply = 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();
thread::sleep(Duration::from_millis(200));
connection.send(message).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(NOTIFICATION_NAMESPACE,
NOTIFICATION_OBJECTPATH,
NOTIFICATION_NAMESPACE,
method_name)
.unwrap_or_else(|_| panic!("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()
}
}