Skip to content

Commit 51903a7

Browse files
committed
Add support for customColor for SVG icons
This commit implements customColor styling for SVG icons using librsvg.
1 parent fdcda3d commit 51903a7

File tree

4 files changed

+66
-23
lines changed

4 files changed

+66
-23
lines changed

config.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ LDFLAGS_DEBUG :=
6262
pkg_config_packs := gio-2.0 \
6363
gdk-pixbuf-2.0 \
6464
"glib-2.0 >= 2.44" \
65+
librsvg-2.0 \
6566
pangocairo \
6667

6768
ifneq (0,${WAYLAND})

src/icon.c

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
#include <assert.h>
44
#include <cairo.h>
55
#include <gdk-pixbuf/gdk-pixbuf.h>
6+
#include <librsvg/rsvg.h>
67
#include <stdbool.h>
78
#include <string.h>
89
#include <math.h>
910

1011
#include "log.h"
11-
#include "notification.h"
1212
#include "settings.h"
1313
#include "utils.h"
1414
#include "icon-lookup.h"
@@ -205,7 +205,7 @@ static char *get_id_from_data(const uint8_t *data_pb, size_t width, size_t heigh
205205
return id;
206206
}
207207

208-
GdkPixbuf *get_pixbuf_from_file(const char *filename, char **id, int min_size, int max_size, double scale)
208+
cairo_surface_t *get_cairo_surface_from_file(const char *filename, char **id, struct color fg_color, int min_size, int max_size, double scale)
209209
{
210210
GError *error = NULL;
211211
gint w, h;
@@ -217,28 +217,74 @@ GdkPixbuf *get_pixbuf_from_file(const char *filename, char **id, int min_size, i
217217
LOG_W("Failed to load image info for %s", STR_NN(filename));
218218
return NULL;
219219
}
220-
GdkPixbuf *pixbuf = NULL;
220+
221221
// TODO immediately rescale icon upon scale changes
222222
icon_size_clamp(&w, &h, min_size, max_size);
223-
pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
223+
cairo_surface_t *icon_surface = cairo_image_surface_create(
224+
CAIRO_FORMAT_ARGB32,
224225
round(w * scale),
225-
round(h * scale),
226-
TRUE,
227-
&error);
226+
round(h * scale)
227+
);
228+
const char *ext = strrchr(filename, '.');
229+
if (ext && !strcmp(ext, ".svg")) {
230+
RsvgHandle *handle = rsvg_handle_new_from_file(filename, &error);
231+
const guint8 stylesheet[37];
232+
const size_t stylesheet_len = sizeof(stylesheet) / sizeof(guint8);
233+
234+
g_snprintf((char*)stylesheet, stylesheet_len, "path { fill: #%02x%02x%02x%02x !important; }",
235+
(int)(fg_color.r * 255),
236+
(int)(fg_color.g * 255),
237+
(int)(fg_color.b * 255),
238+
(int)(fg_color.a * 255));
239+
rsvg_handle_set_stylesheet(handle, stylesheet, stylesheet_len, &error);
240+
241+
cairo_t *cr = cairo_create(icon_surface);
242+
RsvgRectangle viewport = {
243+
0,
244+
0,
245+
cairo_image_surface_get_width(icon_surface),
246+
cairo_image_surface_get_height(icon_surface)
247+
};
248+
rsvg_handle_render_document(handle, cr, &viewport, &error);
249+
cairo_destroy(cr);
250+
g_object_unref(handle);
251+
} else {
252+
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
253+
round(w * scale),
254+
round(h * scale),
255+
TRUE,
256+
&error);
257+
icon_surface = gdk_pixbuf_to_cairo_surface(pixbuf);
258+
g_object_unref(pixbuf);
259+
}
228260

229261
if (error) {
230262
LOG_W("%s", error->message);
231263
g_error_free(error);
232264
}
233265

234-
const uint8_t *data = gdk_pixbuf_get_pixels(pixbuf);
235-
size_t rowstride = gdk_pixbuf_get_rowstride(pixbuf);
236-
size_t n_channels = gdk_pixbuf_get_n_channels(pixbuf);
237-
size_t bits_per_sample = gdk_pixbuf_get_bits_per_sample(pixbuf);
238-
size_t pixelstride = (n_channels * bits_per_sample + 7)/8;
266+
const uint8_t *data = cairo_image_surface_get_data(icon_surface);
267+
size_t rowstride = cairo_image_surface_get_stride(icon_surface);
268+
269+
int pixelstride;
270+
switch (cairo_image_surface_get_format(icon_surface)) {
271+
case CAIRO_FORMAT_A8:
272+
pixelstride = 1;
273+
break;
274+
case CAIRO_FORMAT_RGB24:
275+
pixelstride = 3;
276+
break;
277+
case CAIRO_FORMAT_ARGB32:
278+
pixelstride = 4;
279+
break;
280+
default:
281+
LOG_W("Unsupported cairo format %d", cairo_image_surface_get_format(icon_surface));
282+
cairo_surface_destroy(icon_surface);
283+
return NULL;
284+
}
239285

240286
*id = get_id_from_data(data, w, h, pixelstride, rowstride);
241-
return pixbuf;
287+
return icon_surface;
242288
}
243289

244290
char *get_path_from_icon_name(const char *iconname, int size)

src/icon.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include <cairo.h>
55
#include <gdk-pixbuf/gdk-pixbuf.h>
66

7-
#include "notification.h"
7+
#include "draw.h"
88

99
cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf);
1010

@@ -20,7 +20,7 @@ cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf);
2020
* @return an instance of `GdkPixbuf`
2121
* @retval NULL: file does not exist, not readable, etc..
2222
*/
23-
GdkPixbuf *get_pixbuf_from_file(const char *filename, char **id, int min_size, int max_size, double scale);
23+
cairo_surface_t *get_cairo_surface_from_file(const char *filename, char **id, struct color fg_color, int min_size, int max_size, double scale);
2424

2525

2626
/**

src/notification.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,14 @@
1515
#include <unistd.h>
1616

1717
#include "dbus.h"
18-
#include "dunst.h"
1918
#include "icon.h"
2019
#include "log.h"
2120
#include "markup.h"
2221
#include "menu.h"
23-
#include "queues.h"
2422
#include "rules.h"
2523
#include "settings.h"
2624
#include "utils.h"
2725
#include "draw.h"
28-
#include "icon-lookup.h"
2926
#include "settings_data.h"
3027

3128
static void notification_extract_urls(struct notification *n);
@@ -374,13 +371,12 @@ void notification_icon_replace_path(struct notification *n, const char *new_icon
374371
g_free(n->icon_path);
375372
n->icon_path = get_path_from_icon_name(new_icon, n->min_icon_size);
376373
if (n->icon_path) {
377-
GdkPixbuf *pixbuf = get_pixbuf_from_file(n->icon_path, &n->icon_id,
378-
n->min_icon_size, n->max_icon_size,
374+
cairo_surface_t *icon_surface = get_cairo_surface_from_file(n->icon_path, &n->icon_id,
375+
n->colors.fg, n->min_icon_size, n->max_icon_size,
379376
draw_get_scale());
380-
if (pixbuf) {
381-
n->icon = gdk_pixbuf_to_cairo_surface(pixbuf);
377+
if (icon_surface) {
378+
n->icon = icon_surface;
382379
n->icon_time = time_now();
383-
g_object_unref(pixbuf);
384380
} else {
385381
LOG_W("Failed to load icon from path: '%s'", n->icon_path);
386382
}

0 commit comments

Comments
 (0)