Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for image-data #211

Merged
merged 4 commits into from Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
68 changes: 65 additions & 3 deletions src/Services/Notification.vala
Expand Up @@ -28,6 +28,7 @@ public class Notifications.Notification : Object {
public string[] actions;
public uint32 replaces_id;
public uint32 id;
public bool has_temp_file;
public GLib.DateTime timestamp;
public GLib.Icon badge_icon { get; construct set; }

Expand Down Expand Up @@ -55,7 +56,7 @@ public class Notifications.Notification : Object {

public Notification (
uint32 _id, string _app_name, string _app_icon, string _summary, string _message_body, string _image_path,
string[] _actions, string _desktop_id, int64 _unix_time, uint64 _replaces_id, string _sender
string[] _actions, string _desktop_id, int64 _unix_time, uint64 _replaces_id, string _sender, bool _has_temp_file
) {
app_name = _app_name;
app_icon = _app_icon;
Expand All @@ -71,6 +72,8 @@ public class Notifications.Notification : Object {

desktop_id = _desktop_id;
app_info = new DesktopAppInfo (desktop_id);

has_temp_file = _has_temp_file;
}

public Notification.from_message (DBusMessage message, uint32 _id) {
Expand Down Expand Up @@ -105,8 +108,7 @@ public class Notifications.Notification : Object {
}

// GLib.Notification.set_icon ()
image_path = lookup_string (hints, "image-path");
if (image_path != null) {
if ((image_path = lookup_string (hints, "image-path")) != "" || (image_path = lookup_string (hints, "image_path")) != "") {
// Ensure we're not being sent symbolic badge icons
image_path = image_path.replace ("-symbolic", "");

Expand All @@ -121,6 +123,16 @@ public class Notifications.Notification : Object {
}
}

// Raw image data sent within a variant
Gdk.Pixbuf? buf = null;
if ((buf = lookup_pixbuf (hints, "image-data")) != null || (buf = lookup_pixbuf (hints, "image_data")) != null || (buf = lookup_pixbuf (hints, "icon_data")) != null) {
var tmpfile = store_pixbuf (buf);
if (tmpfile != null) {
image_path = tmpfile;
has_temp_file = true;
}
}

if (app_info == null) {
desktop_id = FALLBACK_DESKTOP_ID;
app_info = new DesktopAppInfo (desktop_id);
Expand Down Expand Up @@ -174,4 +186,54 @@ public class Notifications.Notification : Object {

return child.dup_string ();
}

private Gdk.Pixbuf? lookup_pixbuf (Variant tuple, string key) {
var img = tuple.lookup_value (key, null);

if (img == null || img.get_type_string () != "(iiibiiay)") {
return null;
}

int width = img.get_child_value (0).get_int32 ();
int height = img.get_child_value (1).get_int32 ();
int rowstride = img.get_child_value (2).get_int32 ();
bool has_alpha = img.get_child_value (3).get_boolean ();
int bits_per_sample = img.get_child_value (4).get_int32 ();
unowned uint8[] raw = (uint8[]) img.get_child_value (6).get_data ();

// Build the pixbuf from the unowned buffer, and copy it to maintain our own instance.
Gdk.Pixbuf pixbuf = new Gdk.Pixbuf.with_unowned_data (raw, Gdk.Colorspace.RGB,
has_alpha, bits_per_sample, width, height, rowstride, null);
return pixbuf.copy ();
}

private string? make_temp_file (string tmpl) {
FileIOStream iostream;
try {
File file = File.new_tmp (tmpl, out iostream);
return file.get_path ();
} catch (Error e) {
return null;
}
}

public string? store_pixbuf (Gdk.Pixbuf pixbuf) {
string? tmpfile = make_temp_file ("wingpanel-XXXXXX.png");
if (tmpfile != null) {
try {
if (pixbuf.save (tmpfile, "png", null)) {
return tmpfile;
}
} catch (Error e) {
critical ("Unable to cache image: %s", e.message);
var file = File.new_for_path (tmpfile);
try {
file.delete ();
} catch (Error e) {
critical ("Unable to delete tmpfile: %s", tmpfile);
}
}
}
return null;
}
}
19 changes: 13 additions & 6 deletions src/Services/Session.vala
Expand Up @@ -37,6 +37,7 @@ public class Notifications.Session : GLib.Object {
private const string SENDER_KEY = "Sender";
private const string SUMMARY_KEY = "Summary";
private const string UNIX_TIME_KEY = "UnixTime";
private const string HAS_TEMP_FILE_KEY = "HasTempFile";

private KeyFile key;

Expand Down Expand Up @@ -74,7 +75,8 @@ public class Notifications.Session : GLib.Object {
key.get_string (group, DESKTOP_ID_KEY),
key.get_int64 (group, UNIX_TIME_KEY),
key.get_uint64 (group, REPLACES_ID_KEY),
key.get_string (group, SENDER_KEY)
key.get_string (group, SENDER_KEY),
key.get_boolean (group, HAS_TEMP_FILE_KEY)
);
list.append (notification);
}
Expand All @@ -99,12 +101,21 @@ public class Notifications.Session : GLib.Object {
key.set_string (id, SUMMARY_KEY, notification.summary);
key.set_string_list (id, ACTIONS_KEY, notification.actions);
key.set_uint64 (id, REPLACES_ID_KEY, notification.replaces_id);
key.set_boolean (id, HAS_TEMP_FILE_KEY, notification.has_temp_file);

write_contents ();
}

public void remove_notification (Notification notification) {
try {
if (notification.has_temp_file) {
var file = File.new_for_path (notification.image_path);
try {
file.delete ();
} catch (Error e) {
critical ("Unable to delete tmpfile: %s", notification.image_path);
}
}
key.remove_group (notification.id.to_string ());
} catch (KeyFileError e) {
warning (e.message);
Expand All @@ -115,11 +126,7 @@ public class Notifications.Session : GLib.Object {

public void remove_notifications (Notification[] notifications) {
foreach (unowned var notification in notifications) {
try {
key.remove_group (notification.id.to_string ());
} catch (KeyFileError e) {
warning (e.message);
}
remove_notification (notification);
}

write_contents ();
Expand Down