From e63e68dfdef53b7e73f109b1f4fd7486d39f94de Mon Sep 17 00:00:00 2001 From: deepend Date: Sun, 1 Mar 2026 09:58:04 -0700 Subject: [PATCH] icons: dedupe resolver tables, add unified menu-action API, route gtkutil/pixmaps through one registry + fallback chain --- src/fe-gtk/gtkutil.c | 12 +--- src/fe-gtk/icon-resolver.c | 144 ++++++++++++++----------------------- src/fe-gtk/icon-resolver.h | 3 +- src/fe-gtk/pixmaps.c | 36 ++++------ 4 files changed, 72 insertions(+), 123 deletions(-) diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index 1b21c159..579418c3 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -71,7 +71,7 @@ gtkutil_menu_icon_pixbuf_new (const char *icon_name) const char *system_icon_name = NULL; int action; - if (!icon_name || !icon_resolver_menu_action_from_custom (icon_name, &action)) + if (!icon_name || !icon_resolver_menu_action_from_name (icon_name, &action)) return NULL; resource_path = icon_resolver_resolve_path (ICON_RESOLVER_ROLE_MENU_ACTION, action, @@ -126,16 +126,6 @@ gtkutil_image_new_from_stock (const char *stock, GtkIconSize size) icon_name = gtkutil_icon_name_from_stock (stock); if (!icon_name && stock && g_str_has_prefix (stock, "zc-menu-")) icon_name = stock; - if (size == GTK_ICON_SIZE_MENU) - { - const char *menu_icon_name = icon_resolver_menu_custom_icon_from_stock (stock); - - if (!menu_icon_name) - menu_icon_name = icon_resolver_menu_custom_icon_from_icon_name (icon_name); - - if (menu_icon_name) - icon_name = menu_icon_name; - } image = gtkutil_menu_icon_image_new (icon_name, size); if (image) diff --git a/src/fe-gtk/icon-resolver.c b/src/fe-gtk/icon-resolver.c index 2633bea4..f4fc753d 100644 --- a/src/fe-gtk/icon-resolver.c +++ b/src/fe-gtk/icon-resolver.c @@ -19,12 +19,6 @@ typedef struct const char *system_icon_name; } StockIconMap; -typedef struct -{ - const char *key; - const char *custom_icon_name; -} MenuMap; - static const IconRegistryEntry icon_registry[] = { { ICON_RESOLVER_ROLE_MENU_ACTION, ICON_RESOLVER_MENU_ACTION_NEW, "zc-menu-new", "document-new", "new" }, { ICON_RESOLVER_ROLE_MENU_ACTION, ICON_RESOLVER_MENU_ACTION_NETWORK_LIST, "zc-menu-network-list", "view-list", "network-list" }, @@ -107,65 +101,26 @@ static const StockIconMap stock_icon_map[] = { { "gtk-spell-check", "tools-check-spelling" } }; -static const MenuMap stock_menu_map[] = { - { "gtk-new", "zc-menu-new" }, - { "gtk-index", "zc-menu-network-list" }, - { "gtk-revert-to-saved", "zc-menu-load-plugin" }, - { "gtk-redo", "zc-menu-detach" }, - { "gtk-close", "zc-menu-close" }, - { "gtk-quit", "zc-menu-quit" }, - { "gtk-disconnect", "zc-menu-disconnect" }, - { "gtk-connect", "zc-menu-connect" }, - { "gtk-jump-to", "zc-menu-join" }, - { "gtk-preferences", "zc-menu-preferences" }, - { "gtk-clear", "zc-menu-clear" }, - { "gtk-copy", "zc-menu-copy" }, - { "gtk-delete", "zc-menu-delete" }, - { "gtk-add", "zc-menu-add" }, - { "gtk-remove", "zc-menu-remove" }, - { "gtk-spell-check", "zc-menu-spell-check" }, - { "gtk-save", "zc-menu-save" }, - { "gtk-save-as", "zc-menu-save-as" }, - { "gtk-refresh", "zc-menu-refresh" }, - { "gtk-justify-left", "zc-menu-search" }, - { "gtk-find", "zc-menu-find" }, - { "gtk-go-back", "zc-menu-previous" }, - { "gtk-go-forward", "zc-menu-next" }, - { "gtk-help", "zc-menu-help" }, - { "gtk-about", "zc-menu-about" }, - { "gtk-convert", "zc-menu-emoji" } -}; -static const MenuMap icon_menu_map[] = { - { "document-new", "zc-menu-new" }, - { "view-list", "zc-menu-network-list" }, - { "document-open", "zc-menu-load-plugin" }, - { "edit-redo", "zc-menu-detach" }, - { "window-close", "zc-menu-close" }, - { "application-exit", "zc-menu-quit" }, - { "network-disconnect", "zc-menu-disconnect" }, - { "network-connect", "zc-menu-connect" }, - { "go-jump", "zc-menu-join" }, - { "preferences-system", "zc-menu-preferences" }, - { "edit-clear", "zc-menu-clear" }, - { "edit-copy", "zc-menu-copy" }, - { "edit-delete", "zc-menu-delete" }, - { "list-add", "zc-menu-add" }, - { "list-remove", "zc-menu-remove" }, - { "tools-check-spelling", "zc-menu-spell-check" }, - { "document-save", "zc-menu-save" }, - { "document-save-as", "zc-menu-save-as" }, - { "view-refresh", "zc-menu-refresh" }, - { "edit-find", "zc-menu-find" }, - { "go-previous", "zc-menu-previous" }, - { "go-next", "zc-menu-next" }, - { "help-browser", "zc-menu-help" }, - { "help-about", "zc-menu-about" }, - { "face-smile", "zc-menu-emoji" }, - { "insert-emoticon", "zc-menu-emoji" }, - { "software-update-available", "zc-menu-update" }, - { "network-workgroup", "zc-menu-chanlist" } -}; +static int +menu_action_from_icon_name (const char *icon_name) +{ + size_t i; + + if (!icon_name) + return -1; + + for (i = 0; i < G_N_ELEMENTS (icon_registry); i++) + { + if (icon_registry[i].role != ICON_RESOLVER_ROLE_MENU_ACTION) + continue; + + if (icon_registry[i].system_icon_name && strcmp (icon_name, icon_registry[i].system_icon_name) == 0) + return icon_registry[i].item; + } + + return -1; +} static const IconRegistryEntry * icon_registry_find (IconResolverRole role, int item) @@ -198,23 +153,6 @@ icon_registry_find_custom (const char *custom_icon_name) return NULL; } -static const char * -menu_map_lookup (const MenuMap *map, size_t map_len, const char *key) -{ - size_t i; - - if (!key) - return NULL; - - for (i = 0; i < map_len; i++) - { - if (strcmp (key, map[i].key) == 0) - return map[i].custom_icon_name; - } - - return NULL; -} - const char * icon_resolver_icon_name_from_stock (const char *stock_name) { @@ -232,16 +170,44 @@ icon_resolver_icon_name_from_stock (const char *stock_name) return stock_name; } -const char * -icon_resolver_menu_custom_icon_from_stock (const char *stock_name) +gboolean +icon_resolver_menu_action_from_name (const char *name, int *action_out) { - return menu_map_lookup (stock_menu_map, G_N_ELEMENTS (stock_menu_map), stock_name); -} + size_t i; -const char * -icon_resolver_menu_custom_icon_from_icon_name (const char *icon_name) -{ - return menu_map_lookup (icon_menu_map, G_N_ELEMENTS (icon_menu_map), icon_name); + if (!name) + return FALSE; + + for (i = 0; i < G_N_ELEMENTS (icon_registry); i++) + { + if (icon_registry[i].role != ICON_RESOLVER_ROLE_MENU_ACTION) + continue; + + if ((icon_registry[i].custom_icon_name && strcmp (name, icon_registry[i].custom_icon_name) == 0) || + (icon_registry[i].system_icon_name && strcmp (name, icon_registry[i].system_icon_name) == 0)) + { + if (action_out) + *action_out = icon_registry[i].item; + return TRUE; + } + } + + for (i = 0; i < G_N_ELEMENTS (stock_icon_map); i++) + { + if (strcmp (name, stock_icon_map[i].stock_name) == 0) + { + int action = menu_action_from_icon_name (stock_icon_map[i].system_icon_name); + + if (action >= 0) + { + if (action_out) + *action_out = action; + return TRUE; + } + } + } + + return FALSE; } const char * diff --git a/src/fe-gtk/icon-resolver.h b/src/fe-gtk/icon-resolver.h index 067288d6..0f4a5c8a 100644 --- a/src/fe-gtk/icon-resolver.h +++ b/src/fe-gtk/icon-resolver.h @@ -77,10 +77,9 @@ typedef enum } IconResolverUserlistRank; const char *icon_resolver_icon_name_from_stock (const char *stock_name); -const char *icon_resolver_menu_custom_icon_from_stock (const char *stock_name); -const char *icon_resolver_menu_custom_icon_from_icon_name (const char *icon_name); const char *icon_resolver_icon_name_for_menu_custom (const char *custom_icon_name); gboolean icon_resolver_menu_action_from_custom (const char *custom_icon_name, int *action_out); +gboolean icon_resolver_menu_action_from_name (const char *name, int *action_out); IconResolverThemeVariant icon_resolver_detect_theme_variant (void); char *icon_resolver_resolve_path (IconResolverRole role, int item, GtkIconSize size, const char *context, IconResolverThemeVariant variant, diff --git a/src/fe-gtk/pixmaps.c b/src/fe-gtk/pixmaps.c index 845a21fb..f786670b 100644 --- a/src/fe-gtk/pixmaps.c +++ b/src/fe-gtk/pixmaps.c @@ -152,7 +152,7 @@ pixmap_load_from_file (char *filename) /* load custom icons from /icons, don't mess in system folders */ static GdkPixbuf * -load_pixmap (IconResolverRole role, int item, const char *fallback_name) +load_pixmap (IconResolverRole role, int item) { GdkPixbuf *pixbuf = NULL; GdkPixbuf *scaledpixbuf; @@ -179,12 +179,6 @@ load_pixmap (IconResolverRole role, int item, const char *fallback_name) pixbuf = gtk_icon_theme_load_icon (theme, system_icon_name, 16, GTK_ICON_LOOKUP_FORCE_SIZE, NULL); } - if (!pixbuf && fallback_name) - { - char *resource_path = g_strdup_printf ("/icons/%s.png", fallback_name); - pixbuf = gdk_pixbuf_new_from_resource (resource_path, NULL); - g_free (resource_path); - } scale = g_getenv ("GDK_SCALE"); if (scale && pixbuf) @@ -213,22 +207,22 @@ pixmaps_init (void) { zoitechat_register_resource(); - pix_ulist_voice = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_VOICE, "ulist_voice"); - pix_ulist_halfop = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_HALFOP, "ulist_halfop"); - pix_ulist_op = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_OP, "ulist_op"); - pix_ulist_owner = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_OWNER, "ulist_owner"); - pix_ulist_founder = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_FOUNDER, "ulist_founder"); - pix_ulist_netop = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_NETOP, "ulist_netop"); + pix_ulist_voice = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_VOICE); + pix_ulist_halfop = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_HALFOP); + pix_ulist_op = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_OP); + pix_ulist_owner = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_OWNER); + pix_ulist_founder = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_FOUNDER); + pix_ulist_netop = load_pixmap (ICON_RESOLVER_ROLE_USERLIST_RANK, ICON_RESOLVER_USERLIST_RANK_NETOP); - pix_tray_normal = load_pixmap (ICON_RESOLVER_ROLE_TRAY_STATE, ICON_RESOLVER_TRAY_STATE_NORMAL, "tray_normal"); - pix_tray_fileoffer = load_pixmap (ICON_RESOLVER_ROLE_TRAY_STATE, ICON_RESOLVER_TRAY_STATE_FILEOFFER, "tray_fileoffer"); - pix_tray_highlight = load_pixmap (ICON_RESOLVER_ROLE_TRAY_STATE, ICON_RESOLVER_TRAY_STATE_HIGHLIGHT, "tray_highlight"); - pix_tray_message = load_pixmap (ICON_RESOLVER_ROLE_TRAY_STATE, ICON_RESOLVER_TRAY_STATE_MESSAGE, "tray_message"); + pix_tray_normal = load_pixmap (ICON_RESOLVER_ROLE_TRAY_STATE, ICON_RESOLVER_TRAY_STATE_NORMAL); + pix_tray_fileoffer = load_pixmap (ICON_RESOLVER_ROLE_TRAY_STATE, ICON_RESOLVER_TRAY_STATE_FILEOFFER); + pix_tray_highlight = load_pixmap (ICON_RESOLVER_ROLE_TRAY_STATE, ICON_RESOLVER_TRAY_STATE_HIGHLIGHT); + pix_tray_message = load_pixmap (ICON_RESOLVER_ROLE_TRAY_STATE, ICON_RESOLVER_TRAY_STATE_MESSAGE); - pix_tree_channel = load_pixmap (ICON_RESOLVER_ROLE_TREE_TYPE, ICON_RESOLVER_TREE_TYPE_CHANNEL, "tree_channel"); - pix_tree_dialog = load_pixmap (ICON_RESOLVER_ROLE_TREE_TYPE, ICON_RESOLVER_TREE_TYPE_DIALOG, "tree_dialog"); - pix_tree_server = load_pixmap (ICON_RESOLVER_ROLE_TREE_TYPE, ICON_RESOLVER_TREE_TYPE_SERVER, "tree_server"); - pix_tree_util = load_pixmap (ICON_RESOLVER_ROLE_TREE_TYPE, ICON_RESOLVER_TREE_TYPE_UTIL, "tree_util"); + pix_tree_channel = load_pixmap (ICON_RESOLVER_ROLE_TREE_TYPE, ICON_RESOLVER_TREE_TYPE_CHANNEL); + pix_tree_dialog = load_pixmap (ICON_RESOLVER_ROLE_TREE_TYPE, ICON_RESOLVER_TREE_TYPE_DIALOG); + pix_tree_server = load_pixmap (ICON_RESOLVER_ROLE_TREE_TYPE, ICON_RESOLVER_TREE_TYPE_SERVER); + pix_tree_util = load_pixmap (ICON_RESOLVER_ROLE_TREE_TYPE, ICON_RESOLVER_TREE_TYPE_UTIL); /* non-replaceable book pixmap */ pix_book = gdk_pixbuf_new_from_resource ("/icons/book.png", NULL);