Load symbolic icons as a fallback

Now there are no missing items in the browsers.
This commit is contained in:
Přemysl Eric Janouch 2021-11-20 12:19:09 +01:00
parent 6eb78f1a5c
commit 3e9a388537
Signed by: p
GPG Key ID: A0420B94F92B9493
2 changed files with 91 additions and 9 deletions

View File

@ -67,6 +67,7 @@ static const int g_item_spacing = 1;
struct entry {
char *filename; ///< Absolute path
cairo_surface_t *thumbnail; ///< Prescaled thumbnail
GIcon *icon; ///< If no thumbnail, use this icon
};
static void
@ -75,6 +76,7 @@ entry_free(Entry *self)
g_free(self->filename);
if (self->thumbnail)
cairo_surface_destroy(self->thumbnail);
g_clear_object(&self->icon);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -244,10 +246,15 @@ draw_row(FastivBrowser *self, cairo_t *cr, const Row *row)
GdkRectangle extents = item_extents(item, row);
cairo_translate(cr, extents.x - border.left, extents.y - border.top);
gdk_cairo_set_source_rgba(cr, &glow_color);
draw_outer_border(self, cr,
border.left + extents.width + border.right,
border.top + extents.height + border.bottom);
gtk_style_context_save(style);
if (item->entry->icon) {
gtk_style_context_add_class(style, "symbolic");
} else {
gdk_cairo_set_source_rgba(cr, &glow_color);
draw_outer_border(self, cr,
border.left + extents.width + border.right,
border.top + extents.height + border.bottom);
}
gtk_render_background(
style, cr, border.left, border.top, extents.width, extents.height);
@ -256,10 +263,20 @@ draw_row(FastivBrowser *self, cairo_t *cr, const Row *row)
border.left + extents.width + border.right,
border.top + extents.height + border.bottom);
cairo_set_source_surface(
cr, item->entry->thumbnail, border.left, border.top);
cairo_paint(cr);
if (item->entry->icon) {
GdkRGBA color = {};
gtk_style_context_get_color(style, state, &color);
gdk_cairo_set_source_rgba(cr, &color);
cairo_mask_surface(
cr, item->entry->thumbnail, border.left, border.top);
} else {
cairo_set_source_surface(
cr, item->entry->thumbnail, border.left, border.top);
cairo_paint(cr);
}
cairo_restore(cr);
gtk_style_context_restore(style);
}
gtk_style_context_restore(style);
}
@ -590,6 +607,23 @@ entry_add_thumbnail(gpointer data, G_GNUC_UNUSED gpointer user_data)
Entry *self = data;
self->thumbnail =
rescale_thumbnail(fastiv_io_lookup_thumbnail(self->filename));
if (self->thumbnail)
return;
// Fall back to symbolic icons, though there's only so much we can do
// in parallel--GTK+ isn't thread-safe.
GFile *file = g_file_new_for_path(self->filename);
GFileInfo *info = g_file_query_info(file,
G_FILE_ATTRIBUTE_STANDARD_NAME
"," G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON,
G_FILE_QUERY_INFO_NONE, NULL, NULL);
g_object_unref(file);
if (info) {
GIcon *icon = g_file_info_get_symbolic_icon(info);
if (icon)
self->icon = g_object_ref(icon);
g_object_unref(info);
}
}
void
@ -619,6 +653,50 @@ fastiv_browser_load(FastivBrowser *self, const char *path)
g_thread_pool_push(pool, &g_array_index(self->entries, Entry, i), NULL);
g_thread_pool_free(pool, FALSE, TRUE);
// TODO(p): Sort the entries.
for (guint i = 0; i < self->entries->len; i++) {
Entry *entry = &g_array_index(self->entries, Entry, i);
if (!entry->icon)
continue;
// Fucker will still give us non-symbolic icons, no more playing nice.
// TODO(p): Investigate a bit closer. We may want to abandon the idea
// of using GLib to look up icons for us, derive a list from a guessed
// MIME type, with "-symbolic" prefixes and fallbacks,
// and use gtk_icon_theme_choose_icon() instead.
// TODO(p): Make sure we have /some/ icon for every entry.
// TODO(p): GtkSettings -> notify::gtk-icon-theme-name?
// TODO(p): We might want to populate these on an as-needed basis.
GtkIconInfo *icon_info =
gtk_icon_theme_lookup_by_gicon(gtk_icon_theme_get_default(),
entry->icon, g_row_height / 2, GTK_ICON_LOOKUP_FORCE_SYMBOLIC);
if (!icon_info)
continue;
// Bílá, bílá, bílá, bílá... komu by se nelíbí-lá...
// We do not want any highlights, nor do we want to remember the style.
const GdkRGBA white = {1, 1, 1, 1};
GdkPixbuf *pixbuf = gtk_icon_info_load_symbolic(
icon_info, &white, &white, &white, &white, NULL, NULL);
if (pixbuf) {
int outer_size = g_row_height;
entry->thumbnail = cairo_image_surface_create(
CAIRO_FORMAT_A8, outer_size, outer_size);
// "Note that the resulting pixbuf may not be exactly this size;"
// though GTK_ICON_LOOKUP_FORCE_SIZE is also an option.
int x = (outer_size - gdk_pixbuf_get_width(pixbuf)) / 2;
int y = (outer_size - gdk_pixbuf_get_height(pixbuf)) / 2;
cairo_t *cr = cairo_create(entry->thumbnail);
gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
cairo_paint(cr);
cairo_destroy(cr);
g_object_unref(pixbuf);
}
g_object_unref(icon_info);
}
// TODO(p): Sort and filter the entries.
gtk_widget_queue_resize(GTK_WIDGET(self));
}

View File

@ -489,7 +489,7 @@ main(int argc, char *argv[])
fastiv-view, fastiv-browser { background: #222; } \
fastiv-browser { padding: 5px; } \
fastiv-browser.item { \
border: 1px solid rgba(255, 255, 255, 0.5); \
border: 1px solid rgba(255, 255, 255, 0.375); \
margin: 10px; color: #000; \
background: #333; \
background-image: \
@ -499,6 +499,10 @@ main(int argc, char *argv[])
linear-gradient(-45deg, transparent 74%, @fastiv-tile 74%); \
background-size: 40px 40px; \
background-position: 0 0, 0 20px, 20px -20px, -20px 0px; \
} \
fastiv-browser.item.symbolic { \
border-color: transparent; color: #222; \
background: #2c2c2c; background-image: none; \
}";
GtkCssProvider *provider = gtk_css_provider_new();