diff --git a/source/rofi-icon-fetcher.c b/source/rofi-icon-fetcher.c index 57c671d3..43b08d8e 100644 --- a/source/rofi-icon-fetcher.c +++ b/source/rofi-icon-fetcher.c @@ -26,63 +26,61 @@ */ /** The log domain of this Helper. */ -#define G_LOG_DOMAIN "Helpers.IconFetcher" +#define G_LOG_DOMAIN "Helpers.IconFetcher" -#include #include +#include +#include +#include "helper.h" #include "rofi-icon-fetcher.h" #include "rofi-types.h" -#include "helper.h" #include "settings.h" -#include "xcb.h" #include "keyb.h" #include "view.h" +#include "xcb.h" -#include "nkutils-xdg-theme.h" #include "nkutils-enum.h" +#include "nkutils-xdg-theme.h" #include -#include #include "helper.h" +#include -typedef struct -{ - // Context for icon-themes. - NkXdgThemeContext *xdg_context; +typedef struct { + // Context for icon-themes. + NkXdgThemeContext *xdg_context; - // On name. - GHashTable *icon_cache; - // On uid. - GHashTable *icon_cache_uid; + // On name. + GHashTable *icon_cache; + // On uid. + GHashTable *icon_cache_uid; - // list extensions - GList *supported_extensions; - uint32_t last_uid; + // list extensions + GList *supported_extensions; + uint32_t last_uid; } IconFetcher; -typedef struct -{ - char *name; - GList *sizes; +typedef struct { + char *name; + GList *sizes; } IconFetcherNameEntry; -typedef struct -{ - thread_state state; +typedef struct { + thread_state state; - GCond *cond; - GMutex *mutex; - unsigned int *acount; + GCond *cond; + GMutex *mutex; + unsigned int *acount; - uint32_t uid; - int wsize; - int hsize; - cairo_surface_t *surface; + uint32_t uid; + int wsize; + int hsize; + cairo_surface_t *surface; - IconFetcherNameEntry *entry; + IconFetcherNameEntry *entry; } IconFetcherEntry; /** @@ -90,77 +88,76 @@ typedef struct */ IconFetcher *rofi_icon_fetcher_data = NULL; -static void rofi_icon_fetch_entry_free ( gpointer data ) -{ - IconFetcherNameEntry *entry = (IconFetcherNameEntry *) data; +static void rofi_icon_fetch_entry_free(gpointer data) { + IconFetcherNameEntry *entry = (IconFetcherNameEntry *)data; - // Free name/key. - g_free ( entry->name ); + // Free name/key. + g_free(entry->name); - for ( GList *iter = g_list_first ( entry->sizes ); iter; iter = g_list_next ( iter ) ) { - IconFetcherEntry *sentry = (IconFetcherEntry *) ( iter->data ); + for (GList *iter = g_list_first(entry->sizes); iter; + iter = g_list_next(iter)) { + IconFetcherEntry *sentry = (IconFetcherEntry *)(iter->data); - cairo_surface_destroy ( sentry->surface ); - g_free ( sentry ); - } + cairo_surface_destroy(sentry->surface); + g_free(sentry); + } - g_list_free ( entry->sizes ); - g_free ( entry ); + g_list_free(entry->sizes); + g_free(entry); } -void rofi_icon_fetcher_init ( void ) -{ - g_assert ( rofi_icon_fetcher_data == NULL ); +void rofi_icon_fetcher_init(void) { + g_assert(rofi_icon_fetcher_data == NULL); - static const gchar * const icon_fallback_themes[] = { - "Adwaita", - "gnome", - NULL - }; - const char *themes[2] = { config.icon_theme, NULL }; + static const gchar *const icon_fallback_themes[] = {"Adwaita", "gnome", NULL}; + const char *themes[2] = {config.icon_theme, NULL}; - rofi_icon_fetcher_data = g_malloc0 ( sizeof ( IconFetcher ) ); + rofi_icon_fetcher_data = g_malloc0(sizeof(IconFetcher)); - rofi_icon_fetcher_data->xdg_context = nk_xdg_theme_context_new ( icon_fallback_themes, NULL ); - nk_xdg_theme_preload_themes_icon ( rofi_icon_fetcher_data->xdg_context, themes ); + rofi_icon_fetcher_data->xdg_context = + nk_xdg_theme_context_new(icon_fallback_themes, NULL); + nk_xdg_theme_preload_themes_icon(rofi_icon_fetcher_data->xdg_context, themes); - rofi_icon_fetcher_data->icon_cache_uid = g_hash_table_new ( g_direct_hash, g_direct_equal ); - rofi_icon_fetcher_data->icon_cache = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, rofi_icon_fetch_entry_free ); + rofi_icon_fetcher_data->icon_cache_uid = + g_hash_table_new(g_direct_hash, g_direct_equal); + rofi_icon_fetcher_data->icon_cache = g_hash_table_new_full( + g_str_hash, g_str_equal, NULL, rofi_icon_fetch_entry_free); - GSList *l = gdk_pixbuf_get_formats (); - for ( GSList *li = l; li != NULL; li = g_slist_next ( li ) ) { - gchar **exts = gdk_pixbuf_format_get_extensions ( (GdkPixbufFormat *) li->data ); + GSList *l = gdk_pixbuf_get_formats(); + for (GSList *li = l; li != NULL; li = g_slist_next(li)) { + gchar **exts = + gdk_pixbuf_format_get_extensions((GdkPixbufFormat *)li->data); - for ( unsigned int i = 0; exts && exts[i]; i++ ) { - rofi_icon_fetcher_data->supported_extensions = g_list_append ( rofi_icon_fetcher_data->supported_extensions, exts[i] ); - g_info ( "Add image extension: %s", exts[i] ); - exts[i] = NULL; - } - - g_free ( exts ); - } - g_slist_free ( l ); -} - -static void free_wrapper ( gpointer data, G_GNUC_UNUSED gpointer user_data ) -{ - g_free ( data ) ; -} - -void rofi_icon_fetcher_destroy ( void ) -{ - if ( rofi_icon_fetcher_data == NULL ) { - return; + for (unsigned int i = 0; exts && exts[i]; i++) { + rofi_icon_fetcher_data->supported_extensions = + g_list_append(rofi_icon_fetcher_data->supported_extensions, exts[i]); + g_info("Add image extension: %s", exts[i]); + exts[i] = NULL; } - nk_xdg_theme_context_free ( rofi_icon_fetcher_data->xdg_context ); + g_free(exts); + } + g_slist_free(l); +} - g_hash_table_unref ( rofi_icon_fetcher_data->icon_cache_uid ); - g_hash_table_unref ( rofi_icon_fetcher_data->icon_cache ); +static void free_wrapper(gpointer data, G_GNUC_UNUSED gpointer user_data) { + g_free(data); +} - g_list_foreach ( rofi_icon_fetcher_data->supported_extensions, free_wrapper, NULL ); - g_list_free ( rofi_icon_fetcher_data->supported_extensions ); - g_free ( rofi_icon_fetcher_data ); +void rofi_icon_fetcher_destroy(void) { + if (rofi_icon_fetcher_data == NULL) { + return; + } + + nk_xdg_theme_context_free(rofi_icon_fetcher_data->xdg_context); + + g_hash_table_unref(rofi_icon_fetcher_data->icon_cache_uid); + g_hash_table_unref(rofi_icon_fetcher_data->icon_cache); + + g_list_foreach(rofi_icon_fetcher_data->supported_extensions, free_wrapper, + NULL); + g_list_free(rofi_icon_fetcher_data->supported_extensions); + g_free(rofi_icon_fetcher_data); } /* @@ -171,255 +168,256 @@ void rofi_icon_fetcher_destroy ( void ) */ #if G_BYTE_ORDER == G_LITTLE_ENDIAN /** Location of red byte */ -#define RED_BYTE 2 +#define RED_BYTE 2 /** Location of green byte */ -#define GREEN_BYTE 1 +#define GREEN_BYTE 1 /** Location of blue byte */ -#define BLUE_BYTE 0 +#define BLUE_BYTE 0 /** Location of alpha byte */ -#define ALPHA_BYTE 3 +#define ALPHA_BYTE 3 #else /** Location of red byte */ -#define RED_BYTE 1 +#define RED_BYTE 1 /** Location of green byte */ -#define GREEN_BYTE 2 +#define GREEN_BYTE 2 /** Location of blue byte */ -#define BLUE_BYTE 3 +#define BLUE_BYTE 3 /** Location of alpha byte */ -#define ALPHA_BYTE 0 +#define ALPHA_BYTE 0 #endif -static inline guchar alpha_mult ( guchar c, guchar a ) -{ - guint16 t; - switch ( a ) - { - case 0xff: - return c; - case 0x00: - return 0x00; - default: - t = c * a + 0x7f; - return ( ( t >> 8 ) + t ) >> 8; - } +static inline guchar alpha_mult(guchar c, guchar a) { + guint16 t; + switch (a) { + case 0xff: + return c; + case 0x00: + return 0x00; + default: + t = c * a + 0x7f; + return ((t >> 8) + t) >> 8; + } } -static cairo_surface_t * rofi_icon_fetcher_get_surface_from_pixbuf ( GdkPixbuf - *pixbuf ) -{ - gint width, height; - const guchar *pixels; - gint stride; - gboolean alpha; +static cairo_surface_t * +rofi_icon_fetcher_get_surface_from_pixbuf(GdkPixbuf *pixbuf) { + gint width, height; + const guchar *pixels; + gint stride; + gboolean alpha; - if ( pixbuf == NULL ) { - return NULL; - } - - width = gdk_pixbuf_get_width ( pixbuf ); - height = gdk_pixbuf_get_height ( pixbuf ); - pixels = gdk_pixbuf_read_pixels ( pixbuf ); - stride = gdk_pixbuf_get_rowstride ( pixbuf ); - alpha = gdk_pixbuf_get_has_alpha ( pixbuf ); - - cairo_surface_t *surface = NULL; - - gint cstride; - guint lo, o; - guchar a = 0xff; - const guchar *pixels_end, *line; - guchar *cpixels; - - pixels_end = pixels + height * stride; - o = alpha ? 4 : 3; - lo = o * width; - - surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32, width, height ); - cpixels = cairo_image_surface_get_data ( surface ); - cstride = cairo_image_surface_get_stride ( surface ); - - cairo_surface_flush ( surface ); - while ( pixels < pixels_end ) { - line = pixels; - const guchar *line_end = line + lo; - guchar *cline = cpixels; - - while ( line < line_end ) { - if ( alpha ) { - a = line[3]; - } - cline[RED_BYTE] = alpha_mult ( line[0], a ); - cline[GREEN_BYTE] = alpha_mult ( line[1], a ); - cline[BLUE_BYTE] = alpha_mult ( line[2], a ); - cline[ALPHA_BYTE] = a; - - line += o; - cline += 4; - } - - pixels += stride; - cpixels += cstride; - } - cairo_surface_mark_dirty ( surface ); - cairo_surface_flush ( surface ); - - return surface; -} - -gboolean rofi_icon_fetcher_file_is_image ( const char * const path ) -{ - if ( path == NULL ) { - return FALSE; - } - const char *suf = strrchr ( path, '.' ); - if ( suf == NULL ) { - return FALSE; - } - suf++; - - for ( GList *iter = rofi_icon_fetcher_data->supported_extensions; iter != NULL; iter = g_list_next ( iter ) ) { - if ( g_ascii_strcasecmp ( iter->data, suf ) == 0 ) { - return TRUE; - } - } - return FALSE; -} - -static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpointer user_data ) -{ - g_debug ( "starting up icon fetching thread." ); - // as long as dr->icon is updated atomicly.. (is a pointer write atomic?) - // this should be fine running in another thread. - IconFetcherEntry *sentry = (IconFetcherEntry *) sdata; - const gchar *themes[] = { - config.icon_theme, - NULL - }; - - const gchar *icon_path; - gchar *icon_path_ = NULL; - - if ( g_path_is_absolute ( sentry->entry->name ) ) { - icon_path = sentry->entry->name; - } - else { - icon_path = icon_path_ = nk_xdg_theme_get_icon ( rofi_icon_fetcher_data->xdg_context, themes, NULL, sentry->entry->name, MIN(sentry->wsize,sentry->hsize), 1, TRUE ); - if ( icon_path_ == NULL ) { - g_debug ( "failed to get icon %s(%dx%d): n/a", sentry->entry->name, sentry->wsize, sentry->hsize ); - - const char *ext = g_strrstr(sentry->entry->name, "."); - if ( ext ) { -printf("%s %s\r\n", sentry->entry->name, ext); - icon_path = helper_get_theme_path ( sentry->entry->name, ext ); - } - if ( icon_path == NULL ) { - return; - } - } - else{ - g_debug ( "found icon %s(%dx%d): %s", sentry->entry->name, sentry->wsize, sentry->hsize, icon_path ); - } - } - cairo_surface_t *icon_surf = NULL; - - const char *suf = strrchr ( icon_path, '.' ); - if ( suf == NULL ) { - return; - } - - GError *error = NULL; - GdkPixbuf *pb = gdk_pixbuf_new_from_file_at_scale ( icon_path, sentry->wsize, sentry->hsize, TRUE, &error ); - if ( error != NULL ) { - g_warning ( "Failed to load image: %s", error->message ); - g_error_free ( error ); - if ( pb ) { - g_object_unref ( pb ); - } - } - else { - icon_surf = rofi_icon_fetcher_get_surface_from_pixbuf ( pb ); - g_object_unref ( pb ); - } - - sentry->surface = icon_surf; - g_free ( icon_path_ ); - rofi_view_reload (); -} - -uint32_t rofi_icon_fetcher_query_advanced ( const char *name, const int wsize, const int hsize ) -{ - g_debug ( "Query: %s(%dx%d)", name, wsize, hsize ); - IconFetcherNameEntry *entry = g_hash_table_lookup ( rofi_icon_fetcher_data->icon_cache, name ); - if ( entry == NULL ) { - entry = g_new0 ( IconFetcherNameEntry, 1 ); - entry->name = g_strdup ( name ); - g_hash_table_insert ( rofi_icon_fetcher_data->icon_cache, entry->name, entry ); - } - IconFetcherEntry *sentry; - for ( GList *iter = g_list_first ( entry->sizes ); iter; iter = g_list_next ( iter ) ) { - sentry = iter->data; - if ( sentry->wsize == wsize && sentry->hsize == hsize ) { - return sentry->uid; - } - } - - // Not found. - sentry = g_new0 ( IconFetcherEntry, 1 ); - sentry->uid = ++( rofi_icon_fetcher_data->last_uid ); - sentry->wsize = wsize; - sentry->hsize = hsize; - sentry->entry = entry; - sentry->surface = NULL; - - entry->sizes = g_list_prepend ( entry->sizes, sentry ); - g_hash_table_insert ( rofi_icon_fetcher_data->icon_cache_uid, GINT_TO_POINTER ( sentry->uid ), sentry ); - - // Push into fetching queue. - sentry->state.callback = rofi_icon_fetcher_worker; - g_thread_pool_push ( tpool, sentry, NULL ); - - return sentry->uid; -} -uint32_t rofi_icon_fetcher_query ( const char *name, const int size ) -{ - g_debug ( "Query: %s(%d)", name, size ); - IconFetcherNameEntry *entry = g_hash_table_lookup ( rofi_icon_fetcher_data->icon_cache, name ); - if ( entry == NULL ) { - entry = g_new0 ( IconFetcherNameEntry, 1 ); - entry->name = g_strdup ( name ); - g_hash_table_insert ( rofi_icon_fetcher_data->icon_cache, entry->name, entry ); - } - IconFetcherEntry *sentry; - for ( GList *iter = g_list_first ( entry->sizes ); iter; iter = g_list_next ( iter ) ) { - sentry = iter->data; - if ( sentry->wsize == size && sentry->hsize == size ) { - return sentry->uid; - } - } - - // Not found. - sentry = g_new0 ( IconFetcherEntry, 1 ); - sentry->uid = ++( rofi_icon_fetcher_data->last_uid ); - sentry->wsize = size; - sentry->hsize = size; - sentry->entry = entry; - sentry->surface = NULL; - - entry->sizes = g_list_prepend ( entry->sizes, sentry ); - g_hash_table_insert ( rofi_icon_fetcher_data->icon_cache_uid, GINT_TO_POINTER ( sentry->uid ), sentry ); - - // Push into fetching queue. - sentry->state.callback = rofi_icon_fetcher_worker; - g_thread_pool_push ( tpool, sentry, NULL ); - - return sentry->uid; -} - -cairo_surface_t * rofi_icon_fetcher_get ( const uint32_t uid ) -{ - IconFetcherEntry *sentry = g_hash_table_lookup ( rofi_icon_fetcher_data->icon_cache_uid, GINT_TO_POINTER ( uid ) ); - if ( sentry ) { - return sentry->surface; - } + if (pixbuf == NULL) { return NULL; + } + + width = gdk_pixbuf_get_width(pixbuf); + height = gdk_pixbuf_get_height(pixbuf); + pixels = gdk_pixbuf_read_pixels(pixbuf); + stride = gdk_pixbuf_get_rowstride(pixbuf); + alpha = gdk_pixbuf_get_has_alpha(pixbuf); + + cairo_surface_t *surface = NULL; + + gint cstride; + guint lo, o; + guchar a = 0xff; + const guchar *pixels_end, *line; + guchar *cpixels; + + pixels_end = pixels + height * stride; + o = alpha ? 4 : 3; + lo = o * width; + + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + cpixels = cairo_image_surface_get_data(surface); + cstride = cairo_image_surface_get_stride(surface); + + cairo_surface_flush(surface); + while (pixels < pixels_end) { + line = pixels; + const guchar *line_end = line + lo; + guchar *cline = cpixels; + + while (line < line_end) { + if (alpha) { + a = line[3]; + } + cline[RED_BYTE] = alpha_mult(line[0], a); + cline[GREEN_BYTE] = alpha_mult(line[1], a); + cline[BLUE_BYTE] = alpha_mult(line[2], a); + cline[ALPHA_BYTE] = a; + + line += o; + cline += 4; + } + + pixels += stride; + cpixels += cstride; + } + cairo_surface_mark_dirty(surface); + cairo_surface_flush(surface); + + return surface; +} + +gboolean rofi_icon_fetcher_file_is_image(const char *const path) { + if (path == NULL) { + return FALSE; + } + const char *suf = strrchr(path, '.'); + if (suf == NULL) { + return FALSE; + } + suf++; + + for (GList *iter = rofi_icon_fetcher_data->supported_extensions; iter != NULL; + iter = g_list_next(iter)) { + if (g_ascii_strcasecmp(iter->data, suf) == 0) { + return TRUE; + } + } + return FALSE; +} + +static void rofi_icon_fetcher_worker(thread_state *sdata, + G_GNUC_UNUSED gpointer user_data) { + g_debug("starting up icon fetching thread."); + // as long as dr->icon is updated atomicly.. (is a pointer write atomic?) + // this should be fine running in another thread. + IconFetcherEntry *sentry = (IconFetcherEntry *)sdata; + const gchar *themes[] = {config.icon_theme, NULL}; + + const gchar *icon_path; + gchar *icon_path_ = NULL; + + if (g_path_is_absolute(sentry->entry->name)) { + icon_path = sentry->entry->name; + } else { + icon_path = icon_path_ = nk_xdg_theme_get_icon( + rofi_icon_fetcher_data->xdg_context, themes, NULL, sentry->entry->name, + MIN(sentry->wsize, sentry->hsize), 1, TRUE); + if (icon_path_ == NULL) { + g_debug("failed to get icon %s(%dx%d): n/a", sentry->entry->name, + sentry->wsize, sentry->hsize); + + const char *ext = g_strrstr(sentry->entry->name, "."); + if (ext) { + printf("%s %s\r\n", sentry->entry->name, ext); + icon_path = helper_get_theme_path(sentry->entry->name, ext); + } + if (icon_path == NULL) { + return; + } + } else { + g_debug("found icon %s(%dx%d): %s", sentry->entry->name, sentry->wsize, + sentry->hsize, icon_path); + } + } + cairo_surface_t *icon_surf = NULL; + + const char *suf = strrchr(icon_path, '.'); + if (suf == NULL) { + return; + } + + GError *error = NULL; + GdkPixbuf *pb = gdk_pixbuf_new_from_file_at_scale( + icon_path, sentry->wsize, sentry->hsize, TRUE, &error); + if (error != NULL) { + g_warning("Failed to load image: %s", error->message); + g_error_free(error); + if (pb) { + g_object_unref(pb); + } + } else { + icon_surf = rofi_icon_fetcher_get_surface_from_pixbuf(pb); + g_object_unref(pb); + } + + sentry->surface = icon_surf; + g_free(icon_path_); + rofi_view_reload(); +} + +uint32_t rofi_icon_fetcher_query_advanced(const char *name, const int wsize, + const int hsize) { + g_debug("Query: %s(%dx%d)", name, wsize, hsize); + IconFetcherNameEntry *entry = + g_hash_table_lookup(rofi_icon_fetcher_data->icon_cache, name); + if (entry == NULL) { + entry = g_new0(IconFetcherNameEntry, 1); + entry->name = g_strdup(name); + g_hash_table_insert(rofi_icon_fetcher_data->icon_cache, entry->name, entry); + } + IconFetcherEntry *sentry; + for (GList *iter = g_list_first(entry->sizes); iter; + iter = g_list_next(iter)) { + sentry = iter->data; + if (sentry->wsize == wsize && sentry->hsize == hsize) { + return sentry->uid; + } + } + + // Not found. + sentry = g_new0(IconFetcherEntry, 1); + sentry->uid = ++(rofi_icon_fetcher_data->last_uid); + sentry->wsize = wsize; + sentry->hsize = hsize; + sentry->entry = entry; + sentry->surface = NULL; + + entry->sizes = g_list_prepend(entry->sizes, sentry); + g_hash_table_insert(rofi_icon_fetcher_data->icon_cache_uid, + GINT_TO_POINTER(sentry->uid), sentry); + + // Push into fetching queue. + sentry->state.callback = rofi_icon_fetcher_worker; + g_thread_pool_push(tpool, sentry, NULL); + + return sentry->uid; +} +uint32_t rofi_icon_fetcher_query(const char *name, const int size) { + g_debug("Query: %s(%d)", name, size); + IconFetcherNameEntry *entry = + g_hash_table_lookup(rofi_icon_fetcher_data->icon_cache, name); + if (entry == NULL) { + entry = g_new0(IconFetcherNameEntry, 1); + entry->name = g_strdup(name); + g_hash_table_insert(rofi_icon_fetcher_data->icon_cache, entry->name, entry); + } + IconFetcherEntry *sentry; + for (GList *iter = g_list_first(entry->sizes); iter; + iter = g_list_next(iter)) { + sentry = iter->data; + if (sentry->wsize == size && sentry->hsize == size) { + return sentry->uid; + } + } + + // Not found. + sentry = g_new0(IconFetcherEntry, 1); + sentry->uid = ++(rofi_icon_fetcher_data->last_uid); + sentry->wsize = size; + sentry->hsize = size; + sentry->entry = entry; + sentry->surface = NULL; + + entry->sizes = g_list_prepend(entry->sizes, sentry); + g_hash_table_insert(rofi_icon_fetcher_data->icon_cache_uid, + GINT_TO_POINTER(sentry->uid), sentry); + + // Push into fetching queue. + sentry->state.callback = rofi_icon_fetcher_worker; + g_thread_pool_push(tpool, sentry, NULL); + + return sentry->uid; +} + +cairo_surface_t *rofi_icon_fetcher_get(const uint32_t uid) { + IconFetcherEntry *sentry = g_hash_table_lookup( + rofi_icon_fetcher_data->icon_cache_uid, GINT_TO_POINTER(uid)); + if (sentry) { + return sentry->surface; + } + return NULL; }