diff options
Diffstat (limited to 'notifd/src/daemon.vala')
-rw-r--r-- | notifd/src/daemon.vala | 255 |
1 files changed, 0 insertions, 255 deletions
diff --git a/notifd/src/daemon.vala b/notifd/src/daemon.vala deleted file mode 100644 index b8fb598..0000000 --- a/notifd/src/daemon.vala +++ /dev/null @@ -1,255 +0,0 @@ -[DBus (name = "org.freedesktop.Notifications")] -internal class AstalNotifd.Daemon : Object { - public static string name = "notifd"; - public static string vendor = "astal"; - public static string version = "0.1"; - - private string state_file; - private string state_directory; - private string cache_directory; - - private uint n_id = 1; - private HashTable<uint, Notification> notifs = - new HashTable<uint, Notification>((i) => i, (a, b) => a == b); - - private bool _ignore_timeout; - public bool ignore_timeout { - get { return _ignore_timeout; } - set { - _ignore_timeout = value; - write_state(); - } - } - - private bool _dont_disturb; - public bool dont_disturb { - get { return _dont_disturb; } - set { - _dont_disturb = value; - write_state(); - } - } - - public signal void notified(uint id, bool replaced); - public signal void resolved(uint id, ClosedReason reason); - public signal void action_invoked(uint id, string action); - public signal void prop_changed(string prop); - - // emitting an event from proxy doesn't seem to work - public void emit_resolved(uint id, ClosedReason reason) { resolved(id, reason); } - public void emit_action_invoked(uint id, string action) { action_invoked(id, action); } - - construct { - cache_directory = Environment.get_user_cache_dir() + "/astal/notifd"; - state_directory = Environment.get_user_state_dir() + "/astal/notifd"; - state_file = state_directory + "/notifications.json"; - - if (FileUtils.test(state_file, FileTest.EXISTS)) { - try { - uint8[] json; - File.new_for_path(state_file).load_contents(null, out json, null); - - var obj = Json.from_string((string)json); - - var list = obj.get_object().get_array_member("notifications"); - for (var i = 0; i < list.get_length(); ++i) { - add_notification(new Notification.from_json(list.get_object_element(i))); - } - n_id = list.get_length() + 1; - - _dont_disturb = obj.get_object().get_boolean_member("dont_disturb"); - _ignore_timeout = obj.get_object().get_boolean_member("ignore_timeout"); - } catch (Error err) { - warning("failed to load cache: %s", err.message); - } - } - - notify.connect((prop) => prop_changed(prop.name)); - - notified.connect(() => { - notify_property("notifications"); - }); - - resolved.connect((id, reason) => { - notifs.get(id).resolved(reason); - notifs.remove(id); - write_state(); - notify_property("notifications"); - notification_closed(id, reason); - }); - } - - public uint[] notification_ids() throws DBusError, IOError { - var keys = notifs.get_keys(); - uint[] id = new uint[keys.length()]; - for (var i = 0; i < keys.length(); ++i) - id[i] = keys.nth_data(i); - return id; - } - - [DBus (visible = false)] - public List<weak Notification> notifications { - owned get { return notifs.get_values(); } - } - - [DBus (visible = false)] - public Notification get_notification(uint id) { - return notifs.get(id); - } - - public string get_notification_json(uint id) throws DBusError, IOError { - return notifs.get(id).to_json_string(); - } - - [DBus (name = "Notify")] - public uint Notify( - string app_name, - uint replaces_id, - string app_icon, - string summary, - string body, - string[] actions, - HashTable<string, Variant> hints, - int expire_timeout - ) throws DBusError, IOError { - if (hints.get("image-data") != null) { - var file = cache_image(hints.get("image-data"), app_name); - if (file != null) { - hints.set("image-path", new Variant.string(file)); - hints.remove("image-data"); - } - } - - // deprecated hints - hints.remove("image_data"); - hints.remove("icon_data"); - - var id = replaces_id > 0 ? replaces_id : n_id++; - - var replaced = add_notification(new Notification( - app_name, id, app_icon, summary, body, actions, hints, expire_timeout - )); - - if (!ignore_timeout && expire_timeout > 0) { - Timeout.add(expire_timeout, () => { - resolved(id, ClosedReason.EXPIRED); - return Source.REMOVE; - }, Priority.DEFAULT); - } - - notified(id, replaced); - - write_state(); - return id; - } - - private bool add_notification(Notification n) { - n.dismissed.connect(() => resolved(n.id, ClosedReason.DISMISSED_BY_USER)); - n.invoked.connect((action) => action_invoked(n.id, action)); - var replaced = notifs.contains(n.id); - notifs.set(n.id, n); - return replaced; - } - - private void write_state() { - var list = new Json.Builder().begin_array(); - foreach (var n in notifications) { - list.add_value(n.to_json()); - } - list.end_array(); - - var obj = new Json.Builder() - .begin_object() - .set_member_name("notifications").add_value(list.get_root()) - .set_member_name("ignore_timeout").add_boolean_value(ignore_timeout) - .set_member_name("dont_disturb").add_boolean_value(dont_disturb) - .end_object(); - - try { - if (!FileUtils.test(state_directory, FileTest.EXISTS)) - File.new_for_path(state_directory).make_directory_with_parents(null); - - FileUtils.set_contents_full(state_file, Json.to_string(obj.get_root(), false)); - } catch (Error err) { - warning("failed to cache notifications: %s", err.message); - } - } - - public signal void notification_closed(uint id, uint reason); - public signal void activation_token(uint id, string token); - - public void close_notification(uint id) throws DBusError, IOError { - resolved(id, ClosedReason.CLOSED); - } - - public void get_server_information( - out string name, - out string vendor, - out string version, - out string spec_version - ) throws DBusError, IOError { - name = Daemon.name; - vendor = Daemon.vendor; - version = Daemon.version; - spec_version = "1.2"; - } - - public string[] get_capabilities() throws DBusError, IOError { - return {"action-icons", "actions", "body", "icon-static", "persistence", "sound"}; - } - - private string? cache_image(Variant image, string app_name) { - int w = image.get_child_value(0).get_int32(); - int h = image.get_child_value(1).get_int32(); - int rs = image.get_child_value(2).get_int32(); - bool alpha = image.get_child_value(3).get_boolean(); - int bps = image.get_child_value(4).get_int32(); - Bytes data = image.get_child_value(6).get_data_as_bytes(); - - if (bps != 8) { - warning("Can not cache image from %s. %s", app_name, - "Currently only RGB images with 8 bits per sample are supported."); - return null; - } - - var pixbuf = new Gdk.Pixbuf.from_bytes( - data, Gdk.Colorspace.RGB, alpha, bps, w, h, rs); - - if (pixbuf == null) - return null; - - var file_name = cache_directory + "/" + data.hash().to_string("%u.png"); - - try { - if (!FileUtils.test(cache_directory, FileTest.EXISTS)) - File.new_for_path(cache_directory).make_directory_with_parents(null); - - var output_stream = File.new_for_path(file_name) - .replace(null, false, FileCreateFlags.NONE, null); - - pixbuf.save_to_streamv(output_stream, "png", null, null, null); - output_stream.close(null); - } catch (Error err) { - warning("could not cache image %s", err.message); - return null; - } - - return file_name; - } - - internal Daemon register(DBusConnection conn) { - try { - conn.register_object("/org/freedesktop/Notifications", this); - } catch (Error err) { - critical(err.message); - } - return this; - } -} - -public enum AstalNotifd.ClosedReason { - EXPIRED = 1, - DISMISSED_BY_USER = 2, - CLOSED = 3, - UNDEFINED = 4, -} |