From bb522579128a6e8572816207baa7ed8ec4b54f7e Mon Sep 17 00:00:00 2001 From: Michael Webster Date: Fri, 20 Feb 2026 09:35:09 -0500 Subject: [PATCH 1/3] emblems: Implement internally instead of relying on Gtk for placement and sizing. Emblem sizes in Gtk are calculated as a fraction of the size of the image being emblemed. At various zoom levels we either have to suppress the emblems altogether (when an image is too short or narrow to overlay it) or they end up covering a large portion of the image with larger sizes. --- libnemo-private/meson.build | 2 + libnemo-private/nemo-emblem.c | 136 +++++++++++++++++++++ libnemo-private/nemo-emblem.h | 51 ++++++++ libnemo-private/nemo-emblemed-icon.c | 171 ++++++++++++++++++++++++++ libnemo-private/nemo-emblemed-icon.h | 37 ++++++ libnemo-private/nemo-icon-info.c | 174 +++++++++++++++++++++++++++ src/nemo-icon-view-container.c | 57 ++------- src/nemo-icon-view-grid-container.c | 59 +++------ src/nemo-list-model.c | 30 ++--- src/nemo-tree-sidebar-model.c | 41 ++++--- 10 files changed, 627 insertions(+), 131 deletions(-) create mode 100644 libnemo-private/nemo-emblem.c create mode 100644 libnemo-private/nemo-emblem.h create mode 100644 libnemo-private/nemo-emblemed-icon.c create mode 100644 libnemo-private/nemo-emblemed-icon.h diff --git a/libnemo-private/meson.build b/libnemo-private/meson.build index 16c0618827..d31c3a39d5 100644 --- a/libnemo-private/meson.build +++ b/libnemo-private/meson.build @@ -30,6 +30,8 @@ nemo_private_sources = [ 'nemo-directory-async.c', 'nemo-directory.c', 'nemo-dnd.c', + 'nemo-emblem.c', + 'nemo-emblemed-icon.c', 'nemo-entry.c', 'nemo-file-changes-queue.c', 'nemo-file-conflict-dialog.c', diff --git a/libnemo-private/nemo-emblem.c b/libnemo-private/nemo-emblem.c new file mode 100644 index 0000000000..cab47fe3cd --- /dev/null +++ b/libnemo-private/nemo-emblem.c @@ -0,0 +1,136 @@ +/* nemo-emblem.c - Custom emblem with size and position control + * + * Copyright (C) 2026 Linux Mint + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + +#include +#include "nemo-emblem.h" + +struct _NemoEmblem { + GObject parent_instance; + + GIcon *icon; + NemoEmblemSize size; + NemoEmblemPosition position; +}; + +static void nemo_emblem_icon_iface_init (GIconIface *iface); + +G_DEFINE_TYPE_WITH_CODE (NemoEmblem, nemo_emblem, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ICON, nemo_emblem_icon_iface_init)) + +static void +nemo_emblem_finalize (GObject *object) +{ + NemoEmblem *emblem = NEMO_EMBLEM (object); + + g_clear_object (&emblem->icon); + + G_OBJECT_CLASS (nemo_emblem_parent_class)->finalize (object); +} + +static guint +nemo_emblem_hash (GIcon *icon) +{ + NemoEmblem *emblem = NEMO_EMBLEM (icon); + + return g_icon_hash (emblem->icon) ^ (emblem->size << 8) ^ (emblem->position << 16); +} + +static gboolean +nemo_emblem_equal (GIcon *icon1, GIcon *icon2) +{ + NemoEmblem *a = NEMO_EMBLEM (icon1); + NemoEmblem *b = NEMO_EMBLEM (icon2); + + return g_icon_equal (a->icon, b->icon) && + a->size == b->size && + a->position == b->position; +} + +static GVariant * +nemo_emblem_serialize (GIcon *icon) +{ + NemoEmblem *emblem = NEMO_EMBLEM (icon); + GVariant *inner; + + inner = g_icon_serialize (emblem->icon); + if (inner == NULL) { + return NULL; + } + + GVariant *result = g_variant_new ("(vii)", inner, (gint32) emblem->size, (gint32) emblem->position); + return result; +} + +static void +nemo_emblem_icon_iface_init (GIconIface *iface) +{ + iface->hash = nemo_emblem_hash; + iface->equal = nemo_emblem_equal; + iface->serialize = nemo_emblem_serialize; +} + +static void +nemo_emblem_class_init (NemoEmblemClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = nemo_emblem_finalize; +} + +static void +nemo_emblem_init (NemoEmblem *emblem) +{ +} + +NemoEmblem * +nemo_emblem_new (GIcon *icon, + NemoEmblemSize size, + NemoEmblemPosition position) +{ + NemoEmblem *emblem; + + g_return_val_if_fail (G_IS_ICON (icon), NULL); + + emblem = g_object_new (NEMO_TYPE_EMBLEM, NULL); + emblem->icon = g_object_ref (icon); + emblem->size = size; + emblem->position = position; + + return emblem; +} + +GIcon * +nemo_emblem_get_icon (NemoEmblem *emblem) +{ + g_return_val_if_fail (NEMO_IS_EMBLEM (emblem), NULL); + + return emblem->icon; +} + +NemoEmblemSize +nemo_emblem_get_size (NemoEmblem *emblem) +{ + g_return_val_if_fail (NEMO_IS_EMBLEM (emblem), NEMO_EMBLEM_SIZE_SMALL); + + return emblem->size; +} + +NemoEmblemPosition +nemo_emblem_get_position (NemoEmblem *emblem) +{ + g_return_val_if_fail (NEMO_IS_EMBLEM (emblem), NEMO_EMBLEM_POSITION_DEFAULT); + + return emblem->position; +} diff --git a/libnemo-private/nemo-emblem.h b/libnemo-private/nemo-emblem.h new file mode 100644 index 0000000000..22d5bd2357 --- /dev/null +++ b/libnemo-private/nemo-emblem.h @@ -0,0 +1,51 @@ +/* nemo-emblem.h - Custom emblem with size and position control + * + * Copyright (C) 2026 Linux Mint + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + +#ifndef NEMO_EMBLEM_H +#define NEMO_EMBLEM_H + +#include + +G_BEGIN_DECLS + +typedef enum { + NEMO_EMBLEM_SIZE_EXTRA_SMALL, /* ~15% of icon size */ + NEMO_EMBLEM_SIZE_SMALL, /* ~25% of icon size */ + NEMO_EMBLEM_SIZE_MEDIUM, /* ~33% of icon size */ + NEMO_EMBLEM_SIZE_LARGE /* ~50% of icon size */ +} NemoEmblemSize; + +typedef enum { + NEMO_EMBLEM_POSITION_DEFAULT, /* auto-assign: cycles LR -> LL -> UR -> UL */ + NEMO_EMBLEM_POSITION_UPPER_LEFT, + NEMO_EMBLEM_POSITION_UPPER_RIGHT, + NEMO_EMBLEM_POSITION_LOWER_LEFT, + NEMO_EMBLEM_POSITION_LOWER_RIGHT +} NemoEmblemPosition; + +#define NEMO_TYPE_EMBLEM (nemo_emblem_get_type ()) + +G_DECLARE_FINAL_TYPE (NemoEmblem, nemo_emblem, NEMO, EMBLEM, GObject) + +NemoEmblem * nemo_emblem_new (GIcon *icon, + NemoEmblemSize size, + NemoEmblemPosition position); +GIcon * nemo_emblem_get_icon (NemoEmblem *emblem); +NemoEmblemSize nemo_emblem_get_size (NemoEmblem *emblem); +NemoEmblemPosition nemo_emblem_get_position (NemoEmblem *emblem); + +G_END_DECLS + +#endif /* NEMO_EMBLEM_H */ diff --git a/libnemo-private/nemo-emblemed-icon.c b/libnemo-private/nemo-emblemed-icon.c new file mode 100644 index 0000000000..c95f6bb17d --- /dev/null +++ b/libnemo-private/nemo-emblemed-icon.c @@ -0,0 +1,171 @@ +/* nemo-emblemed-icon.c - Icon with custom emblem compositing + * + * Copyright (C) 2026 Linux Mint + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + +#include +#include "nemo-emblemed-icon.h" + +struct _NemoEmblemedIcon { + GObject parent_instance; + + GIcon *icon; + GList *emblems; +}; + +static void nemo_emblemed_icon_icon_iface_init (GIconIface *iface); + +G_DEFINE_TYPE_WITH_CODE (NemoEmblemedIcon, nemo_emblemed_icon, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ICON, nemo_emblemed_icon_icon_iface_init)) + +static void +nemo_emblemed_icon_finalize (GObject *object) +{ + NemoEmblemedIcon *self = NEMO_EMBLEMED_ICON (object); + + g_clear_object (&self->icon); + g_list_free_full (self->emblems, g_object_unref); + + G_OBJECT_CLASS (nemo_emblemed_icon_parent_class)->finalize (object); +} + +static guint +nemo_emblemed_icon_hash (GIcon *icon) +{ + NemoEmblemedIcon *self = NEMO_EMBLEMED_ICON (icon); + guint hash; + GList *l; + + hash = g_icon_hash (self->icon); + + for (l = self->emblems; l != NULL; l = l->next) { + hash ^= g_icon_hash (G_ICON (l->data)); + } + + return hash; +} + +static gboolean +nemo_emblemed_icon_equal (GIcon *icon1, GIcon *icon2) +{ + NemoEmblemedIcon *a = NEMO_EMBLEMED_ICON (icon1); + NemoEmblemedIcon *b = NEMO_EMBLEMED_ICON (icon2); + GList *la, *lb; + + if (!g_icon_equal (a->icon, b->icon)) { + return FALSE; + } + + if (g_list_length (a->emblems) != g_list_length (b->emblems)) { + return FALSE; + } + + for (la = a->emblems, lb = b->emblems; la != NULL; la = la->next, lb = lb->next) { + if (!g_icon_equal (G_ICON (la->data), G_ICON (lb->data))) { + return FALSE; + } + } + + return TRUE; +} + +static GVariant * +nemo_emblemed_icon_serialize (GIcon *icon) +{ + NemoEmblemedIcon *self = NEMO_EMBLEMED_ICON (icon); + GVariantBuilder builder; + GVariant *inner; + GList *l; + + inner = g_icon_serialize (self->icon); + if (inner == NULL) { + return NULL; + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("av")); + + for (l = self->emblems; l != NULL; l = l->next) { + GVariant *emblem_v = g_icon_serialize (G_ICON (l->data)); + if (emblem_v != NULL) { + g_variant_builder_add (&builder, "v", emblem_v); + } + } + + return g_variant_new ("(vav)", inner, &builder); +} + +static void +nemo_emblemed_icon_icon_iface_init (GIconIface *iface) +{ + iface->hash = nemo_emblemed_icon_hash; + iface->equal = nemo_emblemed_icon_equal; + iface->serialize = nemo_emblemed_icon_serialize; +} + +static void +nemo_emblemed_icon_class_init (NemoEmblemedIconClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = nemo_emblemed_icon_finalize; +} + +static void +nemo_emblemed_icon_init (NemoEmblemedIcon *self) +{ +} + +GIcon * +nemo_emblemed_icon_new (GIcon *icon, + NemoEmblem *emblem) +{ + NemoEmblemedIcon *self; + + g_return_val_if_fail (G_IS_ICON (icon), NULL); + + self = g_object_new (NEMO_TYPE_EMBLEMED_ICON, NULL); + self->icon = g_object_ref (icon); + + if (emblem != NULL) { + self->emblems = g_list_append (self->emblems, g_object_ref (emblem)); + } + + return G_ICON (self); +} + +void +nemo_emblemed_icon_add_emblem (NemoEmblemedIcon *emblemed_icon, + NemoEmblem *emblem) +{ + g_return_if_fail (NEMO_IS_EMBLEMED_ICON (emblemed_icon)); + g_return_if_fail (NEMO_IS_EMBLEM (emblem)); + + emblemed_icon->emblems = g_list_append (emblemed_icon->emblems, + g_object_ref (emblem)); +} + +GIcon * +nemo_emblemed_icon_get_icon (NemoEmblemedIcon *emblemed_icon) +{ + g_return_val_if_fail (NEMO_IS_EMBLEMED_ICON (emblemed_icon), NULL); + + return emblemed_icon->icon; +} + +GList * +nemo_emblemed_icon_get_emblems (NemoEmblemedIcon *emblemed_icon) +{ + g_return_val_if_fail (NEMO_IS_EMBLEMED_ICON (emblemed_icon), NULL); + + return emblemed_icon->emblems; +} diff --git a/libnemo-private/nemo-emblemed-icon.h b/libnemo-private/nemo-emblemed-icon.h new file mode 100644 index 0000000000..6db626efcc --- /dev/null +++ b/libnemo-private/nemo-emblemed-icon.h @@ -0,0 +1,37 @@ +/* nemo-emblemed-icon.h - Icon with custom emblem compositing + * + * Copyright (C) 2026 Linux Mint + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + +#ifndef NEMO_EMBLEMED_ICON_H +#define NEMO_EMBLEMED_ICON_H + +#include +#include "nemo-emblem.h" + +G_BEGIN_DECLS + +#define NEMO_TYPE_EMBLEMED_ICON (nemo_emblemed_icon_get_type ()) + +G_DECLARE_FINAL_TYPE (NemoEmblemedIcon, nemo_emblemed_icon, NEMO, EMBLEMED_ICON, GObject) + +GIcon * nemo_emblemed_icon_new (GIcon *icon, + NemoEmblem *emblem); +void nemo_emblemed_icon_add_emblem (NemoEmblemedIcon *emblemed_icon, + NemoEmblem *emblem); +GIcon * nemo_emblemed_icon_get_icon (NemoEmblemedIcon *emblemed_icon); +GList * nemo_emblemed_icon_get_emblems (NemoEmblemedIcon *emblemed_icon); + +G_END_DECLS + +#endif /* NEMO_EMBLEMED_ICON_H */ diff --git a/libnemo-private/nemo-icon-info.c b/libnemo-private/nemo-icon-info.c index 5be1c35ee4..6c6f41578f 100644 --- a/libnemo-private/nemo-icon-info.c +++ b/libnemo-private/nemo-icon-info.c @@ -23,6 +23,7 @@ #include "nemo-icon-info.h" #include "nemo-icon-names.h" #include "nemo-default-file-icon.h" +#include "nemo-emblemed-icon.h" #include #include @@ -283,6 +284,175 @@ icon_key_free (IconKey *key) g_free (key); } +static gdouble +nemo_emblem_size_get_ratio (NemoEmblemSize size) +{ + switch (size) { + case NEMO_EMBLEM_SIZE_EXTRA_SMALL: + return 0.15; + case NEMO_EMBLEM_SIZE_SMALL: + return 0.25; + case NEMO_EMBLEM_SIZE_MEDIUM: + return 0.33; + case NEMO_EMBLEM_SIZE_LARGE: + return 0.50; + default: + return 0.25; + } +} + +static NemoEmblemPosition +auto_position_order[] = { + NEMO_EMBLEM_POSITION_LOWER_RIGHT, + NEMO_EMBLEM_POSITION_LOWER_LEFT, + NEMO_EMBLEM_POSITION_UPPER_RIGHT, + NEMO_EMBLEM_POSITION_UPPER_LEFT, +}; + +static NemoIconInfo * +nemo_icon_info_lookup_emblemed (NemoEmblemedIcon *emblemed_icon, + int size, + int scale) +{ + GIcon *base_icon; + GList *emblems, *l; + NemoIconInfo *base_info; + GdkPixbuf *base_pixbuf, *result_pixbuf; + gint base_w, base_h, canvas_w, canvas_h, pad_x, pad_y; + gboolean corners_taken[5] = { FALSE }; + gint auto_idx = 0; + gint max_emblem_px = 0; + + base_icon = nemo_emblemed_icon_get_icon (emblemed_icon); + base_info = nemo_icon_info_lookup (base_icon, size, scale); + base_pixbuf = nemo_icon_info_get_pixbuf (base_info); + nemo_icon_info_unref (base_info); + + base_w = gdk_pixbuf_get_width (base_pixbuf); + base_h = gdk_pixbuf_get_height (base_pixbuf); + + emblems = nemo_emblemed_icon_get_emblems (emblemed_icon); + + for (l = emblems; l != NULL; l = l->next) { + NemoEmblem *emblem = NEMO_EMBLEM (l->data); + gdouble ratio = nemo_emblem_size_get_ratio (nemo_emblem_get_size (emblem)); + gint epx = MAX ((gint)(MAX (base_w, base_h) * ratio), 8); + if (epx > max_emblem_px) { + max_emblem_px = epx; + } + corners_taken[nemo_emblem_get_position (emblem)] = TRUE; + } + + pad_x = max_emblem_px > base_w ? (max_emblem_px - base_w + 1) / 2 : 0; + pad_y = max_emblem_px > base_h ? (max_emblem_px - base_h + 1) / 2 : 0; + + canvas_w = base_w + pad_x * 2; + canvas_h = base_h + pad_y * 2; + + result_pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (base_pixbuf), + TRUE, + gdk_pixbuf_get_bits_per_sample (base_pixbuf), + canvas_w, canvas_h); + gdk_pixbuf_fill (result_pixbuf, 0x00000000); + + gdk_pixbuf_copy_area (base_pixbuf, 0, 0, base_w, base_h, + result_pixbuf, pad_x, pad_y); + g_object_unref (base_pixbuf); + + for (l = emblems; l != NULL; l = l->next) { + NemoEmblem *emblem = NEMO_EMBLEM (l->data); + GIcon *emblem_icon; + NemoEmblemPosition pos; + gdouble ratio; + gint emblem_px, dest_x, dest_y; + GtkIconTheme *icon_theme; + GtkIconInfo *emblem_gtkicon; + GdkPixbuf *emblem_pixbuf; + + emblem_icon = nemo_emblem_get_icon (emblem); + pos = nemo_emblem_get_position (emblem); + + if (pos == NEMO_EMBLEM_POSITION_DEFAULT) { + while (auto_idx < 4 && corners_taken[auto_position_order[auto_idx]]) { + auto_idx++; + } + + if (auto_idx < 4) { + pos = auto_position_order[auto_idx]; + corners_taken[pos] = TRUE; + auto_idx++; + } else { + pos = NEMO_EMBLEM_POSITION_LOWER_RIGHT; + } + } + + ratio = nemo_emblem_size_get_ratio (nemo_emblem_get_size (emblem)); + emblem_px = MAX ((gint)(MAX (base_w, base_h) * ratio), 8); + + icon_theme = gtk_icon_theme_get_default (); + emblem_gtkicon = gtk_icon_theme_lookup_by_gicon_for_scale (icon_theme, + emblem_icon, + emblem_px / scale, + scale, + GTK_ICON_LOOKUP_FORCE_SIZE); + if (emblem_gtkicon == NULL) { + continue; + } + + emblem_pixbuf = gtk_icon_info_load_icon (emblem_gtkicon, NULL); + g_object_unref (emblem_gtkicon); + + if (emblem_pixbuf == NULL) { + continue; + } + + gint ew = gdk_pixbuf_get_width (emblem_pixbuf); + gint eh = gdk_pixbuf_get_height (emblem_pixbuf); + + switch (pos) { + case NEMO_EMBLEM_POSITION_LOWER_RIGHT: + dest_x = canvas_w - ew; + dest_y = canvas_h - eh; + break; + case NEMO_EMBLEM_POSITION_LOWER_LEFT: + dest_x = 0; + dest_y = canvas_h - eh; + break; + case NEMO_EMBLEM_POSITION_UPPER_RIGHT: + dest_x = canvas_w - ew; + dest_y = 0; + break; + case NEMO_EMBLEM_POSITION_UPPER_LEFT: + dest_x = 0; + dest_y = 0; + break; + default: + dest_x = canvas_w - ew; + dest_y = canvas_h - eh; + break; + } + + dest_x = MAX (dest_x, 0); + dest_y = MAX (dest_y, 0); + + gdk_pixbuf_composite (emblem_pixbuf, result_pixbuf, + dest_x, dest_y, + MIN (ew, canvas_w - dest_x), + MIN (eh, canvas_h - dest_y), + dest_x, dest_y, + 1.0, 1.0, + GDK_INTERP_BILINEAR, + 255); + + g_object_unref (emblem_pixbuf); + } + + NemoIconInfo *icon_info = nemo_icon_info_new_for_pixbuf (result_pixbuf, scale); + g_object_unref (result_pixbuf); + + return icon_info; +} + NemoIconInfo * nemo_icon_info_lookup (GIcon *icon, int size, @@ -293,6 +463,10 @@ nemo_icon_info_lookup (GIcon *icon, NemoIconInfo *icon_info; + if (NEMO_IS_EMBLEMED_ICON (icon)) { + return nemo_icon_info_lookup_emblemed (NEMO_EMBLEMED_ICON (icon), size, scale); + } + icon_theme = gtk_icon_theme_get_default (); if (G_IS_LOADABLE_ICON (icon)) { diff --git a/src/nemo-icon-view-container.c b/src/nemo-icon-view-container.c index 78bb244095..c61290ebb8 100644 --- a/src/nemo-icon-view-container.c +++ b/src/nemo-icon-view-container.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #define DEBUG_FLAG NEMO_DEBUG_ICON_CONTAINER @@ -92,9 +93,8 @@ nemo_icon_view_container_get_icon_images (NemoIconContainer *container, NemoFile *file; NemoFileIconFlags flags; NemoIconInfo *icon_info; - GdkPixbuf *pixbuf; GIcon *emblemed_icon; - GEmblem *emblem; + NemoEmblem *emblem; GList *emblem_icons, *l; gint scale; @@ -125,51 +125,20 @@ nemo_icon_view_container_get_icon_images (NemoIconContainer *container, /* apply emblems */ if (emblem_icons != NULL) { - gint w, h, s; - gboolean bad_ratio; - - l = emblem_icons; - - pixbuf = nemo_icon_info_get_pixbuf (icon_info); - - w = gdk_pixbuf_get_width (pixbuf); - h = gdk_pixbuf_get_height (pixbuf); - - s = MAX (w, h); - if (s < size) - size = s; - - bad_ratio = (int)nemo_icon_get_emblem_size_for_icon_size (size) * scale > (int)(w * 0.75) || - (int)nemo_icon_get_emblem_size_for_icon_size (size) * scale > (int)(h * 0.75); - - if (bad_ratio) - goto skip_emblem; /* Would prefer to not use goto, but - * I don't want to do these checks on - * non-emblemed icons (the majority) - * as it would be too costly */ - - emblem = g_emblem_new (l->data); - - emblemed_icon = g_emblemed_icon_new (G_ICON (pixbuf), emblem); - g_object_unref (emblem); - - for (l = l->next; l != NULL; l = l->next) { - emblem = g_emblem_new (l->data); - g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (emblemed_icon), - emblem); - g_object_unref (emblem); - } + GIcon *gicon = G_ICON (nemo_icon_info_get_pixbuf (icon_info)); + + for (l = emblem_icons; l != NULL; l = l->next) { + emblem = nemo_emblem_new (l->data, NEMO_EMBLEM_SIZE_MEDIUM, NEMO_EMBLEM_POSITION_DEFAULT); + emblemed_icon = nemo_emblemed_icon_new (gicon, emblem); + g_object_unref (gicon); + g_object_unref (emblem); + gicon = emblemed_icon; + } nemo_icon_info_clear (&icon_info); - icon_info = nemo_icon_info_lookup (emblemed_icon, size, scale); - g_object_unref (emblemed_icon); + icon_info = nemo_icon_info_lookup (gicon, size, scale); + g_object_unref (gicon); -skip_emblem: - g_object_unref (pixbuf); - - } - - if (emblem_icons != NULL) { g_list_free_full (emblem_icons, g_object_unref); } diff --git a/src/nemo-icon-view-grid-container.c b/src/nemo-icon-view-grid-container.c index cfdb725952..dfbdef9b16 100644 --- a/src/nemo-icon-view-grid-container.c +++ b/src/nemo-icon-view-grid-container.c @@ -43,6 +43,7 @@ #include #include #include +#include static void update_layout_constants (NemoIconContainer *container); @@ -71,9 +72,8 @@ nemo_icon_view_grid_container_get_icon_images (NemoIconContainer *container, NemoFile *file; NemoFileIconFlags flags; NemoIconInfo *icon_info; - GdkPixbuf *pixbuf; GIcon *emblemed_icon; - GEmblem *emblem; + NemoEmblem *emblem; GList *emblem_icons, *l; gint scale; @@ -102,51 +102,20 @@ nemo_icon_view_grid_container_get_icon_images (NemoIconContainer *container, /* apply emblems */ if (emblem_icons != NULL) { - gint w, h, s; - gboolean bad_ratio; - - l = emblem_icons; - - pixbuf = nemo_icon_info_get_pixbuf (icon_info); - - w = gdk_pixbuf_get_width (pixbuf); - h = gdk_pixbuf_get_height (pixbuf); - - s = MAX (w, h); - if (s < size) - size = s; - - bad_ratio = (int)nemo_icon_get_emblem_size_for_icon_size (size) * scale > (int)(w * 0.75) || - (int)nemo_icon_get_emblem_size_for_icon_size (size) * scale > (int)(h * 0.75); - - if (bad_ratio) - goto skip_emblem; /* Would prefer to not use goto, but - * I don't want to do these checks on - * non-emblemed icons (the majority) - * as it would be too costly */ - - emblem = g_emblem_new (l->data); - - emblemed_icon = g_emblemed_icon_new (G_ICON (pixbuf), emblem); - g_object_unref (emblem); - - for (l = l->next; l != NULL; l = l->next) { - emblem = g_emblem_new (l->data); - g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (emblemed_icon), - emblem); - g_object_unref (emblem); - } - - nemo_icon_info_clear (&icon_info); - icon_info = nemo_icon_info_lookup (emblemed_icon, size, scale); - g_object_unref (emblemed_icon); - -skip_emblem: - g_object_unref (pixbuf); + GIcon *gicon = G_ICON (nemo_icon_info_get_pixbuf (icon_info)); + + for (l = emblem_icons; l != NULL; l = l->next) { + emblem = nemo_emblem_new (l->data, NEMO_EMBLEM_SIZE_MEDIUM, NEMO_EMBLEM_POSITION_DEFAULT); + emblemed_icon = nemo_emblemed_icon_new (gicon, emblem); + g_object_unref (gicon); + g_object_unref (emblem); + gicon = emblemed_icon; + } - } + nemo_icon_info_clear (&icon_info); + icon_info = nemo_icon_info_lookup (gicon, size, scale); + g_object_unref (gicon); - if (emblem_icons != NULL) { g_list_free_full (emblem_icons, g_object_unref); } diff --git a/src/nemo-list-model.c b/src/nemo-list-model.c index 6f8a454f80..aee3eb9d59 100644 --- a/src/nemo-list-model.c +++ b/src/nemo-list-model.c @@ -38,6 +38,7 @@ #include #include #include +#include enum { SUBDIRECTORY_UNLOADED, @@ -350,36 +351,21 @@ nemo_list_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, int colu if (emblem_icons) { GdkPixbuf *initial_pixbuf; - GIcon *gicon, *emblemed_icon, *emblem_icon; - GEmblem *emblem; - gint w, h, s; - gboolean bad_ratio; + GIcon *gicon; + NemoEmblem *emblem; initial_pixbuf = nemo_icon_info_get_pixbuf_at_size (icon_info, icon_size * icon_scale); - - w = gdk_pixbuf_get_width (initial_pixbuf); - h = gdk_pixbuf_get_height (initial_pixbuf); - - s = MAX (w, h); - if (s < icon_size) - icon_size = s; - - bad_ratio = (int)(nemo_icon_get_emblem_size_for_icon_size (icon_size) * icon_scale) > (int)(w * 0.75) || - (int)(nemo_icon_get_emblem_size_for_icon_size (icon_size) * icon_scale) > (int)(h * 0.75); - gicon = G_ICON (initial_pixbuf); - /* pick only the first emblem we can render for the list view */ - for (l = emblem_icons; !bad_ratio && l != NULL; l = l->next) { - emblem_icon = l->data; - emblem = g_emblem_new (emblem_icon); - emblemed_icon = g_emblemed_icon_new (gicon, emblem); + /* pick only the first emblem for the list view */ + l = emblem_icons; + if (l != NULL) { + emblem = nemo_emblem_new (l->data, NEMO_EMBLEM_SIZE_MEDIUM, NEMO_EMBLEM_POSITION_LOWER_RIGHT); + GIcon *emblemed_icon = nemo_emblemed_icon_new (gicon, emblem); g_object_unref (gicon); g_object_unref (emblem); gicon = emblemed_icon; - - break; } nemo_icon_info_clear (&icon_info); diff --git a/src/nemo-tree-sidebar-model.c b/src/nemo-tree-sidebar-model.c index 92fdfcec73..044a87eee4 100644 --- a/src/nemo-tree-sidebar-model.c +++ b/src/nemo-tree-sidebar-model.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -264,36 +265,36 @@ get_menu_icon_for_file (TreeNode *node, NemoFileIconFlags flags) { NemoFile *parent_file; - GIcon *gicon, *emblem_icon, *emblemed_icon; - GEmblem *emblem; - int size; - GList *emblem_icons, *l; + GIcon *gicon; + int size; + GList *emblem_icons, *l; - size = nemo_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU); - gicon = G_ICON (nemo_file_get_icon_pixbuf (file, size, TRUE, node->icon_scale, flags)); + size = nemo_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU); + gicon = G_ICON (nemo_file_get_icon_pixbuf (file, size, TRUE, node->icon_scale, flags)); parent_file = NULL; - if (node->parent && node->parent->file) { + if (node->parent && node->parent->file) { parent_file = node->parent->file; - } + } - emblem_icons = nemo_file_get_emblem_icons (node->file, parent_file); + emblem_icons = nemo_file_get_emblem_icons (node->file, parent_file); - /* pick only the first emblem we can render for the tree view */ - for (l = emblem_icons; l != NULL; l = l->next) { - emblem_icon = l->data; - emblem = g_emblem_new (emblem_icon); - emblemed_icon = g_emblemed_icon_new (gicon, emblem); + /* pick only the first emblem for the tree view */ + l = emblem_icons; + if (l != NULL) { + NemoEmblem *emblem; + GIcon *emblemed_icon; - g_object_unref (gicon); - g_object_unref (emblem); - gicon = emblemed_icon; + emblem = nemo_emblem_new (l->data, NEMO_EMBLEM_SIZE_MEDIUM, NEMO_EMBLEM_POSITION_LOWER_RIGHT); + emblemed_icon = nemo_emblemed_icon_new (gicon, emblem); - break; - } + g_object_unref (gicon); + g_object_unref (emblem); + gicon = emblemed_icon; + } - g_list_free_full (emblem_icons, g_object_unref); + g_list_free_full (emblem_icons, g_object_unref); return gicon; } From 2babecaacf5af811b66f54dbdc1b8e5c902fd6e0 Mon Sep 17 00:00:00 2001 From: Michael Webster Date: Fri, 20 Feb 2026 09:52:14 -0500 Subject: [PATCH 2/3] Tweak sizes. --- libnemo-private/nemo-icon-info.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libnemo-private/nemo-icon-info.c b/libnemo-private/nemo-icon-info.c index 6c6f41578f..ee50d6c4dc 100644 --- a/libnemo-private/nemo-icon-info.c +++ b/libnemo-private/nemo-icon-info.c @@ -289,15 +289,15 @@ nemo_emblem_size_get_ratio (NemoEmblemSize size) { switch (size) { case NEMO_EMBLEM_SIZE_EXTRA_SMALL: - return 0.15; + return 0.20; case NEMO_EMBLEM_SIZE_SMALL: - return 0.25; - case NEMO_EMBLEM_SIZE_MEDIUM: return 0.33; + case NEMO_EMBLEM_SIZE_MEDIUM: + return 0.45; case NEMO_EMBLEM_SIZE_LARGE: - return 0.50; + return 0.60; default: - return 0.25; + return 0.33; } } From bc807c5016860717b397ec1ede42f25e7e3bdb31 Mon Sep 17 00:00:00 2001 From: Michael Webster Date: Wed, 25 Feb 2026 09:55:07 -0500 Subject: [PATCH 3/3] Fix icon view --- src/nemo-icon-view-container.c | 12 ++++++------ src/nemo-icon-view-grid-container.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/nemo-icon-view-container.c b/src/nemo-icon-view-container.c index c61290ebb8..63edc2e293 100644 --- a/src/nemo-icon-view-container.c +++ b/src/nemo-icon-view-container.c @@ -125,19 +125,19 @@ nemo_icon_view_container_get_icon_images (NemoIconContainer *container, /* apply emblems */ if (emblem_icons != NULL) { - GIcon *gicon = G_ICON (nemo_icon_info_get_pixbuf (icon_info)); + GdkPixbuf *pixbuf = nemo_icon_info_get_pixbuf (icon_info); + emblemed_icon = nemo_emblemed_icon_new (G_ICON (pixbuf), NULL); for (l = emblem_icons; l != NULL; l = l->next) { emblem = nemo_emblem_new (l->data, NEMO_EMBLEM_SIZE_MEDIUM, NEMO_EMBLEM_POSITION_DEFAULT); - emblemed_icon = nemo_emblemed_icon_new (gicon, emblem); - g_object_unref (gicon); + nemo_emblemed_icon_add_emblem (NEMO_EMBLEMED_ICON (emblemed_icon), emblem); g_object_unref (emblem); - gicon = emblemed_icon; } nemo_icon_info_clear (&icon_info); - icon_info = nemo_icon_info_lookup (gicon, size, scale); - g_object_unref (gicon); + icon_info = nemo_icon_info_lookup (emblemed_icon, size, scale); + g_object_unref (emblemed_icon); + g_object_unref (pixbuf); g_list_free_full (emblem_icons, g_object_unref); } diff --git a/src/nemo-icon-view-grid-container.c b/src/nemo-icon-view-grid-container.c index dfbdef9b16..572176b3f7 100644 --- a/src/nemo-icon-view-grid-container.c +++ b/src/nemo-icon-view-grid-container.c @@ -102,19 +102,19 @@ nemo_icon_view_grid_container_get_icon_images (NemoIconContainer *container, /* apply emblems */ if (emblem_icons != NULL) { - GIcon *gicon = G_ICON (nemo_icon_info_get_pixbuf (icon_info)); + GdkPixbuf *pixbuf = nemo_icon_info_get_pixbuf (icon_info); + emblemed_icon = nemo_emblemed_icon_new (G_ICON (pixbuf), NULL); for (l = emblem_icons; l != NULL; l = l->next) { emblem = nemo_emblem_new (l->data, NEMO_EMBLEM_SIZE_MEDIUM, NEMO_EMBLEM_POSITION_DEFAULT); - emblemed_icon = nemo_emblemed_icon_new (gicon, emblem); - g_object_unref (gicon); + nemo_emblemed_icon_add_emblem (NEMO_EMBLEMED_ICON (emblemed_icon), emblem); g_object_unref (emblem); - gicon = emblemed_icon; } nemo_icon_info_clear (&icon_info); - icon_info = nemo_icon_info_lookup (gicon, size, scale); - g_object_unref (gicon); + icon_info = nemo_icon_info_lookup (emblemed_icon, size, scale); + g_object_unref (emblemed_icon); + g_object_unref (pixbuf); g_list_free_full (emblem_icons, g_object_unref); }