29 #define G_LOG_DOMAIN "Helpers.IconFetcher"
33 #include <xcb/xproto.h>
40 #include <pango/pangocairo.h>
46 #include "nkutils-enum.h"
47 #include "nkutils-xdg-theme.h"
52 #include <gdk-pixbuf/gdk-pixbuf.h>
99 for (GList *iter = g_list_first(entry->
sizes); iter;
100 iter = g_list_next(iter)) {
103 cairo_surface_destroy(sentry->
surface);
107 g_list_free(entry->
sizes);
114 static const gchar *
const icon_fallback_themes[] = {
"Adwaita",
"gnome", NULL};
120 nk_xdg_theme_context_new(icon_fallback_themes, NULL);
124 g_hash_table_new(g_direct_hash, g_direct_equal);
128 GSList *l = gdk_pixbuf_get_formats();
129 for (GSList *li = l; li != NULL; li = g_slist_next(li)) {
131 gdk_pixbuf_format_get_extensions((GdkPixbufFormat *)li->data);
133 for (
unsigned int i = 0; exts && exts[i]; i++) {
136 g_info(
"Add image extension: %s", exts[i]);
145 static void free_wrapper(gpointer data, G_GNUC_UNUSED gpointer user_data) {
171 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
200 return ((t >> 8) + t) >> 8;
204 static cairo_surface_t *
207 const guchar *pixels;
211 if (pixbuf == NULL) {
215 width = gdk_pixbuf_get_width(pixbuf);
216 height = gdk_pixbuf_get_height(pixbuf);
217 pixels = gdk_pixbuf_read_pixels(pixbuf);
218 stride = gdk_pixbuf_get_rowstride(pixbuf);
219 alpha = gdk_pixbuf_get_has_alpha(pixbuf);
221 cairo_surface_t *surface = NULL;
226 const guchar *pixels_end, *line;
229 pixels_end = pixels + height * stride;
233 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
234 cpixels = cairo_image_surface_get_data(surface);
235 cstride = cairo_image_surface_get_stride(surface);
237 cairo_surface_flush(surface);
238 while (pixels < pixels_end) {
240 const guchar *line_end = line + lo;
241 guchar *cline = cpixels;
243 while (line < line_end) {
259 cairo_surface_mark_dirty(surface);
260 cairo_surface_flush(surface);
269 const char *suf = strrchr(path,
'.');
276 iter = g_list_next(iter)) {
277 if (g_ascii_strcasecmp(iter->data, suf) == 0) {
285 G_GNUC_UNUSED gpointer user_data) {
286 g_debug(
"starting up icon fetching thread.");
292 const gchar *icon_path;
293 gchar *icon_path_ = NULL;
295 if (g_path_is_absolute(sentry->
entry->
name)) {
297 }
else if (g_str_has_prefix(sentry->
entry->
name,
"<span")) {
298 cairo_surface_t *surface = cairo_image_surface_create(
299 CAIRO_FORMAT_ARGB32, sentry->
wsize, sentry->
hsize);
300 cairo_t *cr = cairo_create(surface);
301 PangoLayout *layout = pango_cairo_create_layout(cr);
302 pango_layout_set_markup(layout, sentry->
entry->
name, -1);
305 pango_layout_get_size(layout, &width, &height);
306 double ws = sentry->
wsize / ((double)width / PANGO_SCALE);
307 double wh = sentry->
hsize / ((double)height / PANGO_SCALE);
308 double scale = MIN(ws, wh);
311 cr, (sentry->
wsize - ((
double)width / PANGO_SCALE) * scale) / 2.0,
312 (sentry->
hsize - ((
double)height / PANGO_SCALE) * scale) / 2.0);
313 cairo_scale(cr, scale, scale);
314 pango_cairo_update_layout(cr, layout);
315 pango_layout_get_size(layout, &width, &height);
316 pango_cairo_show_layout(cr, layout);
317 g_object_unref(layout);
324 icon_path = icon_path_ = nk_xdg_theme_get_icon(
327 if (icon_path_ == NULL) {
328 g_debug(
"failed to get icon %s(%dx%d): n/a", sentry->
entry->
name,
331 const char *ext = g_strrstr(sentry->
entry->
name,
".");
335 if (icon_path == NULL) {
339 g_debug(
"found icon %s(%dx%d): %s", sentry->
entry->
name, sentry->
wsize,
340 sentry->
hsize, icon_path);
343 cairo_surface_t *icon_surf = NULL;
345 const char *suf = strrchr(icon_path,
'.');
350 GError *error = NULL;
351 GdkPixbuf *pb = gdk_pixbuf_new_from_file_at_scale(
352 icon_path, sentry->
wsize, sentry->
hsize, TRUE, &error);
354 g_warning(
"Failed to load image: %s", error->message);
371 g_debug(
"Query: %s(%dx%d)", name, wsize, hsize);
376 entry->
name = g_strdup(name);
380 for (GList *iter = g_list_first(entry->
sizes); iter;
381 iter = g_list_next(iter)) {
383 if (sentry->
wsize == wsize && sentry->
hsize == hsize) {
391 sentry->
wsize = wsize;
392 sentry->
hsize = hsize;
393 sentry->
entry = entry;
396 entry->
sizes = g_list_prepend(entry->
sizes, sentry);
398 GINT_TO_POINTER(sentry->
uid), sentry);
402 g_thread_pool_push(
tpool, sentry, NULL);
407 g_debug(
"Query: %s(%d)", name, size);
412 entry->
name = g_strdup(name);
416 for (GList *iter = g_list_first(entry->
sizes); iter;
417 iter = g_list_next(iter)) {
419 if (sentry->
wsize == size && sentry->
hsize == size) {
427 sentry->
wsize = size;
428 sentry->
hsize = size;
429 sentry->
entry = entry;
432 entry->
sizes = g_list_prepend(entry->
sizes, sentry);
434 GINT_TO_POINTER(sentry->
uid), sentry);
438 g_thread_pool_push(
tpool, sentry, NULL);
char * helper_get_theme_path(const char *file, const char *ext)
uint32_t rofi_icon_fetcher_query_advanced(const char *name, const int wsize, const int hsize)
gboolean rofi_icon_fetcher_file_is_image(const char *const path)
void rofi_icon_fetcher_destroy(void)
cairo_surface_t * rofi_icon_fetcher_get(const uint32_t uid)
uint32_t rofi_icon_fetcher_query(const char *name, const int size)
void rofi_icon_fetcher_init(void)
void rofi_view_reload(void)
static void rofi_icon_fetch_entry_free(gpointer data)
static void free_wrapper(gpointer data, G_GNUC_UNUSED gpointer user_data)
IconFetcher * rofi_icon_fetcher_data
static guchar alpha_mult(guchar c, guchar a)
static cairo_surface_t * rofi_icon_fetcher_get_surface_from_pixbuf(GdkPixbuf *pixbuf)
static void rofi_icon_fetcher_worker(thread_state *sdata, G_GNUC_UNUSED gpointer user_data)
IconFetcherNameEntry * entry
cairo_surface_t * surface
NkXdgThemeContext * xdg_context
GHashTable * icon_cache_uid
GList * supported_extensions
void(* callback)(struct _thread_state *t, gpointer data)