Skip to content

Commit aaadead

Browse files
authoredJan 13, 2025··
Fix & refactor notifications (#284)
* fix 283 * refactor notifications * fix use-after-free in `pixbufFromVariant` * formatting * notifications: scale large images * notifications: optimize pixbufFromVariant
1 parent f49f719 commit aaadead

File tree

3 files changed

+34
-50
lines changed

3 files changed

+34
-50
lines changed
 

‎src/panel/widgets/notifications/daemon.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ try {
8686
{
8787
signal_notification_new.emit(id);
8888
}
89-
} catch (const std::invalid_argument & err)
89+
} catch (const std::exception & err)
9090
{
91-
std::cerr << "Error at " << __PRETTY_FUNCTION__ << ": " << err.what() << std::endl;
91+
std::cerr << "Error at " << __PRETTY_FUNCTION__ << ": " << err.what() << '\n';
9292
}
9393

9494
dbus_method(Daemon::CloseNotification)

‎src/panel/widgets/notifications/notification-info.cpp

+18-46
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22

33
#include <gdkmm.h>
44

5-
template<class T>
6-
static void iterTo(Glib::VariantIter & iter, T & to)
5+
namespace
76
{
8-
Glib::Variant<T> var;
9-
iter.next_value(var);
10-
to = var.get();
7+
template<class... T>
8+
void extractValues(const Glib::VariantBase & variant, T&... values)
9+
{
10+
std::tie(values...) = Glib::VariantBase::cast_dynamic<Glib::Variant<std::tuple<T...>>>(variant).get();
1111
}
1212

1313
template<class K>
14-
static K getHint(const std::map<std::string, Glib::VariantBase> & map, const std::string & key)
14+
K getHint(const std::map<std::string, Glib::VariantBase> & map, const std::string & key)
1515
{
1616
if (map.count(key) != 0)
1717
{
1818
const auto & val = map.at(key);
1919
if (val.is_of_type(Glib::Variant<K>::variant_type()))
2020
{
21-
return Glib::VariantBase::cast_dynamic<Glib::Variant<K>>(map.at(key)).get();
21+
return Glib::VariantBase::cast_dynamic<Glib::Variant<K>>(val).get();
2222
}
2323
}
2424

@@ -27,41 +27,29 @@ static K getHint(const std::map<std::string, Glib::VariantBase> & map, const std
2727

2828
Glib::RefPtr<Gdk::Pixbuf> pixbufFromVariant(const Glib::VariantBase & variant)
2929
{
30-
if (!variant.is_of_type(Glib::VariantType("iiibiiay")))
31-
{
32-
throw std::invalid_argument("Cannot create pixbuf from variant.");
33-
}
34-
35-
auto iter = Glib::VariantIter(variant);
3630
gint32 width;
3731
gint32 height;
3832
gint32 rowstride;
3933
bool has_alpha;
4034
gint32 bits_per_sample;
4135
gint32 channels;
42-
43-
iterTo(iter, width);
44-
iterTo(iter, height);
45-
iterTo(iter, rowstride);
46-
iterTo(iter, has_alpha);
47-
iterTo(iter, bits_per_sample);
48-
iterTo(iter, channels);
49-
50-
Glib::VariantBase data_var;
51-
iter.next_value(data_var);
36+
std::vector<guint8> data;
37+
extractValues(variant, width, height, rowstride, has_alpha, bits_per_sample, channels, data);
5238

5339
// for integer positive A, floor((A + 7) / 8) = ceil(A / 8)
5440
gulong pixel_size = (channels * bits_per_sample + 7) / 8;
55-
if (data_var.get_size() != ((gulong)height - 1) * (gulong)rowstride + (gulong)width * pixel_size)
41+
if (data.size() != ((gulong)height - 1) * (gulong)rowstride + (gulong)width * pixel_size)
5642
{
5743
throw std::invalid_argument(
5844
"Cannot create pixbuf from variant: expected data size doesn't equal actual one.");
5945
}
6046

61-
const auto *data = (guint8*)(g_memdup2(data_var.get_data(), data_var.get_size()));
62-
return Gdk::Pixbuf::create_from_data(data, Gdk::COLORSPACE_RGB, has_alpha, bits_per_sample, width, height,
63-
rowstride);
47+
auto *data_ptr = new auto(std::move(data));
48+
return Gdk::Pixbuf::create_from_data(data_ptr->data(),
49+
Gdk::COLORSPACE_RGB, has_alpha, bits_per_sample, width, height,
50+
rowstride, [data_ptr] (auto*) { delete data_ptr; });
6451
}
52+
} // namespace
6553

6654
Notification::Hints::Hints(const std::map<std::string, Glib::VariantBase> & map)
6755
{
@@ -73,7 +61,7 @@ Notification::Hints::Hints(const std::map<std::string, Glib::VariantBase> & map)
7361
image_data = pixbufFromVariant(map.at("image-data"));
7462
} else if (map.count("icon_data") != 0)
7563
{
76-
image_data = pixbufFromVariant(map.at("image_data"));
64+
image_data = pixbufFromVariant(map.at("icon_data"));
7765
}
7866

7967
image_path = getHint<Glib::ustring>(map, "image-path");
@@ -94,29 +82,13 @@ Notification::Hints::Hints(const std::map<std::string, Glib::VariantBase> & map)
9482

9583
Notification::Notification(const Glib::VariantContainerBase & parameters, const Glib::ustring & sender)
9684
{
97-
static const auto REQUIRED_TYPE = Glib::VariantType("(susssasa{sv}i)");
98-
if (!parameters.is_of_type(REQUIRED_TYPE))
99-
{
100-
throw std::invalid_argument("NotificationInfo: parameters type must be (susssasa{sv}i)");
101-
}
102-
103-
Glib::VariantBase params_var;
104-
parameters.get_normal_form(params_var);
105-
auto iter = Glib::VariantIter(params_var);
106-
iterTo(iter, app_name);
107-
iterTo(iter, id);
85+
std::map<std::string, Glib::VariantBase> hints_map;
86+
extractValues(parameters, app_name, id, app_icon, summary, body, actions, hints_map, expire_time);
10887
if (id == 0)
10988
{
11089
id = ++Notification::notifications_count;
11190
}
11291

113-
iterTo(iter, app_icon);
114-
iterTo(iter, summary);
115-
iterTo(iter, body);
116-
iterTo(iter, actions);
117-
118-
std::map<std::string, Glib::VariantBase> hints_map;
119-
iterTo(iter, hints_map);
12092
hints = Hints(hints_map);
12193

12294
additional_info.recv_time = std::time(nullptr);

‎src/panel/widgets/notifications/single-notification.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,29 @@ WfSingleNotification::WfSingleNotification(const Notification & notification)
9797

9898
child.add(top_bar);
9999

100+
Gtk::IconSize body_image_size = Gtk::ICON_SIZE_DIALOG;
100101
if (notification.hints.image_data)
101102
{
102-
image.set(notification.hints.image_data);
103+
int width;
104+
int height;
105+
Gtk::IconSize::lookup(body_image_size, width, height);
106+
107+
auto image_pixbuf = notification.hints.image_data;
108+
if (image_pixbuf->get_width() > width)
109+
{
110+
image_pixbuf = image_pixbuf->scale_simple(width,
111+
width * image_pixbuf->get_height() / image_pixbuf->get_width(), Gdk::INTERP_BILINEAR);
112+
}
113+
114+
image.set(image_pixbuf);
103115
} else if (!notification.hints.image_path.empty())
104116
{
105117
if (is_file_uri(notification.hints.image_path))
106118
{
107119
image.set(path_from_uri(notification.hints.image_path));
108120
} else
109121
{
110-
image.set_from_icon_name(notification.hints.image_path, Gtk::ICON_SIZE_DIALOG);
122+
image.set_from_icon_name(notification.hints.image_path, body_image_size);
111123
}
112124
}
113125

0 commit comments

Comments
 (0)
Please sign in to comment.