[DBus (name = "org.freedesktop.Notifications")] internal interface AstalNotifd.IDaemon : DBusProxy { public abstract bool ignore_timeout { get; set; } public abstract bool dont_disturb { get; set; } public abstract uint[] notification_ids() throws DBusError, IOError; public abstract string get_notification_json(uint id) throws DBusError, IOError; public signal void notified(uint id, bool replaced); public signal void resolved(uint id, ClosedReason reason); public signal void prop_changed(string prop); public abstract void emit_resolved(uint id, ClosedReason reason); public abstract void emit_action_invoked(uint id, string action); } internal class AstalNotifd.DaemonProxy : Object { private HashTable notifs = new HashTable((i) => i, (a, b) => a == b); public List notifications { owned get { return notifs.get_values(); } } public bool ignore_timeout { get { return proxy.ignore_timeout; } set { proxy.ignore_timeout = value; } } public bool dont_disturb { get { return proxy.dont_disturb; } set { proxy.dont_disturb = value; } } public Notification get_notification(uint id) { return notifs.get(id); } public signal void notified(uint id, bool replaced); public signal void resolved(uint id, ClosedReason reason); private IDaemon proxy; private List ids = new List(); public void stop() { foreach (var id in ids) { SignalHandler.disconnect(proxy, id); } } public bool start() { try { var bus = Bus.get_sync(BusType.SESSION, null); var variant = bus.call_sync( "org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", "GetServerInformation", null, null, DBusCallFlags.NONE, -1, null); var name = variant.get_child_value(0).get_string(); var vendor = variant.get_child_value(1).get_string(); var version = variant.get_child_value(2).get_string(); var running = name == Daemon.name && vendor == Daemon.vendor && version == Daemon.version; if (running) { setup_proxy(); return true; } else { critical("cannot get proxy: %s is already running", name); } } catch (Error err) { critical("cannot get proxy: %s", err.message); } return false; } private void setup_proxy() throws Error { proxy = Bus.get_proxy_sync( BusType.SESSION, "org.freedesktop.Notifications", "/org/freedesktop/Notifications" ); foreach (var id in proxy.notification_ids()) add_notification(id); ids.append(proxy.prop_changed.connect((prop) => { if (prop == "dont-disturb") { proxy.set_cached_property("DontDisturb", null); notify_property(prop); } if (prop == "ignore-timeout") { proxy.set_cached_property("IgnoreTimeout", null); notify_property(prop); } })); ids.append(proxy.notified.connect((id, replaced) => { add_notification(id); notified(id, replaced); notify_property("notifications"); })); ids.append(proxy.resolved.connect((id, reason) => { notifs.remove(id); resolved(id, reason); notify_property("notifications"); })); } private void add_notification(uint id) { try { var n = Notification.from_json_string(proxy.get_notification_json(id)); proxy.resolved.connect((id, reason) => n.resolved(reason)); n.dismissed.connect(() => proxy.emit_resolved(id, ClosedReason.DISMISSED_BY_USER)); n.invoked.connect((action) => proxy.emit_action_invoked(id, action)); notifs.set(id, n); } catch (Error err) { critical(err.message); } } }