10#include <gdk-pixbuf/gdk-pixbuf.h>
27 const unsigned char *pixels_p,
28 unsigned char *pixels_c,
35#if G_BYTE_ORDER == G_LITTLE_ENDIAN
36 static const size_t CAIRO_B = 0;
37 static const size_t CAIRO_G = 1;
38 static const size_t CAIRO_R = 2;
39 static const size_t CAIRO_A = 3;
40#elif G_BYTE_ORDER == G_BIG_ENDIAN
41 static const size_t CAIRO_A = 0;
42 static const size_t CAIRO_R = 1;
43 static const size_t CAIRO_G = 2;
44 static const size_t CAIRO_B = 3;
45#elif G_BYTE_ORDER == G_PDP_ENDIAN
46 static const size_t CAIRO_R = 0;
47 static const size_t CAIRO_A = 1;
48 static const size_t CAIRO_B = 2;
49 static const size_t CAIRO_G = 3;
52#error Unsupported Endianness
60 if (n_channels == 3) {
61 for (
int h = 0; h < height; h++) {
62 unsigned char *iter_c = pixels_c + h * rowstride_c;
63 const unsigned char *iter_p = pixels_p + h * rowstride_p;
64 for (
int w = 0; w < width; w++) {
65 iter_c[CAIRO_R] = iter_p[0];
66 iter_c[CAIRO_G] = iter_p[1];
67 iter_c[CAIRO_B] = iter_p[2];
68 iter_c[CAIRO_A] = 0xff;
74 for (
int h = 0; h < height; h++) {
75 unsigned char *iter_c = pixels_c + h * rowstride_c;
76 const unsigned char *iter_p = pixels_p + h * rowstride_p;
77 for (
int w = 0; w < width; w++) {
78 double alpha_factor = iter_p[3] / (double)0xff;
79 iter_c[CAIRO_R] = (
unsigned char)(iter_p[0] * alpha_factor + .5);
80 iter_c[CAIRO_G] = (
unsigned char)(iter_p[1] * alpha_factor + .5);
81 iter_c[CAIRO_B] = (
unsigned char)(iter_p[2] * alpha_factor + .5);
82 iter_c[CAIRO_A] = iter_p[3];
92 return round(cairo_image_surface_get_width(icon) / scale);
96 return round(cairo_image_surface_get_height(icon) / scale);
99cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf)
105 int width = gdk_pixbuf_get_width(pixbuf);
106 int height = gdk_pixbuf_get_height(pixbuf);
108 cairo_format_t fmt = gdk_pixbuf_get_has_alpha(pixbuf) ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24;
109 cairo_surface_t *icon_surface = cairo_image_surface_create(fmt, width, height);
112 cairo_surface_flush(icon_surface);
114 cairo_image_surface_get_data(icon_surface),
115 gdk_pixbuf_get_rowstride(pixbuf),
116 cairo_format_stride_for_width(fmt, width),
117 gdk_pixbuf_get_width(pixbuf),
118 gdk_pixbuf_get_height(pixbuf),
119 gdk_pixbuf_get_n_channels(pixbuf));
120 cairo_surface_mark_dirty(icon_surface);
135 int _w = *w, _h = *h;
136 int landscape = _w > _h;
137 int orig_larger = landscape ? _w : _h;
138 double larger = orig_larger;
139 double smaller = landscape ? _h : _w;
140 if (min_size && smaller < min_size) {
141 larger = larger / smaller * min_size;
144 if (max_size && larger > max_size) {
145 smaller = smaller / larger * max_size;
148 if ((
int) larger != orig_larger) {
149 *w = (int) (landscape ? larger : smaller);
150 *h = (int) (landscape ? smaller : larger);
173 int w = gdk_pixbuf_get_width(pixbuf);
174 int h = gdk_pixbuf_get_height(pixbuf);
178 w = round(w * dpi_scale);
179 h = round(h * dpi_scale);
181 GdkPixbuf *scaled = gdk_pixbuf_scale_simple(
185 GDK_INTERP_BILINEAR);
186 g_object_unref(pixbuf);
191static char *get_id_from_data(
const uint8_t *data_pb,
size_t width,
size_t height,
size_t pixelstride,
size_t rowstride)
197 size_t data_chk_len = pixelstride * width * height;
198 unsigned char *data_chk = g_malloc(data_chk_len);
199 size_t rowstride_short = pixelstride * width;
201 for (
int i = 0; i < height; i++) {
202 memcpy(data_chk + (i*rowstride_short),
203 data_pb + (i*rowstride),
207 char *
id = g_compute_checksum_for_data(G_CHECKSUM_MD5, data_chk, data_chk_len);
215 GError *error = NULL;
221 if (!gdk_pixbuf_get_file_info (filename, &w, &h)) {
222 LOG_W(
"Failed to load image info for %s",
STR_NN(filename));
225 GdkPixbuf *pixbuf = NULL;
228 pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
235 LOG_W(
"%s", error->message);
239 const uint8_t *data = gdk_pixbuf_get_pixels(pixbuf);
240 size_t rowstride = gdk_pixbuf_get_rowstride(pixbuf);
241 size_t n_channels = gdk_pixbuf_get_n_channels(pixbuf);
242 size_t bits_per_sample = gdk_pixbuf_get_bits_per_sample(pixbuf);
243 size_t pixelstride = (n_channels * bits_per_sample + 7)/8;
245 *
id = get_id_from_data(data, w, h, pixelstride, rowstride);
254 if (g_str_has_prefix(iconname,
"file://")) {
255 char *uri_path = g_filename_from_uri(iconname, NULL, NULL);
257 LOG_W(
"Invalid file uri '%s'", iconname);
262 return g_strdup(iconname);
263 }
else if (
settings.enable_recursive_icon_lookup) {
266 LOG_W(
"Icon '%s' not found in themes", iconname);
268 LOG_I(
"Found icon '%s' at %s", iconname,
STR_NN(path));
273 const char *suffixes[] = {
".svg",
".svgz",
".png",
".xpm", NULL };
274 char *start =
settings.icon_path, *end, *current_folder, *maybe_icon_path, *path = NULL;
277 end = strchr(start,
':');
278 if (!end) end = strchr(
settings.icon_path,
'\0');
282 for (
const char **suf = suffixes; *suf; suf++) {
283 gchar *name_with_extension = g_strconcat(iconname, *suf, NULL);
284 maybe_icon_path = g_build_filename(current_folder, name_with_extension, NULL);
286 path = g_strdup(maybe_icon_path);
288 g_free(name_with_extension);
289 g_free(maybe_icon_path);
293 g_free(current_folder);
300 LOG_W(
"Icon '%s' not found in icon_path", iconname);
302 LOG_I(
"Found icon '%s' at %s", iconname, path);
307static void icon_destroy(guchar *pixels, gpointer data)
313GdkPixbuf *
icon_get_for_data(GVariant *data,
char **
id,
double dpi_scale,
int min_size,
int max_size)
318 if (!
STR_EQ(
"(iiibiiay)", g_variant_get_type_string(data))) {
319 LOG_W(
"Invalid data for pixbuf given.");
342 GdkPixbuf *pixbuf = NULL;
343 GVariant *data_variant = NULL;
344 unsigned char *data_pb;
368 pixelstride = (n_channels * bits_per_sample + 7)/8;
369 len_expected = (height - 1) * rowstride + width * pixelstride;
370 len_actual = g_variant_get_size(data_variant);
372 if (len_actual != len_expected) {
373 LOG_W(
"Expected image data to be of length %" G_GSIZE_FORMAT
374 " but got a length of %" G_GSIZE_FORMAT,
377 g_variant_unref(data_variant);
383#if GLIB_CHECK_VERSION(2,67,3)
384 data_pb = (guchar *) g_memdup2(g_variant_get_data(data_variant), len_actual);
386 data_pb = (guchar *) g_memdup(g_variant_get_data(data_variant), len_actual);
389 pixbuf = gdk_pixbuf_new_from_data(data_pb,
401 LOG_W(
"Cannot serialise raw icon data into pixbuf.");
406 *
id = get_id_from_data(data_pb, width, height, pixelstride, rowstride);
408 g_variant_unref(data_variant);
char * find_icon_path(const char *name, int size)
Find icon of specified size in the default theme or an inherited theme.
Recursive icon lookup in theme directories.
static GdkPixbuf * icon_pixbuf_scale_to_size(GdkPixbuf *pixbuf, double dpi_scale, int min_size, int max_size)
Scales the given GdkPixbuf to a given size.
static bool icon_size_clamp(int *w, int *h, int min_size, int max_size)
Scales the given image dimensions if necessary according to the settings.
static void pixbuf_data_to_cairo_data(const unsigned char *pixels_p, unsigned char *pixels_c, size_t rowstride_p, size_t rowstride_c, int width, int height, int n_channels)
Reassemble the data parts of a GdkPixbuf into a cairo_surface_t's data field.
int get_icon_width(cairo_surface_t *icon, double scale)
Get the unscaled icon width.
char * get_path_from_icon_name(const char *iconname, int size)
Retrieve a path from an icon name.
GdkPixbuf * icon_get_for_data(GVariant *data, char **id, double dpi_scale, int min_size, int max_size)
Convert a GVariant like described in GdkPixbuf, scaled according to settings.
GdkPixbuf * get_pixbuf_from_file(const char *filename, char **id, int min_size, int max_size, double scale)
Retrieve an icon by its full filepath, scaled according to settings.
int get_icon_height(cairo_surface_t *icon, double scale)
Get the unscaled icon height, see get_icon_width.
Notification images loading.
Logging subsystem and helpers.
Type definitions for settings.
bool is_like_path(const char *string)
Check if the strings looks like a path.
bool is_readable_file(const char *const path)
Check if file is readable.
char * string_to_path(char *string)
Replace tilde and path-specific values with it's equivalents.
String, time and other various helpers.
#define STR_EMPTY(s)
Test if a string is NULL or empty.
#define STR_EQ(a, b)
Test if string a and b contain the same chars.
#define STR_FULL(s)
Test if a string is non-NULL and not empty.
#define STR_NN(s)
Get a non null string from a possibly null one.
#define ASSERT_OR_RET(expr, val)
Assert that expr evaluates to true, if not return val.