From ee107621c4d5f42c650b7992b9c1215c23cfd221 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 15:23:03 -0700 Subject: [PATCH 01/38] =?UTF-8?q?Removed=20the=20custom=20emoji=20picker/m?= =?UTF-8?q?enu=20implementation=20from=20maingui.c=20(including=20its=20ca?= =?UTF-8?q?llbacks=20and=20helper=20declarations),=20so=20the=20old=20in-a?= =?UTF-8?q?pp=20emoji=20menu=20is=20no=20longer=20present.=20The=20code=20?= =?UTF-8?q?now=20transitions=20directly=20from=20emoji=20font=20fallback?= =?UTF-8?q?=20logic=20to=20the=20search-bar=20section.=20updated=20the=20i?= =?UTF-8?q?nput=20entry=20creation=20to=20stop=20creating=20a=20separate?= =?UTF-8?q?=20emoji=20button,=20and=20instead=20enable=20GTK=E2=80=99s=20b?= =?UTF-8?q?uilt-in=20emoji=20menu=20icon=20with=20show-emoji-icon=20on=20G?= =?UTF-8?q?TK3+=20builds=20only=20(no=20GTK2=20fallback=20path).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fe-gtk/maingui.c | 159 ++----------------------------------------- 1 file changed, 4 insertions(+), 155 deletions(-) diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index ec5e6b6c..9743264d 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -95,10 +95,6 @@ enum #define TAG_UTIL 1 /* dcc, notify, chanlist */ static void mg_apply_emoji_fallback_widget (GtkWidget *widget); -static void mg_apply_emoji_primary_widget (GtkWidget *widget); -static void mg_emoji_button_cb (GtkWidget *widget, session_gui *gui); -static GtkWidget *mg_create_emoji_menu (session_gui *gui); -static void mg_emoji_insert_cb (GtkMenuItem *item, session_gui *gui); static inline void mg_set_source_color (cairo_t *cr, const XTextColor *color) @@ -3294,148 +3290,6 @@ mg_apply_emoji_fallback_widget (GtkWidget *widget) pango_font_description_free (desc); } -static void -mg_apply_emoji_primary_widget (GtkWidget *widget) -{ - PangoFontDescription *desc; -#if HAVE_GTK3 - GtkStyleContext *context; - const PangoFontDescription *base_desc; -#else - GtkStyle *style; -#endif - - if (!widget) - return; - -#if HAVE_GTK3 - context = gtk_widget_get_style_context (widget); - if (!context) - return; - - base_desc = gtk_style_context_get_font (context, GTK_STATE_FLAG_NORMAL); - if (!base_desc) - return; - - desc = mg_fontdesc_with_fallback (base_desc, TRUE); -#else - style = gtk_widget_get_style (widget); - if (!style || !style->font_desc) - return; - - desc = mg_fontdesc_with_fallback (style->font_desc, TRUE); -#endif - if (!desc) - return; - -#if HAVE_GTK3 - mg_apply_font_css (widget, desc, "zoitechat-emoji-font", - "zoitechat-emoji-font-provider"); -#else - gtk_widget_modify_font (widget, desc); -#endif - pango_font_description_free (desc); -} - -static void -mg_apply_emoji_primary_widget_with_child (GtkWidget *widget) -{ - GtkWidget *child; - - if (!widget) - return; - - mg_apply_emoji_primary_widget (widget); - if (!GTK_IS_BIN (widget)) - return; - - child = gtk_bin_get_child (GTK_BIN (widget)); - if (child) - mg_apply_emoji_primary_widget (child); -} - -/* ------------------------------------------------------------------------- * - * Emoji picker (optional UI sugar) - * ------------------------------------------------------------------------- */ - -static void -mg_emoji_insert_cb (GtkMenuItem *item, session_gui *gui) -{ - const char *emoji = g_object_get_data (G_OBJECT (item), "emoji"); - gint pos; - - if (!emoji || !gui || !gui->input_box) - return; - - pos = SPELL_ENTRY_GET_POS (gui->input_box); - gtk_editable_insert_text (GTK_EDITABLE (gui->input_box), emoji, -1, &pos); - gtk_editable_set_position (GTK_EDITABLE (gui->input_box), pos); - gtk_widget_grab_focus (gui->input_box); -} - -static GtkWidget * -mg_create_emoji_menu (session_gui *gui) -{ - /* VS16 (emoji presentation). No, it does not need a space. */ -#define VS16 "\xEF\xB8\x8F" - static const char *emoji_list[] = { - "๐Ÿ˜€","๐Ÿ˜ƒ","๐Ÿ˜„","๐Ÿ˜","๐Ÿ˜†","๐Ÿ˜‚","๐Ÿคฃ","๐Ÿ˜Š","๐Ÿ˜‡","๐Ÿ˜‰","๐Ÿ˜", - "๐Ÿฅฐ","๐Ÿ˜˜","๐Ÿ˜œ","๐Ÿคช","๐Ÿ˜Ž","๐Ÿคฉ","๐Ÿค”","๐Ÿคจ","๐Ÿ˜","๐Ÿ˜ถ","๐Ÿ™„", - "๐Ÿ˜","๐Ÿ˜ฃ","๐Ÿ˜ฅ","๐Ÿ˜ฎ","๐Ÿ˜ฏ","๐Ÿ˜ช","๐Ÿ˜ด","๐Ÿ˜Œ","๐Ÿ˜”","๐Ÿ˜ข", - "๐Ÿ˜ญ","๐Ÿ˜ค","๐Ÿ˜ ","๐Ÿ˜ก","๐Ÿคฌ","๐Ÿฅบ","๐Ÿ˜ณ","๐Ÿค—","๐Ÿคญ","๐Ÿคซ", - "๐Ÿค","๐Ÿ˜ท","๐Ÿค’","๐Ÿค•","๐Ÿคข","๐Ÿคฎ","๐Ÿฅต","๐Ÿฅถ","๐Ÿฅด","๐Ÿคฏ", - "๐Ÿ‘"VS16,"๐Ÿ‘Ž"VS16,"๐Ÿ‘"VS16,"๐Ÿ™Œ"VS16,"๐Ÿ™"VS16,"๐Ÿ’ช"VS16, - "๐Ÿ‘€"VS16,"๐Ÿ’ฏ"VS16,"โœ…"VS16,"โŒ"VS16,"๐ŸŽ‰"VS16,"๐Ÿ”ฅ"VS16, - "โค","๐Ÿ’”","๐Ÿ’–","๐Ÿ’™","๐Ÿ’š","๐Ÿ’›","๐Ÿ’œ","๐Ÿงก","๐Ÿค","๐Ÿ–ค", - "โญ"VS16,"๐ŸŒŸ","โœจ","โšก"VS16,"โ˜€","๐ŸŒˆ","โ˜•"VS16,"๐Ÿ•", - "๐Ÿ”","๐ŸŸ","๐Ÿฃ","๐Ÿฉ","๐ŸŽ‚","๐Ÿบ","๐Ÿท","๐ŸŽ","๐ŸŽˆ","๐ŸŽฏ", - "๐ŸŽต","๐ŸŽถ","๐ŸŽฎ","๐Ÿš€","โœˆ","๐Ÿš—","๐Ÿš•","๐Ÿšฒ","๐Ÿก","๐ŸŒ", - NULL - }; -#undef VS16 - - GtkWidget *menu; - const int columns = 8; - int i; - - menu = gtk_menu_new (); - - for (i = 0; emoji_list[i]; i++) - { - GtkWidget *item = gtk_menu_item_new_with_label (emoji_list[i]); - int row = i / columns; - int col = i % columns; - - g_object_set_data_full (G_OBJECT (item), "emoji", g_strdup (emoji_list[i]), g_free); - g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (mg_emoji_insert_cb), gui); - - /* Prefer emoji fonts for the label itself */ - mg_apply_emoji_primary_widget_with_child (item); - - gtk_menu_attach (GTK_MENU (menu), item, col, col + 1, row, row + 1); - gtk_widget_show (item); - } - - g_signal_connect (G_OBJECT (menu), "selection-done", G_CALLBACK (gtk_widget_destroy), NULL); - return menu; -} - -static void -mg_emoji_button_cb (GtkWidget *widget, session_gui *gui) -{ - GtkWidget *menu; - - menu = mg_create_emoji_menu (gui); -#if HAVE_GTK3 - gtk_menu_popup_at_widget (GTK_MENU (menu), widget, - GDK_GRAVITY_SOUTH_WEST, - GDK_GRAVITY_NORTH_WEST, - NULL); -#else - gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ()); -#endif -} - /* Search bar adapted from Conspire's by William Pitcock */ #define SEARCH_CHANGE 1 @@ -3664,7 +3518,7 @@ mg_create_search(session *sess, GtkWidget *box) static void mg_create_entry (session *sess, GtkWidget *box) { - GtkWidget *hbox, *but, *entry, *emoji_button; + GtkWidget *hbox, *but, *entry; session_gui *gui = sess->gui; hbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); @@ -3705,14 +3559,9 @@ mg_create_entry (session *sess, GtkWidget *box) if (prefs.hex_gui_input_style) mg_apply_entry_style (entry); - /* Optional emoji button (kept since you already added it) */ - emoji_button = gtk_button_new_with_label ("๐Ÿ˜Š"); - gtk_button_set_relief (GTK_BUTTON (emoji_button), GTK_RELIEF_NONE); - gtk_widget_set_can_focus (emoji_button, FALSE); - gtk_widget_set_tooltip_text (emoji_button, _("Insert emoji")); - mg_apply_emoji_primary_widget_with_child (emoji_button); - g_signal_connect (G_OBJECT (emoji_button), "clicked", G_CALLBACK (mg_emoji_button_cb), gui); - gtk_box_pack_start (GTK_BOX (hbox), emoji_button, FALSE, FALSE, 4); +#if HAVE_GTK3 + g_object_set (G_OBJECT (entry), "show-emoji-icon", TRUE, NULL); +#endif } static void From cb0fd33089136341280dad696ea309bf746b4e58 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 15:43:15 -0700 Subject: [PATCH 02/38] =?UTF-8?q?updated=20the=20Windows=20packaging=20pro?= =?UTF-8?q?ject=20to=20include=20Adwaita=20icons=20in=20the=20bundle=20by?= =?UTF-8?q?=20adding=20an=20AdwaitaIcons=20item=20from=20$(DepsRoot)\share?= =?UTF-8?q?\icons\Adwaita\**\*=20and=20copying=20it=20into=20$(ZoiteChatRe?= =?UTF-8?q?l)\share\icons\Adwaita\....=20Added=20a=20Windows-packaged=20at?= =?UTF-8?q?tribution=20file=20at=20win32/copy/share/adwaita-icons-attribut?= =?UTF-8?q?ion.txt;=20because=20win32/copy/copy.vcxproj=20already=20copies?= =?UTF-8?q?=20share\**\*,=20this=20file=20will=20be=20included=20in=20the?= =?UTF-8?q?=20Windows=20output=20under=20share\adwaita-icons-attribution.t?= =?UTF-8?q?xt.=20The=20attribution=20text=20explicitly=20uses=20=E2=80=9CG?= =?UTF-8?q?NOME=20Project=E2=80=9D=20and=20includes=20the=20requested=20li?= =?UTF-8?q?nk=20http://www.gnome.org.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- win32/copy/copy.vcxproj | 3 ++- win32/copy/share/adwaita-icons-attribution.txt | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 win32/copy/share/adwaita-icons-attribution.txt diff --git a/win32/copy/copy.vcxproj b/win32/copy/copy.vcxproj index 3053ba91..f0d1b972 100644 --- a/win32/copy/copy.vcxproj +++ b/win32/copy/copy.vcxproj @@ -88,6 +88,7 @@ + @@ -101,6 +102,7 @@ + @@ -115,4 +117,3 @@ - diff --git a/win32/copy/share/adwaita-icons-attribution.txt b/win32/copy/share/adwaita-icons-attribution.txt new file mode 100644 index 00000000..65e51d24 --- /dev/null +++ b/win32/copy/share/adwaita-icons-attribution.txt @@ -0,0 +1,7 @@ +Adwaita Icons Attribution +========================= + +This package includes icons from Adwaita. +Artwork attribution: GNOME Project. + +Website: http://www.gnome.org From dd452f82ffd1a38977b9de81a13580140e046cbb Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 18:25:29 -0700 Subject: [PATCH 03/38] The Windows copy project already stages Adwaita icons into win32/rel\share\icons\Adwaita, but the Inno Setup script did not include that folder in [Files], so installed builds could miss those icons. I added an installer file rule to include share\icons\Adwaita\* recursively under the libs component. --- win32/installer/zoitechat.iss.tt | 1 + 1 file changed, 1 insertion(+) diff --git a/win32/installer/zoitechat.iss.tt b/win32/installer/zoitechat.iss.tt index c06df2e4..ff17bf6a 100644 --- a/win32/installer/zoitechat.iss.tt +++ b/win32/installer/zoitechat.iss.tt @@ -114,6 +114,7 @@ Source: "cert.pem"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "share\xml\*"; DestDir: "{app}\share\xml"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs Source: "share\doc\*"; DestDir: "{app}\share\doc"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs Source: "share\themes\MS-Windows\*"; DestDir: "{app}\share\themes\MS-Windows"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs +Source: "share\icons\Adwaita\*"; DestDir: "{app}\share\icons\Adwaita"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs Source: "share\glib-2.0\schemas\*"; DestDir: "{app}\share\glib-2.0\schemas"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs Source: "share\locale\*"; DestDir: "{app}\share\locale"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: translations Source: "etc\fonts\*"; DestDir: "{app}\etc\fonts"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs From 6bd7a309b36a306af825bfd8d8929c120d7698cb Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 18:55:38 -0700 Subject: [PATCH 04/38] =?UTF-8?q?Updated=20Windows=20GTK=20startup=20envir?= =?UTF-8?q?onment=20handling=20so=20ZoiteChat=20always=20prepends=20its=20?= =?UTF-8?q?bundled=20share=20directory=20to=20XDG=5FDATA=5FDIRS=20(without?= =?UTF-8?q?=20breaking=20existing=20values),=20which=20enables=20GTK=20to?= =?UTF-8?q?=20discover=20packaged=20runtime=20data=20used=20by=20icon/them?= =?UTF-8?q?e=20and=20emoji=20resources.=20Also=20changed=20GSETTINGS=5FSCH?= =?UTF-8?q?EMA=5FDIR=20logic=20so=20it=20no=20longer=20short-circuits=20th?= =?UTF-8?q?is=20setup=20when=20GSETTINGS=5FSCHEMA=5FDIR=20is=20already=20s?= =?UTF-8?q?et.=20Added=20a=20Win32=20icon-theme=20setup=20helper=20that=20?= =?UTF-8?q?appends=20bundled=20share/icons=20to=20GtkIconTheme=20search=20?= =?UTF-8?q?paths=20and=20forces=20Adwaita=20when=20available,=20so=20the?= =?UTF-8?q?=20emoji=20chooser=E2=80=99s=20category/menu=20symbolic=20icons?= =?UTF-8?q?=20resolve=20instead=20of=20showing=20placeholder=20squares.=20?= =?UTF-8?q?Invoked=20the=20new=20Win32=20icon-theme=20configuration=20imme?= =?UTF-8?q?diately=20after=20gtk=5Finit()=20so=20it=20applies=20before=20U?= =?UTF-8?q?I=20usage,=20including=20the=20emoji=20chooser=20popover=20crea?= =?UTF-8?q?ted=20from=20entries.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fe-gtk/fe-gtk.c | 80 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c index f823fdc8..46678e74 100644 --- a/src/fe-gtk/fe-gtk.c +++ b/src/fe-gtk/fe-gtk.c @@ -121,22 +121,90 @@ static void win32_set_gsettings_schema_dir (void) { char *base_path; + char *share_path; char *schema_path; - - if (g_getenv ("GSETTINGS_SCHEMA_DIR") != NULL) - return; + char *xdg_data_dirs; + char **xdg_parts; + gboolean have_share_path = FALSE; + gint i; base_path = g_win32_get_package_installation_directory_of_module (NULL); if (base_path == NULL) return; + share_path = g_build_filename (base_path, "share", NULL); + + /* Ensure GTK can discover bundled icon themes and other shared data. */ + xdg_data_dirs = g_strdup (g_getenv ("XDG_DATA_DIRS")); + if (xdg_data_dirs && *xdg_data_dirs) + { + xdg_parts = g_strsplit (xdg_data_dirs, G_SEARCHPATH_SEPARATOR_S, -1); + for (i = 0; xdg_parts[i] != NULL; i++) + { + if (g_ascii_strcasecmp (xdg_parts[i], share_path) == 0) + { + have_share_path = TRUE; + break; + } + } + g_strfreev (xdg_parts); + + if (!have_share_path) + { + char *updated = g_strdup_printf ("%s%c%s", share_path, + G_SEARCHPATH_SEPARATOR, + xdg_data_dirs); + g_setenv ("XDG_DATA_DIRS", updated, TRUE); + g_free (updated); + } + } + else + { + g_setenv ("XDG_DATA_DIRS", share_path, TRUE); + } + schema_path = g_build_filename (base_path, "share", "glib-2.0", "schemas", NULL); - if (g_file_test (schema_path, G_FILE_TEST_IS_DIR)) + if (g_getenv ("GSETTINGS_SCHEMA_DIR") == NULL + && g_file_test (schema_path, G_FILE_TEST_IS_DIR)) g_setenv ("GSETTINGS_SCHEMA_DIR", schema_path, FALSE); + g_free (xdg_data_dirs); + g_free (share_path); g_free (schema_path); g_free (base_path); } + +static void +win32_configure_icon_theme (void) +{ + GtkIconTheme *theme; + char *base_path; + char *icons_path; + char *adwaita_path; + + theme = gtk_icon_theme_get_default (); + if (!theme) + return; + + base_path = g_win32_get_package_installation_directory_of_module (NULL); + if (!base_path) + return; + + icons_path = g_build_filename (base_path, "share", "icons", NULL); + adwaita_path = g_build_filename (icons_path, "Adwaita", NULL); + + if (g_file_test (icons_path, G_FILE_TEST_IS_DIR)) + gtk_icon_theme_append_search_path (theme, icons_path); + + /* GtkEntry's emoji chooser uses symbolic category/menu icons only present in + * Adwaita in our Windows bundle. Force it when available. */ + if (g_file_test (adwaita_path, G_FILE_TEST_IS_DIR)) + gtk_icon_theme_set_custom_theme (theme, "Adwaita"); + + g_free (adwaita_path); + g_free (icons_path); + g_free (base_path); +} #endif int @@ -272,6 +340,10 @@ fe_args (int argc, char *argv[]) #endif gtk_init (&argc, &argv); +#ifdef WIN32 + win32_configure_icon_theme (); +#endif + #ifdef HAVE_GTK_MAC osx_app = g_object_new(GTKOSX_TYPE_APPLICATION, NULL); #endif From 5d4eec3b71e3512a2c66aba1ff9c66721c4fd40e Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 20:05:13 -0700 Subject: [PATCH 05/38] updated, fixed or replaced menu icons. --- data/icons/menu/dark/about.svg | 5 ++ data/icons/menu/dark/chanlist.svg | 5 ++ data/icons/menu/dark/clear.svg | 6 +++ data/icons/menu/dark/close.svg | 4 ++ data/icons/menu/dark/connect.svg | 5 ++ data/icons/menu/dark/detach.svg | 4 ++ data/icons/menu/dark/disconnect.svg | 5 ++ data/icons/menu/dark/find.svg | 5 ++ data/icons/menu/dark/help.svg | 5 ++ data/icons/menu/dark/join.svg | 5 ++ data/icons/menu/dark/load-plugin.svg | 6 +++ data/icons/menu/dark/new.svg | 5 ++ data/icons/menu/dark/preferences.svg | 4 ++ data/icons/menu/dark/quit.svg | 4 ++ data/icons/menu/dark/save.svg | 5 ++ data/icons/menu/dark/search.svg | 4 ++ data/icons/menu/light/about.svg | 5 ++ data/icons/menu/light/chanlist.svg | 5 ++ data/icons/menu/light/clear.svg | 6 +++ data/icons/menu/light/close.svg | 4 ++ data/icons/menu/light/connect.svg | 5 ++ data/icons/menu/light/detach.svg | 4 ++ data/icons/menu/light/disconnect.svg | 5 ++ data/icons/menu/light/find.svg | 5 ++ data/icons/menu/light/help.svg | 5 ++ data/icons/menu/light/join.svg | 5 ++ data/icons/menu/light/load-plugin.svg | 6 +++ data/icons/menu/light/new.svg | 5 ++ data/icons/menu/light/preferences.svg | 4 ++ data/icons/menu/light/quit.svg | 4 ++ data/icons/menu/light/save.svg | 5 ++ data/icons/menu/light/search.svg | 4 ++ data/zoitechat.gresource.xml | 34 ++++++++++++ src/fe-gtk/menu.c | 78 +++++++++++++++++++-------- 34 files changed, 244 insertions(+), 22 deletions(-) create mode 100644 data/icons/menu/dark/about.svg create mode 100644 data/icons/menu/dark/chanlist.svg create mode 100644 data/icons/menu/dark/clear.svg create mode 100644 data/icons/menu/dark/close.svg create mode 100644 data/icons/menu/dark/connect.svg create mode 100644 data/icons/menu/dark/detach.svg create mode 100644 data/icons/menu/dark/disconnect.svg create mode 100644 data/icons/menu/dark/find.svg create mode 100644 data/icons/menu/dark/help.svg create mode 100644 data/icons/menu/dark/join.svg create mode 100644 data/icons/menu/dark/load-plugin.svg create mode 100644 data/icons/menu/dark/new.svg create mode 100644 data/icons/menu/dark/preferences.svg create mode 100644 data/icons/menu/dark/quit.svg create mode 100644 data/icons/menu/dark/save.svg create mode 100644 data/icons/menu/dark/search.svg create mode 100644 data/icons/menu/light/about.svg create mode 100644 data/icons/menu/light/chanlist.svg create mode 100644 data/icons/menu/light/clear.svg create mode 100644 data/icons/menu/light/close.svg create mode 100644 data/icons/menu/light/connect.svg create mode 100644 data/icons/menu/light/detach.svg create mode 100644 data/icons/menu/light/disconnect.svg create mode 100644 data/icons/menu/light/find.svg create mode 100644 data/icons/menu/light/help.svg create mode 100644 data/icons/menu/light/join.svg create mode 100644 data/icons/menu/light/load-plugin.svg create mode 100644 data/icons/menu/light/new.svg create mode 100644 data/icons/menu/light/preferences.svg create mode 100644 data/icons/menu/light/quit.svg create mode 100644 data/icons/menu/light/save.svg create mode 100644 data/icons/menu/light/search.svg diff --git a/data/icons/menu/dark/about.svg b/data/icons/menu/dark/about.svg new file mode 100644 index 00000000..29ed7982 --- /dev/null +++ b/data/icons/menu/dark/about.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/dark/chanlist.svg b/data/icons/menu/dark/chanlist.svg new file mode 100644 index 00000000..d1875770 --- /dev/null +++ b/data/icons/menu/dark/chanlist.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/dark/clear.svg b/data/icons/menu/dark/clear.svg new file mode 100644 index 00000000..92241371 --- /dev/null +++ b/data/icons/menu/dark/clear.svg @@ -0,0 +1,6 @@ + diff --git a/data/icons/menu/dark/close.svg b/data/icons/menu/dark/close.svg new file mode 100644 index 00000000..b900bde1 --- /dev/null +++ b/data/icons/menu/dark/close.svg @@ -0,0 +1,4 @@ + diff --git a/data/icons/menu/dark/connect.svg b/data/icons/menu/dark/connect.svg new file mode 100644 index 00000000..23e9f7e1 --- /dev/null +++ b/data/icons/menu/dark/connect.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/dark/detach.svg b/data/icons/menu/dark/detach.svg new file mode 100644 index 00000000..5d27f27b --- /dev/null +++ b/data/icons/menu/dark/detach.svg @@ -0,0 +1,4 @@ + diff --git a/data/icons/menu/dark/disconnect.svg b/data/icons/menu/dark/disconnect.svg new file mode 100644 index 00000000..ac33ae30 --- /dev/null +++ b/data/icons/menu/dark/disconnect.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/dark/find.svg b/data/icons/menu/dark/find.svg new file mode 100644 index 00000000..da071ab0 --- /dev/null +++ b/data/icons/menu/dark/find.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/dark/help.svg b/data/icons/menu/dark/help.svg new file mode 100644 index 00000000..372b8148 --- /dev/null +++ b/data/icons/menu/dark/help.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/dark/join.svg b/data/icons/menu/dark/join.svg new file mode 100644 index 00000000..b7c79c33 --- /dev/null +++ b/data/icons/menu/dark/join.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/dark/load-plugin.svg b/data/icons/menu/dark/load-plugin.svg new file mode 100644 index 00000000..16a7ea74 --- /dev/null +++ b/data/icons/menu/dark/load-plugin.svg @@ -0,0 +1,6 @@ + diff --git a/data/icons/menu/dark/new.svg b/data/icons/menu/dark/new.svg new file mode 100644 index 00000000..6b5a7da2 --- /dev/null +++ b/data/icons/menu/dark/new.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/dark/preferences.svg b/data/icons/menu/dark/preferences.svg new file mode 100644 index 00000000..e9c6ad2b --- /dev/null +++ b/data/icons/menu/dark/preferences.svg @@ -0,0 +1,4 @@ + diff --git a/data/icons/menu/dark/quit.svg b/data/icons/menu/dark/quit.svg new file mode 100644 index 00000000..8fed449f --- /dev/null +++ b/data/icons/menu/dark/quit.svg @@ -0,0 +1,4 @@ + diff --git a/data/icons/menu/dark/save.svg b/data/icons/menu/dark/save.svg new file mode 100644 index 00000000..8525797c --- /dev/null +++ b/data/icons/menu/dark/save.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/dark/search.svg b/data/icons/menu/dark/search.svg new file mode 100644 index 00000000..a90679aa --- /dev/null +++ b/data/icons/menu/dark/search.svg @@ -0,0 +1,4 @@ + diff --git a/data/icons/menu/light/about.svg b/data/icons/menu/light/about.svg new file mode 100644 index 00000000..0b174910 --- /dev/null +++ b/data/icons/menu/light/about.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/light/chanlist.svg b/data/icons/menu/light/chanlist.svg new file mode 100644 index 00000000..d76e703e --- /dev/null +++ b/data/icons/menu/light/chanlist.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/light/clear.svg b/data/icons/menu/light/clear.svg new file mode 100644 index 00000000..bd8ab3c8 --- /dev/null +++ b/data/icons/menu/light/clear.svg @@ -0,0 +1,6 @@ + diff --git a/data/icons/menu/light/close.svg b/data/icons/menu/light/close.svg new file mode 100644 index 00000000..b3802887 --- /dev/null +++ b/data/icons/menu/light/close.svg @@ -0,0 +1,4 @@ + diff --git a/data/icons/menu/light/connect.svg b/data/icons/menu/light/connect.svg new file mode 100644 index 00000000..0ae90ca0 --- /dev/null +++ b/data/icons/menu/light/connect.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/light/detach.svg b/data/icons/menu/light/detach.svg new file mode 100644 index 00000000..1f24c1d5 --- /dev/null +++ b/data/icons/menu/light/detach.svg @@ -0,0 +1,4 @@ + diff --git a/data/icons/menu/light/disconnect.svg b/data/icons/menu/light/disconnect.svg new file mode 100644 index 00000000..07337c2f --- /dev/null +++ b/data/icons/menu/light/disconnect.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/light/find.svg b/data/icons/menu/light/find.svg new file mode 100644 index 00000000..534d74f2 --- /dev/null +++ b/data/icons/menu/light/find.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/light/help.svg b/data/icons/menu/light/help.svg new file mode 100644 index 00000000..b629f781 --- /dev/null +++ b/data/icons/menu/light/help.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/light/join.svg b/data/icons/menu/light/join.svg new file mode 100644 index 00000000..7e8bce9f --- /dev/null +++ b/data/icons/menu/light/join.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/light/load-plugin.svg b/data/icons/menu/light/load-plugin.svg new file mode 100644 index 00000000..e74500b2 --- /dev/null +++ b/data/icons/menu/light/load-plugin.svg @@ -0,0 +1,6 @@ + diff --git a/data/icons/menu/light/new.svg b/data/icons/menu/light/new.svg new file mode 100644 index 00000000..a63e69fb --- /dev/null +++ b/data/icons/menu/light/new.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/light/preferences.svg b/data/icons/menu/light/preferences.svg new file mode 100644 index 00000000..a69c4449 --- /dev/null +++ b/data/icons/menu/light/preferences.svg @@ -0,0 +1,4 @@ + diff --git a/data/icons/menu/light/quit.svg b/data/icons/menu/light/quit.svg new file mode 100644 index 00000000..c4141749 --- /dev/null +++ b/data/icons/menu/light/quit.svg @@ -0,0 +1,4 @@ + diff --git a/data/icons/menu/light/save.svg b/data/icons/menu/light/save.svg new file mode 100644 index 00000000..ac089f3a --- /dev/null +++ b/data/icons/menu/light/save.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/light/search.svg b/data/icons/menu/light/search.svg new file mode 100644 index 00000000..f2aa57d7 --- /dev/null +++ b/data/icons/menu/light/search.svg @@ -0,0 +1,4 @@ + diff --git a/data/zoitechat.gresource.xml b/data/zoitechat.gresource.xml index 889ef0f3..d4d87c3f 100644 --- a/data/zoitechat.gresource.xml +++ b/data/zoitechat.gresource.xml @@ -20,5 +20,39 @@ icons/tree_dialog.png icons/tree_server.png icons/tree_util.png + + icons/menu/light/new.svg + icons/menu/light/load-plugin.svg + icons/menu/light/detach.svg + icons/menu/light/close.svg + icons/menu/light/quit.svg + icons/menu/light/disconnect.svg + icons/menu/light/connect.svg + icons/menu/light/join.svg + icons/menu/light/chanlist.svg + icons/menu/light/preferences.svg + icons/menu/light/clear.svg + icons/menu/light/save.svg + icons/menu/light/search.svg + icons/menu/light/find.svg + icons/menu/light/help.svg + icons/menu/light/about.svg + + icons/menu/dark/new.svg + icons/menu/dark/load-plugin.svg + icons/menu/dark/detach.svg + icons/menu/dark/close.svg + icons/menu/dark/quit.svg + icons/menu/dark/disconnect.svg + icons/menu/dark/connect.svg + icons/menu/dark/join.svg + icons/menu/dark/chanlist.svg + icons/menu/dark/preferences.svg + icons/menu/dark/clear.svg + icons/menu/dark/save.svg + icons/menu/dark/search.svg + icons/menu/dark/find.svg + icons/menu/dark/help.svg + icons/menu/dark/about.svg diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 4f649445..de249755 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -1951,22 +1951,22 @@ menu_about (GtkWidget *wid, gpointer sess) } #if HAVE_GTK3 -#define ICON_NEW "document-new" -#define ICON_LOAD_PLUGIN "document-open" -#define ICON_DETACH "edit-redo" -#define ICON_CLOSE "window-close" -#define ICON_QUIT "application-exit" -#define ICON_DISCONNECT "network-disconnect" -#define ICON_CONNECT "network-connect" -#define ICON_JOIN "go-jump" -#define ICON_CHANLIST "view-list" -#define ICON_PREFERENCES "preferences-system" -#define ICON_CLEAR "edit-clear" -#define ICON_SAVE "document-save" -#define ICON_SEARCH "edit-find" -#define ICON_FIND "edit-find" -#define ICON_HELP "help-contents" -#define ICON_ABOUT "help-about" +#define ICON_NEW "zc-menu-new" +#define ICON_LOAD_PLUGIN "zc-menu-load-plugin" +#define ICON_DETACH "zc-menu-detach" +#define ICON_CLOSE "zc-menu-close" +#define ICON_QUIT "zc-menu-quit" +#define ICON_DISCONNECT "zc-menu-disconnect" +#define ICON_CONNECT "zc-menu-connect" +#define ICON_JOIN "zc-menu-join" +#define ICON_CHANLIST "zc-menu-chanlist" +#define ICON_PREFERENCES "zc-menu-preferences" +#define ICON_CLEAR "zc-menu-clear" +#define ICON_SAVE "zc-menu-save" +#define ICON_SEARCH "zc-menu-search" +#define ICON_FIND "zc-menu-find" +#define ICON_HELP "zc-menu-help" +#define ICON_ABOUT "zc-menu-about" #endif #if !HAVE_GTK3 #define ICON_NEW GTK_STOCK_NEW @@ -2036,7 +2036,7 @@ static struct mymenu mymenu[] = { {N_("_Disconnect"), menu_disconnect, ICON_DISCONNECT, M_MENUSTOCK, MENU_ID_DISCONNECT, 0, 1}, {N_("_Reconnect"), menu_reconnect, ICON_CONNECT, M_MENUSTOCK, MENU_ID_RECONNECT, 0, 1}, {N_("_Join a Channel" ELLIPSIS), menu_join, ICON_JOIN, M_MENUSTOCK, MENU_ID_JOIN, 0, 1}, - {N_("Channel _List"), menu_chanlist, ICON_CHANLIST, M_MENUITEM, 0, 0, 1}, + {N_("Channel _List"), menu_chanlist, ICON_CHANLIST, M_MENUSTOCK, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, #define AWAY_OFFSET (41) {N_("Marked _Away"), menu_away, 0, M_MENUTOG, MENU_ID_AWAY, 0, 1, GDK_KEY_a}, @@ -2115,6 +2115,13 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) GtkWidget *label_widget; GtkWidget *image = NULL; const char *icon_name; + const char *custom_icon = NULL; + GtkSettings *settings; + gboolean prefer_dark = FALSE; + char *theme_name = NULL; + char *theme_name_lower = NULL; + const char *theme_variant = "light"; + char *resource_path; #endif #if !HAVE_GTK3 GtkWidget *img; @@ -2123,11 +2130,38 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) if (is_stock) { #if HAVE_GTK3 - icon_name = gtkutil_icon_name_from_stock (stock_name); - if (!icon_name) - icon_name = stock_name; - if (icon_name) - image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); + icon_name = stock_name; + if (g_str_has_prefix (icon_name, "zc-menu-")) + { + custom_icon = icon_name + strlen ("zc-menu-"); + settings = gtk_settings_get_default (); + if (settings) + { + g_object_get (G_OBJECT (settings), "gtk-application-prefer-dark-theme", &prefer_dark, NULL); + g_object_get (G_OBJECT (settings), "gtk-theme-name", &theme_name, NULL); + } + + if (theme_name) + theme_name_lower = g_ascii_strdown (theme_name, -1); + if (prefer_dark || (theme_name_lower && g_strrstr (theme_name_lower, "dark"))) + theme_variant = "dark"; + + resource_path = g_strdup_printf ("/icons/menu/%s/%s.svg", theme_variant, custom_icon); + if (g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL)) + image = gtk_image_new_from_resource (resource_path); + g_free (resource_path); + g_free (theme_name_lower); + g_free (theme_name); + } + + if (!image) + { + icon_name = gtkutil_icon_name_from_stock (stock_name); + if (!icon_name) + icon_name = stock_name; + if (icon_name) + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); + } #endif #if !HAVE_GTK3 img = gtk_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); From 39aa63057ec0d0723b37fff0e2707442040e4b15 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 20:37:37 -0700 Subject: [PATCH 06/38] =?UTF-8?q?Added=20a=20centralized=20menu=5Fnew()=20?= =?UTF-8?q?helper=20in=20the=20GTK=20menu=20code=20that=20creates=20menus?= =?UTF-8?q?=20and=20disables=20GTK3=E2=80=99s=20reserved=20toggle=20gutter?= =?UTF-8?q?=20(gtk=5Fmenu=5Fset=5Freserve=5Ftoggle=5Fsize(...,=20FALSE)),?= =?UTF-8?q?=20which=20removes=20the=20awkward=20empty=20left-side=20spacin?= =?UTF-8?q?g=20for=20normal=20menu=20items.=20Updated=20menu=20constructio?= =?UTF-8?q?n=20callsites=20in=20the=20main=20menu=20paths=20(top-level,=20?= =?UTF-8?q?submenus,=20nick/url/channel=20context=20menus)=20to=20use=20me?= =?UTF-8?q?nu=5Fnew(),=20so=20the=20spacing=20fix=20applies=20broadly=20ac?= =?UTF-8?q?ross=20menus=20instead=20of=20only=20one=20location.=20Committe?= =?UTF-8?q?d=20the=20change=20on=20the=20current=20branch=20(976970f)=20an?= =?UTF-8?q?d=20created=20a=20PR=20record=20via=20the=20make=5Fpr=20tool.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fe-gtk/menu.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index de249755..86aa4297 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -65,6 +65,18 @@ static GSList *submenu_list; +static GtkWidget * +menu_new (void) +{ + GtkWidget *menu = gtk_menu_new (); + +#if HAVE_GTK3 + gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE); +#endif + + return menu; +} + enum { M_MENUITEM, @@ -388,7 +400,7 @@ menu_quick_sub (char *name, GtkWidget *menu, GtkWidget **sub_item_ret, int flags return menu; /* Code to add a submenu */ - sub_menu = gtk_menu_new (); + sub_menu = menu_new (); if (flags & XCMENU_MARKUP) { sub_item = gtk_menu_item_new_with_label (""); @@ -805,7 +817,7 @@ menu_nickmenu (session *sess, GdkEventButton *event, char *nick, int num_sel) { char buf[512]; struct User *user; - GtkWidget *submenu, *menu = gtk_menu_new (); + GtkWidget *submenu, *menu = menu_new (); g_free (str_copy); str_copy = g_strdup (nick); @@ -1040,7 +1052,7 @@ menu_urlmenu (GdkEventButton *event, char *url) g_free (str_copy); str_copy = g_strdup (url); - menu = gtk_menu_new (); + menu = menu_new (); /* more than 51 chars? Chop it */ if (g_utf8_strlen (str_copy, -1) >= 52) { @@ -1132,7 +1144,7 @@ menu_chanmenu (struct session *sess, GdkEventButton * event, char *chan) g_free (str_copy); str_copy = g_strdup (chan); - menu = gtk_menu_new (); + menu = menu_new (); menu_quick_item (0, chan, menu, XCMENU_SHADED, str_copy, 0); menu_quick_item (0, 0, menu, XCMENU_SHADED, str_copy, 0); @@ -2657,7 +2669,7 @@ menu_create_main (void *accel_group, int bar, int away, int toplevel, #endif } else - menu_bar = gtk_menu_new (); + menu_bar = menu_new (); /* /MENU needs to know this later */ g_object_set_data (G_OBJECT (menu_bar), "accel", accel_group); @@ -2753,7 +2765,7 @@ menu_create_main (void *accel_group, int bar, int away, int toplevel, case M_NEWMENU: if (menu) gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu); - item = menu = gtk_menu_new (); + item = menu = menu_new (); if (mymenu[i].id == MENU_ID_USERMENU) usermenu = menu; menu_item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text)); @@ -2839,7 +2851,7 @@ togitem: case M_MENUSUB: group = NULL; - submenu = gtk_menu_new (); + submenu = menu_new (); item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, TRUE); /* record the English name for /menu */ g_object_set_data (G_OBJECT (item), "name", mymenu[i].text); From 643ea9c7fb04444062ea78a957dcf21d54bcc7b2 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 20:39:12 -0700 Subject: [PATCH 07/38] =?UTF-8?q?Removed=20the=20Windows-specific=20forced?= =?UTF-8?q?=20Adwaita=20icon=20theme=20override=20from=20win32=5Fconfigure?= =?UTF-8?q?=5Ficon=5Ftheme(),=20so=20ZoiteChat=20will=20no=20longer=20swit?= =?UTF-8?q?ch=20to=20Adwaita=20at=20runtime=20and=20can=20use=20the=20app?= =?UTF-8?q?=E2=80=99s=20own=20icon=20assets=20from=20the=20configured=20ic?= =?UTF-8?q?on=20search=20path.=20Removed=20Adwaita=20icon=20bundle=20copy?= =?UTF-8?q?=20rules=20from=20the=20Windows=20packaging=20project=20(copy.v?= =?UTF-8?q?cxproj),=20so=20share/icons/Adwaita=20is=20no=20longer=20pulled?= =?UTF-8?q?=20into=20Windows=20build=20artifacts.=20Removed=20Adwaita=20ic?= =?UTF-8?q?on=20inclusion=20from=20the=20Windows=20installer=20manifest=20?= =?UTF-8?q?(zoitechat.iss.tt),=20so=20installer=20builds=20no=20longer=20s?= =?UTF-8?q?hip=20Adwaita=20icon=20files.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fe-gtk/fe-gtk.c | 8 -------- win32/copy/copy.vcxproj | 2 -- win32/installer/zoitechat.iss.tt | 1 - 3 files changed, 11 deletions(-) diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c index 46678e74..c75bc748 100644 --- a/src/fe-gtk/fe-gtk.c +++ b/src/fe-gtk/fe-gtk.c @@ -180,7 +180,6 @@ win32_configure_icon_theme (void) GtkIconTheme *theme; char *base_path; char *icons_path; - char *adwaita_path; theme = gtk_icon_theme_get_default (); if (!theme) @@ -191,17 +190,10 @@ win32_configure_icon_theme (void) return; icons_path = g_build_filename (base_path, "share", "icons", NULL); - adwaita_path = g_build_filename (icons_path, "Adwaita", NULL); if (g_file_test (icons_path, G_FILE_TEST_IS_DIR)) gtk_icon_theme_append_search_path (theme, icons_path); - /* GtkEntry's emoji chooser uses symbolic category/menu icons only present in - * Adwaita in our Windows bundle. Force it when available. */ - if (g_file_test (adwaita_path, G_FILE_TEST_IS_DIR)) - gtk_icon_theme_set_custom_theme (theme, "Adwaita"); - - g_free (adwaita_path); g_free (icons_path); g_free (base_path); } diff --git a/win32/copy/copy.vcxproj b/win32/copy/copy.vcxproj index f0d1b972..3ef04afe 100644 --- a/win32/copy/copy.vcxproj +++ b/win32/copy/copy.vcxproj @@ -88,7 +88,6 @@ - @@ -102,7 +101,6 @@ - diff --git a/win32/installer/zoitechat.iss.tt b/win32/installer/zoitechat.iss.tt index ff17bf6a..c06df2e4 100644 --- a/win32/installer/zoitechat.iss.tt +++ b/win32/installer/zoitechat.iss.tt @@ -114,7 +114,6 @@ Source: "cert.pem"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "share\xml\*"; DestDir: "{app}\share\xml"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs Source: "share\doc\*"; DestDir: "{app}\share\doc"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs Source: "share\themes\MS-Windows\*"; DestDir: "{app}\share\themes\MS-Windows"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs -Source: "share\icons\Adwaita\*"; DestDir: "{app}\share\icons\Adwaita"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs Source: "share\glib-2.0\schemas\*"; DestDir: "{app}\share\glib-2.0\schemas"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs Source: "share\locale\*"; DestDir: "{app}\share\locale"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: translations Source: "etc\fonts\*"; DestDir: "{app}\etc\fonts"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs From f90783c298f4be7d912415c60be6a67c792f5792 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 20:47:20 -0700 Subject: [PATCH 08/38] Updated Windows packaging to include all dependency-provided icon assets by adding a new DepsRootIcons item ($(DepsRoot)\share\icons\**\*) in win32/copy/copy.vcxproj. Added a corresponding copy step so those icons are emitted into the Windows release tree at $(ZoiteChatRel)\share\icons\..., ensuring parity with Linux icon availability in installed builds. --- win32/copy/copy.vcxproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/win32/copy/copy.vcxproj b/win32/copy/copy.vcxproj index 3ef04afe..63cc564c 100644 --- a/win32/copy/copy.vcxproj +++ b/win32/copy/copy.vcxproj @@ -86,6 +86,7 @@ + @@ -96,6 +97,7 @@ + @@ -114,4 +116,3 @@ - From 18632bc5fdab66b0a9349b46989e7fd0d0a823a0 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 20:51:13 -0700 Subject: [PATCH 09/38] =?UTF-8?q?Added=20a=20new=20tree-store=20column=20(?= =?UTF-8?q?COL=5FUNDERLINE)=20for=20channel=20rows=20so=20the=20UI=20can?= =?UTF-8?q?=20track=20underline=20state=20per=20channel=20entry=20in=20the?= =?UTF-8?q?=20channel=20list=20model.=20Initialized=20each=20new=20channel?= =?UTF-8?q?=20row=20with=20PANGO=5FUNDERLINE=5FNONE=20so=20only=20the=20ac?= =?UTF-8?q?tive=20channel=20gets=20emphasized.=20Updated=20tree=20selectio?= =?UTF-8?q?n=20handling=20to=20remove=20underline=20from=20the=20previousl?= =?UTF-8?q?y=20focused=20row=20and=20apply=20PANGO=5FUNDERLINE=5FSINGLE=20?= =?UTF-8?q?to=20the=20newly=20selected=20row,=20creating=20a=20clear=20?= =?UTF-8?q?=E2=80=9Ccurrently=20viewed=20channel=E2=80=9D=20indicator.=20B?= =?UTF-8?q?ound=20the=20channel=20name=20renderer=E2=80=99s=20underline=20?= =?UTF-8?q?property=20to=20the=20new=20model=20column=20so=20underline=20c?= =?UTF-8?q?hanges=20are=20reflected=20immediately=20in=20the=20channel=20l?= =?UTF-8?q?ist=20UI.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fe-gtk/chanview-tree.c | 21 ++++++++++++++++++++- src/fe-gtk/chanview.c | 9 ++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/fe-gtk/chanview-tree.c b/src/fe-gtk/chanview-tree.c index 7d3c351c..b4279de3 100644 --- a/src/fe-gtk/chanview-tree.c +++ b/src/fe-gtk/chanview-tree.c @@ -41,13 +41,28 @@ static void /* row selected callback */ cv_tree_sel_cb (GtkTreeSelection *sel, chanview *cv) { GtkTreeModel *model; + GtkTreeIter prev_iter; GtkTreeIter iter; chan *ch; + chan *prev_ch; + gboolean has_prev; + + has_prev = cv->focused && gtk_tree_store_iter_is_valid (cv->store, &cv->focused->iter); + if (has_prev) + prev_iter = cv->focused->iter; if (gtk_tree_selection_get_selected (sel, &model, &iter)) { gtk_tree_model_get (model, &iter, COL_CHAN, &ch, -1); + if (has_prev) + { + gtk_tree_model_get (model, &prev_iter, COL_CHAN, &prev_ch, -1); + if (prev_ch != ch) + gtk_tree_store_set (cv->store, &prev_iter, COL_UNDERLINE, PANGO_UNDERLINE_NONE, -1); + } + gtk_tree_store_set (cv->store, &iter, COL_UNDERLINE, PANGO_UNDERLINE_SINGLE, -1); + cv->focused = ch; cv->cb_focus (cv, ch, ch->tag, ch->userdata); } @@ -175,7 +190,11 @@ cv_tree_init (chanview *cv) g_object_set (G_OBJECT (renderer), "ypad", 0, NULL); gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1); gtk_tree_view_column_pack_start(col, renderer, TRUE); - gtk_tree_view_column_set_attributes (col, renderer, "text", COL_NAME, "attributes", COL_ATTR, NULL); + gtk_tree_view_column_set_attributes (col, renderer, + "text", COL_NAME, + "attributes", COL_ATTR, + "underline", COL_UNDERLINE, + NULL); gtk_tree_view_column_set_expand (col, TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); diff --git a/src/fe-gtk/chanview.c b/src/fe-gtk/chanview.c index f4055d54..90de36d7 100644 --- a/src/fe-gtk/chanview.c +++ b/src/fe-gtk/chanview.c @@ -35,6 +35,7 @@ #define COL_CHAN 1 /* (chan *) */ #define COL_ATTR 2 /* (PangoAttrList *) */ #define COL_PIXBUF 3 /* (GdkPixbuf *) */ +#define COL_UNDERLINE 4 /* (PangoUnderline) */ struct _chanview { @@ -310,8 +311,8 @@ chanview_new (int type, int trunc_len, gboolean sort, gboolean use_icons, chanview *cv; cv = g_new0 (chanview, 1); - cv->store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, - PANGO_TYPE_ATTR_LIST, GDK_TYPE_PIXBUF); + cv->store = gtk_tree_store_new (5, G_TYPE_STRING, G_TYPE_POINTER, + PANGO_TYPE_ATTR_LIST, GDK_TYPE_PIXBUF, G_TYPE_INT); #if HAVE_GTK3 cv->font_desc = font_desc; #else @@ -429,7 +430,9 @@ chanview_add_real (chanview *cv, char *name, void *family, void *userdata, memcpy (&(ch->iter), &iter, sizeof (iter)); gtk_tree_store_set (cv->store, &iter, COL_NAME, name, COL_CHAN, ch, - COL_PIXBUF, icon, -1); + COL_PIXBUF, icon, + COL_UNDERLINE, PANGO_UNDERLINE_NONE, + -1); cv->size++; if (!has_parent) From a078d00eef49076ce8ac02fa00434b21eba095ac Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 20:58:15 -0700 Subject: [PATCH 10/38] =?UTF-8?q?Updated=20GTK3=20tab=20dropdown=20icon=20?= =?UTF-8?q?constants=20to=20use=20ZoiteChat=E2=80=99s=20bundled=20zc-menu-?= =?UTF-8?q?*=20icon=20names=20(detach/close)=20instead=20of=20theme-depend?= =?UTF-8?q?ent=20names,=20so=20Windows=20builds=20render=20the=20intended?= =?UTF-8?q?=20menu=20icons=20consistently.=20Updated=20GTK3=20tray=20menu?= =?UTF-8?q?=20icon=20constants=20for=20Preferences/Quit=20to=20use=20bundl?= =?UTF-8?q?ed=20zc-menu-*=20icon=20names,=20fixing=20theme-missing=20icon?= =?UTF-8?q?=20issues=20in=20Windows=20menu/dropdown=20contexts.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fe-gtk/maingui.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index 9743264d..8a35b240 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -61,8 +61,8 @@ #endif #if HAVE_GTK3 -#define ICON_TAB_DETACH "edit-redo" -#define ICON_TAB_CLOSE "window-close" +#define ICON_TAB_DETACH "zc-menu-detach" +#define ICON_TAB_CLOSE "zc-menu-close" #define ICON_TAB_PREVIOUS "go-previous" #define ICON_TAB_NEXT "go-next" #define ICON_ENTRY_ERROR "dialog-error" From 0a5c95c6b4078b2f348f39873dd3c739e4d2c9b1 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 21:08:18 -0700 Subject: [PATCH 11/38] Fixed the Windows installer so it now installs GTK icon theme assets (share\icons) into the app directory. This ensures icon-name lookups used by menus/widgets can resolve real icons instead of placeholders on Windows installs. The change was made in the [Files] section by adding a recursive copy rule for share\icons\* under the libs component. --- win32/installer/zoitechat.iss.tt | 1 + 1 file changed, 1 insertion(+) diff --git a/win32/installer/zoitechat.iss.tt b/win32/installer/zoitechat.iss.tt index c06df2e4..5bfc4275 100644 --- a/win32/installer/zoitechat.iss.tt +++ b/win32/installer/zoitechat.iss.tt @@ -113,6 +113,7 @@ Source: "readme.url"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "cert.pem"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "share\xml\*"; DestDir: "{app}\share\xml"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs Source: "share\doc\*"; DestDir: "{app}\share\doc"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs +Source: "share\icons\*"; DestDir: "{app}\share\icons"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs Source: "share\themes\MS-Windows\*"; DestDir: "{app}\share\themes\MS-Windows"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs Source: "share\glib-2.0\schemas\*"; DestDir: "{app}\share\glib-2.0\schemas"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs Source: "share\locale\*"; DestDir: "{app}\share\locale"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: translations From afc490aa180ad523621f6394a7e1b63c2453af9b Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 21:19:22 -0700 Subject: [PATCH 12/38] Fixed GTK3 menu icon fallback handling so Windows no longer falls through to non-standard zc-menu-* icon IDs (which show as placeholders in many setups). The code now maps each custom menu icon key (new, connect, disconnect, save, help, etc.) to a concrete freedesktop icon name before calling gtk_image_new_from_icon_name(). Kept the existing preferred behavior intact: load bundled SVG menu icons from GResource first (light/dark variant), and only use fallback icon names when those resources are unavailable. --- src/fe-gtk/menu.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 86aa4297..50d9ccab 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -2134,6 +2134,7 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) char *theme_name_lower = NULL; const char *theme_variant = "light"; char *resource_path; + const char *custom_fallback_icon = NULL; #endif #if !HAVE_GTK3 GtkWidget *img; @@ -2166,9 +2167,45 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) g_free (theme_name); } + if (custom_icon) + { + if (g_str_equal (custom_icon, "new")) + custom_fallback_icon = "document-new"; + else if (g_str_equal (custom_icon, "load-plugin")) + custom_fallback_icon = "document-open"; + else if (g_str_equal (custom_icon, "detach")) + custom_fallback_icon = "view-restore"; + else if (g_str_equal (custom_icon, "close")) + custom_fallback_icon = "window-close"; + else if (g_str_equal (custom_icon, "quit")) + custom_fallback_icon = "application-exit"; + else if (g_str_equal (custom_icon, "disconnect")) + custom_fallback_icon = "network-offline"; + else if (g_str_equal (custom_icon, "connect")) + custom_fallback_icon = "network-transmit-receive"; + else if (g_str_equal (custom_icon, "join")) + custom_fallback_icon = "list-add"; + else if (g_str_equal (custom_icon, "chanlist")) + custom_fallback_icon = "view-list"; + else if (g_str_equal (custom_icon, "preferences")) + custom_fallback_icon = "preferences-system"; + else if (g_str_equal (custom_icon, "clear")) + custom_fallback_icon = "edit-clear"; + else if (g_str_equal (custom_icon, "save")) + custom_fallback_icon = "document-save"; + else if (g_str_equal (custom_icon, "search") || g_str_equal (custom_icon, "find")) + custom_fallback_icon = "edit-find"; + else if (g_str_equal (custom_icon, "help")) + custom_fallback_icon = "help-browser"; + else if (g_str_equal (custom_icon, "about")) + custom_fallback_icon = "help-about"; + } + if (!image) { icon_name = gtkutil_icon_name_from_stock (stock_name); + if (!icon_name && custom_fallback_icon) + icon_name = custom_fallback_icon; if (!icon_name) icon_name = stock_name; if (icon_name) From 1a920ba955169c0bd5a2bd062d9b6638e5de6180 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 21:30:51 -0700 Subject: [PATCH 13/38] I fixed the Windows runtime path so gdk-pixbuf can actually find/use its loader modules before GTK initializes, by adding win32_configure_pixbuf_loaders() and calling it in startup on Windows. This sets GDK_PIXBUF_MODULEDIR / GDK_PIXBUF_MODULE_FILE from the bundled install tree so SVG resources can render instead of placeholder icons. I also fixed Windows packaging to include what the SVG path needs at runtime: librsvg DLLs, gdk-pixbuf loader modules, and loaders.cache in the release bundle. --- src/fe-gtk/fe-gtk.c | 48 +++++++++++++++++++++++++++++++++++++++++ win32/copy/copy.vcxproj | 5 +++++ 2 files changed, 53 insertions(+) diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c index c75bc748..07bab186 100644 --- a/src/fe-gtk/fe-gtk.c +++ b/src/fe-gtk/fe-gtk.c @@ -174,6 +174,53 @@ win32_set_gsettings_schema_dir (void) g_free (base_path); } + +static void +win32_configure_pixbuf_loaders (void) +{ + char *base_path; + char *pixbuf_root; + GDir *versions; + const gchar *entry; + + base_path = g_win32_get_package_installation_directory_of_module (NULL); + if (!base_path) + return; + + pixbuf_root = g_build_filename (base_path, "lib", "gdk-pixbuf-2.0", NULL); + if (!g_file_test (pixbuf_root, G_FILE_TEST_IS_DIR)) + { + g_free (pixbuf_root); + g_free (base_path); + return; + } + + versions = g_dir_open (pixbuf_root, 0, NULL); + if (versions) + { + while ((entry = g_dir_read_name (versions)) != NULL) + { + char *module_dir = g_build_filename (pixbuf_root, entry, "loaders", NULL); + char *module_file = g_build_filename (pixbuf_root, entry, "loaders.cache", NULL); + + if (g_file_test (module_dir, G_FILE_TEST_IS_DIR)) + g_setenv ("GDK_PIXBUF_MODULEDIR", module_dir, TRUE); + if (g_file_test (module_file, G_FILE_TEST_EXISTS)) + g_setenv ("GDK_PIXBUF_MODULE_FILE", module_file, TRUE); + + g_free (module_file); + g_free (module_dir); + + if (g_getenv ("GDK_PIXBUF_MODULEDIR") != NULL) + break; + } + g_dir_close (versions); + } + + g_free (pixbuf_root); + g_free (base_path); +} + static void win32_configure_icon_theme (void) { @@ -307,6 +354,7 @@ fe_args (int argc, char *argv[]) #ifdef WIN32 win32_set_gsettings_schema_dir (); + win32_configure_pixbuf_loaders (); /* this is mainly for irc:// URL handling. When windows calls us from */ /* I.E, it doesn't give an option of "Start in" directory, like short */ diff --git a/win32/copy/copy.vcxproj b/win32/copy/copy.vcxproj index 63cc564c..5830519a 100644 --- a/win32/copy/copy.vcxproj +++ b/win32/copy/copy.vcxproj @@ -67,6 +67,7 @@ + @@ -82,6 +83,8 @@ + + @@ -95,6 +98,8 @@ + + From 9bdf654cbca479a9bb6ee497c7d823c4d712f7a4 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 21:46:46 -0700 Subject: [PATCH 14/38] =?UTF-8?q?Fixed=20the=20Windows=20packaging=20pipel?= =?UTF-8?q?ine=20to=20include=20the=20app=E2=80=99s=20bundled=20menu=20ico?= =?UTF-8?q?ns=20from=20data/icons/menu/**=20by=20adding=20a=20dedicated=20?= =?UTF-8?q?ZoiteChatMenuIcons=20item=20group=20in=20the=20copy=20project.?= =?UTF-8?q?=20This=20ensures=20both=20light=20and=20dark=20menu=20icon=20f?= =?UTF-8?q?iles=20are=20staged=20during=20Windows=20builds.=20Added=20an?= =?UTF-8?q?=20explicit=20copy=20step=20that=20places=20those=20menu=20icon?= =?UTF-8?q?s=20into=20$(ZoiteChatRel)\share\icons\menu\...,=20which=20is?= =?UTF-8?q?=20already=20included=20by=20the=20installer=E2=80=99s=20share\?= =?UTF-8?q?icons\*=20rule,=20so=20they=20now=20get=20installed=20on=20Wind?= =?UTF-8?q?ows.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- win32/copy/copy.vcxproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/win32/copy/copy.vcxproj b/win32/copy/copy.vcxproj index 5830519a..241dab13 100644 --- a/win32/copy/copy.vcxproj +++ b/win32/copy/copy.vcxproj @@ -90,6 +90,7 @@ + @@ -103,6 +104,7 @@ + @@ -120,4 +122,3 @@ - From 329a641adfbced9721c0f5b5566fa5927109a173 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 22:03:51 -0700 Subject: [PATCH 15/38] =?UTF-8?q?I=20added=20a=20Windows-specific=20fallba?= =?UTF-8?q?ck=20to=20load=20custom=20menu=20icons=20directly=20from=20the?= =?UTF-8?q?=20installed=20share/icons/menu//=20path=20when=20GRes?= =?UTF-8?q?ource=20lookup=20doesn=E2=80=99t=20return=20an=20icon.=20This?= =?UTF-8?q?=20uses=20g=5Fwin32=5Fget=5Fpackage=5Finstallation=5Fdirectory?= =?UTF-8?q?=5Fof=5Fmodule()=20plus=20g=5Fbuild=5Ffilename()=20to=20avoid?= =?UTF-8?q?=20separator/path=20issues.=20The=20new=20fallback=20tries=20*.?= =?UTF-8?q?svg=20first,=20then=20*.png,=20so=20if=20resources=20aren?= =?UTF-8?q?=E2=80=99t=20available=20at=20runtime=20but=20files=20were=20in?= =?UTF-8?q?stalled,=20menu=20icons=20still=20render.=20After=20that,=20the?= =?UTF-8?q?=20existing=20icon-name=20fallback=20chain=20still=20runs=20(cu?= =?UTF-8?q?stom=5Ffallback=5Ficon=20=E2=86=92=20stock=20mapping=20?= =?UTF-8?q?=E2=86=92=20stock=20name),=20so=20non-file-based=20fallback=20b?= =?UTF-8?q?ehavior=20is=20preserved.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fe-gtk/menu.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 50d9ccab..923d57cf 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -2201,11 +2201,46 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) custom_fallback_icon = "help-about"; } + if (!image && custom_icon) + { +#ifdef WIN32 + char *base_path = g_win32_get_package_installation_directory_of_module (NULL); + + if (base_path) + { + char *icons_menu_path = g_build_filename (base_path, "share", "icons", "menu", theme_variant, NULL); + char *filename = g_strconcat (custom_icon, ".svg", NULL); + char *icon_path = g_build_filename (icons_menu_path, filename, NULL); + + if (g_file_test (icon_path, G_FILE_TEST_EXISTS)) + image = gtk_image_new_from_file (icon_path); + + g_free (icon_path); + g_free (filename); + + if (!image) + { + filename = g_strconcat (custom_icon, ".png", NULL); + icon_path = g_build_filename (icons_menu_path, filename, NULL); + + if (g_file_test (icon_path, G_FILE_TEST_EXISTS)) + image = gtk_image_new_from_file (icon_path); + + g_free (icon_path); + g_free (filename); + } + + g_free (icons_menu_path); + g_free (base_path); + } +#endif + } + if (!image) { - icon_name = gtkutil_icon_name_from_stock (stock_name); - if (!icon_name && custom_fallback_icon) - icon_name = custom_fallback_icon; + icon_name = custom_fallback_icon ? custom_fallback_icon : gtkutil_icon_name_from_stock (stock_name); + if (!icon_name) + icon_name = gtkutil_icon_name_from_stock (stock_name); if (!icon_name) icon_name = stock_name; if (icon_name) From 15d918f1fb7bf56a9138a322b7f6a8d3a3487aa2 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 22:19:50 -0700 Subject: [PATCH 16/38] =?UTF-8?q?Added=20Windows-side=20icon=20theme=20fal?= =?UTF-8?q?lback=20logic=20in=20win32=5Fconfigure=5Ficon=5Ftheme=20that=20?= =?UTF-8?q?now=20checks=20(in=20addition=20to=20the=20existing=20/sh?= =?UTF-8?q?are/icons)=20these=20paths:=20=20=20=20=20ZOITECHAT=5FICON=5FPA?= =?UTF-8?q?TH=20(user=20override=20env=20var),=20=20=20=20=20current=20wor?= =?UTF-8?q?king=20directory=20+=20share/icons,=20=20=20=20=20argv[0]=20dir?= =?UTF-8?q?ectory=20+=20share/icons.=20=20=20=20=20Valid=20directories=20a?= =?UTF-8?q?re=20appended=20to=20GTK=E2=80=99s=20icon=20search=20path.=20Ad?= =?UTF-8?q?ded=20diagnostic=20logging=20so=20startup=20clearly=20reports?= =?UTF-8?q?=20either=20the=20selected=20icon=20path=20source/path=20or=20t?= =?UTF-8?q?hat=20none=20of=20the=20expected=20locations=20were=20usable,?= =?UTF-8?q?=20to=20speed=20up=20Windows=20missing-icon=20triage.=20Reused/?= =?UTF-8?q?stored=20the=20computed=20argv[0]=20directory=20in=20fe=5Fargs?= =?UTF-8?q?=20(via=20win32=5Fargv0=5Fdir)=20so=20it=20can=20be=20used=20bo?= =?UTF-8?q?th=20for=20chdir=20and=20for=20icon=20fallback=20resolution.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fe-gtk/fe-gtk.c | 70 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c index 07bab186..b7376750 100644 --- a/src/fe-gtk/fe-gtk.c +++ b/src/fe-gtk/fe-gtk.c @@ -117,6 +117,8 @@ create_msg_dialog (gchar *title, gchar *message) gtk_widget_destroy (dialog); } +static char *win32_argv0_dir; + static void win32_set_gsettings_schema_dir (void) { @@ -225,24 +227,66 @@ static void win32_configure_icon_theme (void) { GtkIconTheme *theme; + const char *env_icons_path; char *base_path; char *icons_path; + char *cwd_dir; + char *cwd_path; + char *argv0_icons_path; + const char *selected_source = NULL; + char *selected_path = NULL; + + #define WIN32_SET_ICON_PATH(source_name, path_value) \ + G_STMT_START { \ + if ((path_value) != NULL && g_file_test ((path_value), G_FILE_TEST_IS_DIR)) \ + { \ + gtk_icon_theme_append_search_path (theme, (path_value)); \ + if (selected_path == NULL) \ + { \ + selected_source = (source_name); \ + selected_path = g_strdup (path_value); \ + } \ + } \ + } G_STMT_END theme = gtk_icon_theme_get_default (); if (!theme) return; + env_icons_path = g_getenv ("ZOITECHAT_ICON_PATH"); + if (env_icons_path && *env_icons_path) + WIN32_SET_ICON_PATH ("ZOITECHAT_ICON_PATH", env_icons_path); + base_path = g_win32_get_package_installation_directory_of_module (NULL); - if (!base_path) - return; + if (base_path) + { + icons_path = g_build_filename (base_path, "share", "icons", NULL); + WIN32_SET_ICON_PATH ("module base", icons_path); + g_free (icons_path); + } - icons_path = g_build_filename (base_path, "share", "icons", NULL); + cwd_dir = g_get_current_dir (); + cwd_path = g_build_filename (cwd_dir, "share", "icons", NULL); + WIN32_SET_ICON_PATH ("current working directory", cwd_path); + g_free (cwd_path); + g_free (cwd_dir); - if (g_file_test (icons_path, G_FILE_TEST_IS_DIR)) - gtk_icon_theme_append_search_path (theme, icons_path); + if (win32_argv0_dir) + { + argv0_icons_path = g_build_filename (win32_argv0_dir, "share", "icons", NULL); + WIN32_SET_ICON_PATH ("argv[0] directory", argv0_icons_path); + g_free (argv0_icons_path); + } - g_free (icons_path); + if (selected_path) + g_message ("win32_configure_icon_theme: selected icon path (%s): %s", selected_source, selected_path); + else + g_message ("win32_configure_icon_theme: no usable icon path found (checked ZOITECHAT_ICON_PATH, module base/share/icons, cwd/share/icons, argv[0]/share/icons)"); + + g_free (selected_path); g_free (base_path); + + #undef WIN32_SET_ICON_PATH } #endif @@ -361,16 +405,10 @@ fe_args (int argc, char *argv[]) /* cuts can. So we have to set the current dir manually, to the path */ /* of the exe. */ { - char *tmp = g_strdup (argv[0]); - char *sl; - - sl = strrchr (tmp, G_DIR_SEPARATOR); - if (sl) - { - *sl = 0; - chdir (tmp); - } - g_free (tmp); + g_free (win32_argv0_dir); + win32_argv0_dir = g_path_get_dirname (argv[0]); + if (win32_argv0_dir) + chdir (win32_argv0_dir); } #endif From e8ca0a1213ec0ccda5f436a495c2412b428a7b67 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 22:50:34 -0700 Subject: [PATCH 17/38] attempting to fix menu icon loading issues on the windows build. --- src/fe-gtk/menu.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 923d57cf..95f4f380 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -2135,6 +2135,7 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) const char *theme_variant = "light"; char *resource_path; const char *custom_fallback_icon = NULL; + GdkPixbuf *custom_pixbuf = NULL; #endif #if !HAVE_GTK3 GtkWidget *img; @@ -2161,7 +2162,14 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) resource_path = g_strdup_printf ("/icons/menu/%s/%s.svg", theme_variant, custom_icon); if (g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL)) - image = gtk_image_new_from_resource (resource_path); + { + custom_pixbuf = gdk_pixbuf_new_from_resource (resource_path, NULL); + if (custom_pixbuf) + { + image = gtk_image_new_from_pixbuf (custom_pixbuf); + g_object_unref (custom_pixbuf); + } + } g_free (resource_path); g_free (theme_name_lower); g_free (theme_name); @@ -2213,7 +2221,14 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) char *icon_path = g_build_filename (icons_menu_path, filename, NULL); if (g_file_test (icon_path, G_FILE_TEST_EXISTS)) - image = gtk_image_new_from_file (icon_path); + { + custom_pixbuf = gdk_pixbuf_new_from_file (icon_path, NULL); + if (custom_pixbuf) + { + image = gtk_image_new_from_pixbuf (custom_pixbuf); + g_object_unref (custom_pixbuf); + } + } g_free (icon_path); g_free (filename); @@ -2224,7 +2239,14 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) icon_path = g_build_filename (icons_menu_path, filename, NULL); if (g_file_test (icon_path, G_FILE_TEST_EXISTS)) - image = gtk_image_new_from_file (icon_path); + { + custom_pixbuf = gdk_pixbuf_new_from_file (icon_path, NULL); + if (custom_pixbuf) + { + image = gtk_image_new_from_pixbuf (custom_pixbuf); + g_object_unref (custom_pixbuf); + } + } g_free (icon_path); g_free (filename); From e316413f6047372829499cd4ada5649d02a18d19 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 23:07:17 -0700 Subject: [PATCH 18/38] Added stronger icon fallback handling for zc-menu-* menu items (including Server dropdown icons and Preferences) by introducing alternate fallback icon names and choosing an alternate only when the primary fallback icon is unavailable in the active icon theme. This specifically improves connect, disconnect, join, and preferences cases on Windows theme variations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kept the custom resource/file loading path in place (resource SVG + installed file fallback), then layered the improved theme fallback selection after it so menu icons still resolve if resource decoding is unavailable. Added emoji entry fallback logic: if GTKโ€™s built-in show-emoji-icon leaves the secondary icon empty, the input box now picks the first available icon from a fallback list (face-smile-symbolic, face-smile, insert-emoticon-symbolic, insert-emoticon). --- src/fe-gtk/maingui.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index 8a35b240..e40a0e0b 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -3198,6 +3198,25 @@ static const char *mg_emoji_family_fallback = "Noto Color Emoji, Segoe UI Emoji, Apple Color Emoji, Twemoji Mozilla, EmojiOne Color"; #endif +static const char * +mg_find_available_icon_name (const char *const *icon_names) +{ + GtkIconTheme *theme; + int i; + + theme = gtk_icon_theme_get_default (); + if (!theme || !icon_names) + return NULL; + + for (i = 0; icon_names[i] != NULL; i++) + { + if (gtk_icon_theme_has_icon (theme, icon_names[i])) + return icon_names[i]; + } + + return NULL; +} + static gboolean mg_family_already_has_emoji (const gchar *family) { @@ -3520,6 +3539,16 @@ mg_create_entry (session *sess, GtkWidget *box) { GtkWidget *hbox, *but, *entry; session_gui *gui = sess->gui; +#if HAVE_GTK3 + const char *emoji_fallback_icon_names[] = { + "face-smile-symbolic", + "face-smile", + "insert-emoticon-symbolic", + "insert-emoticon", + NULL + }; + const char *emoji_fallback_icon_name; +#endif hbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), hbox, 0, 0, 0); @@ -3561,6 +3590,13 @@ mg_create_entry (session *sess, GtkWidget *box) #if HAVE_GTK3 g_object_set (G_OBJECT (entry), "show-emoji-icon", TRUE, NULL); + + if (gtk_entry_get_icon_storage_type (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY) + { + emoji_fallback_icon_name = mg_find_available_icon_name (emoji_fallback_icon_names); + if (emoji_fallback_icon_name) + gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, emoji_fallback_icon_name); + } #endif } From 335a8f4d6b4a90ca738438f963e1f76202c70f8c Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 23:12:34 -0700 Subject: [PATCH 19/38] Added stronger icon fallback handling for zc-menu-* menu items (including Server dropdown icons and Preferences) by introducing alternate fallback icon names and choosing an alternate only when the primary fallback icon is unavailable in the active icon theme. This specifically improves connect, disconnect, join, and preferences cases on Windows theme variations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kept the custom resource/file loading path in place (resource SVG + installed file fallback), then layered the improved theme fallback selection after it so menu icons still resolve if resource decoding is unavailable. Added emoji entry fallback logic: if GTKโ€™s built-in show-emoji-icon leaves the secondary icon empty, the input box now picks the first available icon from a fallback list (face-smile-symbolic, face-smile, insert-emoticon-symbolic, insert-emoticon) --- src/fe-gtk/menu.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 95f4f380..1661d6bd 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -2135,6 +2135,10 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) const char *theme_variant = "light"; char *resource_path; const char *custom_fallback_icon = NULL; +<<<<<<< ours +======= + const char *custom_alt_fallback_icon = NULL; +>>>>>>> theirs GdkPixbuf *custom_pixbuf = NULL; #endif #if !HAVE_GTK3 @@ -2188,15 +2192,27 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) else if (g_str_equal (custom_icon, "quit")) custom_fallback_icon = "application-exit"; else if (g_str_equal (custom_icon, "disconnect")) - custom_fallback_icon = "network-offline"; + { + custom_fallback_icon = "network-disconnect"; + custom_alt_fallback_icon = "network-offline"; + } else if (g_str_equal (custom_icon, "connect")) - custom_fallback_icon = "network-transmit-receive"; + { + custom_fallback_icon = "network-connect"; + custom_alt_fallback_icon = "network-transmit-receive"; + } else if (g_str_equal (custom_icon, "join")) + { custom_fallback_icon = "list-add"; + custom_alt_fallback_icon = "go-jump"; + } else if (g_str_equal (custom_icon, "chanlist")) custom_fallback_icon = "view-list"; else if (g_str_equal (custom_icon, "preferences")) + { custom_fallback_icon = "preferences-system"; + custom_alt_fallback_icon = "preferences-desktop"; + } else if (g_str_equal (custom_icon, "clear")) custom_fallback_icon = "edit-clear"; else if (g_str_equal (custom_icon, "save")) @@ -2260,9 +2276,18 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) if (!image) { + GtkIconTheme *icon_theme = gtk_icon_theme_get_default (); + icon_name = custom_fallback_icon ? custom_fallback_icon : gtkutil_icon_name_from_stock (stock_name); if (!icon_name) icon_name = gtkutil_icon_name_from_stock (stock_name); + + if (icon_theme && custom_alt_fallback_icon && icon_name && !gtk_icon_theme_has_icon (icon_theme, icon_name) + && gtk_icon_theme_has_icon (icon_theme, custom_alt_fallback_icon)) + { + icon_name = custom_alt_fallback_icon; + } + if (!icon_name) icon_name = stock_name; if (icon_name) From b5db1685da59e33345765e24154aaed296e3dc76 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 23:15:51 -0700 Subject: [PATCH 20/38] Removed the unresolved version-control conflict markers from create_icon_menu and kept the custom_alt_fallback_icon declaration intact so the later fallback icon assignments remain valid for compilation. --- src/fe-gtk/menu.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 1661d6bd..59414eb3 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -2135,10 +2135,7 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) const char *theme_variant = "light"; char *resource_path; const char *custom_fallback_icon = NULL; -<<<<<<< ours -======= const char *custom_alt_fallback_icon = NULL; ->>>>>>> theirs GdkPixbuf *custom_pixbuf = NULL; #endif #if !HAVE_GTK3 From 7af8f069e7b602980e9c22d81285050e82f4680f Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 23:26:26 -0700 Subject: [PATCH 21/38] Reworked the GTK3 menu icon pipeline so zc-menu-* entries now load from the bundled data/icons/menu assets only, with shared theme-variant detection (light/dark). Split menu icon loading by platform: Windows: loads from installed share/icons/menu//.svg. Non-Windows: loads from embedded GResource /icons/menu//.svg. Removed the old per-icon fallback mapping for zc-menu-* (system icon substitutions), so menu icons stay consistent with the exact bundled icon set; non-zc-menu-* stock behavior remains unchanged. --- src/fe-gtk/menu.c | 232 ++++++++++++++++++---------------------------- 1 file changed, 91 insertions(+), 141 deletions(-) diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 59414eb3..db478523 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -1999,6 +1999,91 @@ menu_about (GtkWidget *wid, gpointer sess) #define ICON_ABOUT GTK_STOCK_ABOUT #endif +#if HAVE_GTK3 +static const char * +menu_icon_theme_variant (void) +{ + GtkSettings *settings; + gboolean prefer_dark = FALSE; + char *theme_name = NULL; + char *theme_name_lower = NULL; + const char *theme_variant = "light"; + + settings = gtk_settings_get_default (); + if (settings) + { + g_object_get (G_OBJECT (settings), "gtk-application-prefer-dark-theme", &prefer_dark, NULL); + g_object_get (G_OBJECT (settings), "gtk-theme-name", &theme_name, NULL); + } + + if (theme_name) + theme_name_lower = g_ascii_strdown (theme_name, -1); + if (prefer_dark || (theme_name_lower && g_strrstr (theme_name_lower, "dark"))) + theme_variant = "dark"; + + g_free (theme_name_lower); + g_free (theme_name); + + return theme_variant; +} + +#ifdef WIN32 +static GtkWidget * +menu_icon_image_from_data_icons (const char *icon_name, const char *theme_variant) +{ + GtkWidget *image = NULL; + GdkPixbuf *custom_pixbuf = NULL; + char *base_path = g_win32_get_package_installation_directory_of_module (NULL); + + if (base_path) + { + char *icons_menu_path = g_build_filename (base_path, "share", "icons", "menu", theme_variant, NULL); + char *filename = g_strconcat (icon_name, ".svg", NULL); + char *icon_path = g_build_filename (icons_menu_path, filename, NULL); + + if (g_file_test (icon_path, G_FILE_TEST_EXISTS)) + { + custom_pixbuf = gdk_pixbuf_new_from_file (icon_path, NULL); + if (custom_pixbuf) + { + image = gtk_image_new_from_pixbuf (custom_pixbuf); + g_object_unref (custom_pixbuf); + } + } + + g_free (icon_path); + g_free (filename); + g_free (icons_menu_path); + g_free (base_path); + } + + return image; +} +#else +static GtkWidget * +menu_icon_image_from_data_icons (const char *icon_name, const char *theme_variant) +{ + GtkWidget *image = NULL; + GdkPixbuf *custom_pixbuf; + char *resource_path = g_strdup_printf ("/icons/menu/%s/%s.svg", theme_variant, icon_name); + + if (g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL)) + { + custom_pixbuf = gdk_pixbuf_new_from_resource (resource_path, NULL); + if (custom_pixbuf) + { + image = gtk_image_new_from_pixbuf (custom_pixbuf); + g_object_unref (custom_pixbuf); + } + } + + g_free (resource_path); + + return image; +} +#endif +#endif + static struct mymenu mymenu[] = { {N_("_ZoiteChat"), 0, 0, M_NEWMENU, MENU_ID_ZOITECHAT, 0, 1}, {N_("Network Li_st"), menu_open_server_list, (char *)&pix_book, M_MENUPIX, 0, 0, 1, GDK_KEY_s}, @@ -2128,15 +2213,7 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) GtkWidget *image = NULL; const char *icon_name; const char *custom_icon = NULL; - GtkSettings *settings; - gboolean prefer_dark = FALSE; - char *theme_name = NULL; - char *theme_name_lower = NULL; const char *theme_variant = "light"; - char *resource_path; - const char *custom_fallback_icon = NULL; - const char *custom_alt_fallback_icon = NULL; - GdkPixbuf *custom_pixbuf = NULL; #endif #if !HAVE_GTK3 GtkWidget *img; @@ -2149,145 +2226,18 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) if (g_str_has_prefix (icon_name, "zc-menu-")) { custom_icon = icon_name + strlen ("zc-menu-"); - settings = gtk_settings_get_default (); - if (settings) - { - g_object_get (G_OBJECT (settings), "gtk-application-prefer-dark-theme", &prefer_dark, NULL); - g_object_get (G_OBJECT (settings), "gtk-theme-name", &theme_name, NULL); - } - - if (theme_name) - theme_name_lower = g_ascii_strdown (theme_name, -1); - if (prefer_dark || (theme_name_lower && g_strrstr (theme_name_lower, "dark"))) - theme_variant = "dark"; - - resource_path = g_strdup_printf ("/icons/menu/%s/%s.svg", theme_variant, custom_icon); - if (g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL)) - { - custom_pixbuf = gdk_pixbuf_new_from_resource (resource_path, NULL); - if (custom_pixbuf) - { - image = gtk_image_new_from_pixbuf (custom_pixbuf); - g_object_unref (custom_pixbuf); - } - } - g_free (resource_path); - g_free (theme_name_lower); - g_free (theme_name); - } - - if (custom_icon) - { - if (g_str_equal (custom_icon, "new")) - custom_fallback_icon = "document-new"; - else if (g_str_equal (custom_icon, "load-plugin")) - custom_fallback_icon = "document-open"; - else if (g_str_equal (custom_icon, "detach")) - custom_fallback_icon = "view-restore"; - else if (g_str_equal (custom_icon, "close")) - custom_fallback_icon = "window-close"; - else if (g_str_equal (custom_icon, "quit")) - custom_fallback_icon = "application-exit"; - else if (g_str_equal (custom_icon, "disconnect")) - { - custom_fallback_icon = "network-disconnect"; - custom_alt_fallback_icon = "network-offline"; - } - else if (g_str_equal (custom_icon, "connect")) - { - custom_fallback_icon = "network-connect"; - custom_alt_fallback_icon = "network-transmit-receive"; - } - else if (g_str_equal (custom_icon, "join")) - { - custom_fallback_icon = "list-add"; - custom_alt_fallback_icon = "go-jump"; - } - else if (g_str_equal (custom_icon, "chanlist")) - custom_fallback_icon = "view-list"; - else if (g_str_equal (custom_icon, "preferences")) - { - custom_fallback_icon = "preferences-system"; - custom_alt_fallback_icon = "preferences-desktop"; - } - else if (g_str_equal (custom_icon, "clear")) - custom_fallback_icon = "edit-clear"; - else if (g_str_equal (custom_icon, "save")) - custom_fallback_icon = "document-save"; - else if (g_str_equal (custom_icon, "search") || g_str_equal (custom_icon, "find")) - custom_fallback_icon = "edit-find"; - else if (g_str_equal (custom_icon, "help")) - custom_fallback_icon = "help-browser"; - else if (g_str_equal (custom_icon, "about")) - custom_fallback_icon = "help-about"; - } - - if (!image && custom_icon) - { -#ifdef WIN32 - char *base_path = g_win32_get_package_installation_directory_of_module (NULL); - - if (base_path) - { - char *icons_menu_path = g_build_filename (base_path, "share", "icons", "menu", theme_variant, NULL); - char *filename = g_strconcat (custom_icon, ".svg", NULL); - char *icon_path = g_build_filename (icons_menu_path, filename, NULL); - - if (g_file_test (icon_path, G_FILE_TEST_EXISTS)) - { - custom_pixbuf = gdk_pixbuf_new_from_file (icon_path, NULL); - if (custom_pixbuf) - { - image = gtk_image_new_from_pixbuf (custom_pixbuf); - g_object_unref (custom_pixbuf); - } - } - - g_free (icon_path); - g_free (filename); - - if (!image) - { - filename = g_strconcat (custom_icon, ".png", NULL); - icon_path = g_build_filename (icons_menu_path, filename, NULL); - - if (g_file_test (icon_path, G_FILE_TEST_EXISTS)) - { - custom_pixbuf = gdk_pixbuf_new_from_file (icon_path, NULL); - if (custom_pixbuf) - { - image = gtk_image_new_from_pixbuf (custom_pixbuf); - g_object_unref (custom_pixbuf); - } - } - - g_free (icon_path); - g_free (filename); - } - - g_free (icons_menu_path); - g_free (base_path); - } -#endif + theme_variant = menu_icon_theme_variant (); + image = menu_icon_image_from_data_icons (custom_icon, theme_variant); + if (!image) + image = menu_icon_image_from_data_icons (custom_icon, "light"); } if (!image) { - GtkIconTheme *icon_theme = gtk_icon_theme_get_default (); - - icon_name = custom_fallback_icon ? custom_fallback_icon : gtkutil_icon_name_from_stock (stock_name); - if (!icon_name) - icon_name = gtkutil_icon_name_from_stock (stock_name); - - if (icon_theme && custom_alt_fallback_icon && icon_name && !gtk_icon_theme_has_icon (icon_theme, icon_name) - && gtk_icon_theme_has_icon (icon_theme, custom_alt_fallback_icon)) - { - icon_name = custom_alt_fallback_icon; - } - + icon_name = gtkutil_icon_name_from_stock (stock_name); if (!icon_name) icon_name = stock_name; - if (icon_name) + if (icon_name && !custom_icon) image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); } #endif From 01e890eb3fa7c582fb4f8bbf9e93cf14fbb70854 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 23:35:32 -0700 Subject: [PATCH 22/38] Updated GTK3 menu item rendering so any zc-menu-* icon passed into menu_quick_item() is treated as a bundled ZoiteChat menu icon and loaded via menu_icon_image_from_data_icons(...) using the active light/dark variant, which makes dynamic/custom menu entries use the same icon source as the main menu icons. Added GTK3 forward declarations for menu_icon_theme_variant() and menu_icon_image_from_data_icons() so menu_quick_item() can call those helpers before their later definitions in the file. Kept fallback behavior intact: if bundled icon loading fails, the code still falls back to icon-theme lookup by name. --- src/fe-gtk/menu.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index db478523..4b3f2c69 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -273,6 +273,11 @@ menu_toggle_item (char *label, GtkWidget *menu, void *callback, void *userdata, return item; } +#if HAVE_GTK3 +static const char *menu_icon_theme_variant (void); +static GtkWidget *menu_icon_image_from_data_icons (const char *icon_name, const char *theme_variant); +#endif + GtkWidget * menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, gpointer userdata, char *icon) @@ -281,6 +286,7 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, char *path; #if HAVE_GTK3 const char *icon_name = NULL; + const char *custom_icon = NULL; GtkWidget *box; GtkWidget *image = NULL; GtkWidget *label_widget; @@ -310,6 +316,8 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, icon_name = gtkutil_icon_name_from_stock (icon); if (!icon_name) icon_name = icon; + if (g_str_has_prefix (icon_name, "zc-menu-")) + custom_icon = icon_name + strlen ("zc-menu-"); #endif #if !HAVE_GTK3 img = gtk_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); @@ -321,7 +329,9 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, #if HAVE_GTK3 item = gtk_menu_item_new (); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - if (icon_name) + if (custom_icon) + image = menu_icon_image_from_data_icons (custom_icon, menu_icon_theme_variant ()); + if (!image && icon_name) image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); else if (img) image = img; From 8642d8bde4eda4acf3ac110a5785af3853b424cc Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 23:44:22 -0700 Subject: [PATCH 23/38] Updated the Network List menu entry to use the same menu icon mechanism as the other iconized menu items by switching it from M_MENUPIX (pix_book) to M_MENUSTOCK with a zc-menu-* icon name (zc-menu-network-list). Added the new network-list SVG icon in both light and dark variants under data/icons/menu, so it comes from the same icon set as the rest of the menu icons. Registered both new icon files in the compiled GResource manifest so they are available through the existing resource-loading path. --- data/icons/menu/dark/network-list.svg | 5 +++++ data/icons/menu/light/network-list.svg | 5 +++++ data/zoitechat.gresource.xml | 2 ++ src/fe-gtk/menu.c | 4 +++- 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 data/icons/menu/dark/network-list.svg create mode 100644 data/icons/menu/light/network-list.svg diff --git a/data/icons/menu/dark/network-list.svg b/data/icons/menu/dark/network-list.svg new file mode 100644 index 00000000..d1875770 --- /dev/null +++ b/data/icons/menu/dark/network-list.svg @@ -0,0 +1,5 @@ + diff --git a/data/icons/menu/light/network-list.svg b/data/icons/menu/light/network-list.svg new file mode 100644 index 00000000..d76e703e --- /dev/null +++ b/data/icons/menu/light/network-list.svg @@ -0,0 +1,5 @@ + diff --git a/data/zoitechat.gresource.xml b/data/zoitechat.gresource.xml index d4d87c3f..8ff44484 100644 --- a/data/zoitechat.gresource.xml +++ b/data/zoitechat.gresource.xml @@ -22,6 +22,7 @@ icons/tree_util.png icons/menu/light/new.svg + icons/menu/light/network-list.svg icons/menu/light/load-plugin.svg icons/menu/light/detach.svg icons/menu/light/close.svg @@ -39,6 +40,7 @@ icons/menu/light/about.svg icons/menu/dark/new.svg + icons/menu/dark/network-list.svg icons/menu/dark/load-plugin.svg icons/menu/dark/detach.svg icons/menu/dark/close.svg diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 4b3f2c69..e9d23756 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -1974,6 +1974,7 @@ menu_about (GtkWidget *wid, gpointer sess) #if HAVE_GTK3 #define ICON_NEW "zc-menu-new" +#define ICON_NETWORK_LIST "zc-menu-network-list" #define ICON_LOAD_PLUGIN "zc-menu-load-plugin" #define ICON_DETACH "zc-menu-detach" #define ICON_CLOSE "zc-menu-close" @@ -1992,6 +1993,7 @@ menu_about (GtkWidget *wid, gpointer sess) #endif #if !HAVE_GTK3 #define ICON_NEW GTK_STOCK_NEW +#define ICON_NETWORK_LIST GTK_STOCK_INDEX #define ICON_LOAD_PLUGIN GTK_STOCK_REVERT_TO_SAVED #define ICON_DETACH GTK_STOCK_REDO #define ICON_CLOSE GTK_STOCK_CLOSE @@ -2096,7 +2098,7 @@ menu_icon_image_from_data_icons (const char *icon_name, const char *theme_varian static struct mymenu mymenu[] = { {N_("_ZoiteChat"), 0, 0, M_NEWMENU, MENU_ID_ZOITECHAT, 0, 1}, - {N_("Network Li_st"), menu_open_server_list, (char *)&pix_book, M_MENUPIX, 0, 0, 1, GDK_KEY_s}, + {N_("Network Li_st"), menu_open_server_list, ICON_NETWORK_LIST, M_MENUSTOCK, 0, 0, 1, GDK_KEY_s}, {0, 0, 0, M_SEP, 0, 0, 0}, {N_("_New"), 0, ICON_NEW, M_MENUSUB, 0, 0, 1}, From bc2b1bd509670cef027d293fbbff8b488843f541 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 23:49:59 -0700 Subject: [PATCH 24/38] Standardized GTK3 menu-related icon constants to use the bundled zc-menu-* icon set (from data/icons/menu) in the places that had direct equivalents, including raw log, URL grabber, channel list actions, tray menu, and plugin load action. Updated menu_quick_item() so zc-menu-* icons now fall back to the light variant if the current theme variant is unavailable, which helps avoid missing icons. Added centralized zc-menu-* resource loading to gtkutil_image_new_from_stock() (theme-variant detection + light fallback), so menu/button icon rendering uses the same bundled source path consistently. --- src/fe-gtk/chanlist.c | 6 ++-- src/fe-gtk/gtkutil.c | 76 ++++++++++++++++++++++++++++++++++++++++ src/fe-gtk/menu.c | 4 +++ src/fe-gtk/plugin-tray.c | 4 +-- src/fe-gtk/plugingui.c | 2 +- src/fe-gtk/rawlog.c | 4 +-- src/fe-gtk/urlgrab.c | 4 +-- 7 files changed, 90 insertions(+), 10 deletions(-) diff --git a/src/fe-gtk/chanlist.c b/src/fe-gtk/chanlist.c index 0957da7a..22bec3b0 100644 --- a/src/fe-gtk/chanlist.c +++ b/src/fe-gtk/chanlist.c @@ -46,11 +46,11 @@ #include "custom-list.h" #if HAVE_GTK3 -#define ICON_CHANLIST_JOIN "go-jump" +#define ICON_CHANLIST_JOIN "zc-menu-join" #define ICON_CHANLIST_COPY "edit-copy" -#define ICON_CHANLIST_FIND "edit-find" +#define ICON_CHANLIST_FIND "zc-menu-find" #define ICON_CHANLIST_REFRESH "view-refresh" -#define ICON_CHANLIST_SAVE "document-save-as" +#define ICON_CHANLIST_SAVE "zc-menu-save" #endif #if !HAVE_GTK3 #define ICON_CHANLIST_JOIN GTK_STOCK_JUMP_TO diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index 9aa64ec1..e0074ea0 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -121,12 +121,88 @@ gtkutil_icon_name_from_stock (const char *stock_name) } #endif +#if HAVE_GTK3 +static const char * +gtkutil_menu_icon_theme_variant (void) +{ + GtkSettings *settings; + gboolean prefer_dark = FALSE; + char *theme_name = NULL; + char *theme_name_lower = NULL; + const char *theme_variant = "light"; + + settings = gtk_settings_get_default (); + if (settings) + { + g_object_get (G_OBJECT (settings), "gtk-application-prefer-dark-theme", &prefer_dark, NULL); + g_object_get (G_OBJECT (settings), "gtk-theme-name", &theme_name, NULL); + } + + if (theme_name) + theme_name_lower = g_ascii_strdown (theme_name, -1); + if (prefer_dark || (theme_name_lower && g_strrstr (theme_name_lower, "dark"))) + theme_variant = "dark"; + + g_free (theme_name_lower); + g_free (theme_name); + + return theme_variant; +} + +static GtkWidget * +gtkutil_menu_icon_image_new (const char *icon_name, GtkIconSize size) +{ + GtkWidget *image = NULL; + GdkPixbuf *pixbuf = NULL; + char *resource_path; + const char *variant; + + if (!icon_name || !g_str_has_prefix (icon_name, "zc-menu-")) + return NULL; + + variant = gtkutil_menu_icon_theme_variant (); + resource_path = g_strdup_printf ("/icons/menu/%s/%s.svg", variant, icon_name + strlen ("zc-menu-")); + if (!g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL)) + { + g_free (resource_path); + resource_path = g_strdup_printf ("/icons/menu/light/%s.svg", icon_name + strlen ("zc-menu-")); + } + + pixbuf = gdk_pixbuf_new_from_resource_at_scale (resource_path, -1, -1, TRUE, NULL); + if (pixbuf) + { + image = gtk_image_new_from_pixbuf (pixbuf); + g_object_unref (pixbuf); + } + + g_free (resource_path); + + if (image) + { + GtkIconSize tmp_size; + gint width; + gint height; + + tmp_size = size; + if (gtk_icon_size_lookup (tmp_size, &width, &height)) + gtk_image_set_pixel_size (GTK_IMAGE (image), MAX (width, height)); + } + + return image; +} +#endif + GtkWidget * gtkutil_image_new_from_stock (const char *stock, GtkIconSize size) { #if HAVE_GTK3 + GtkWidget *image; const char *icon_name = gtkutil_icon_name_from_stock (stock); + image = gtkutil_menu_icon_image_new (icon_name, size); + if (image) + return image; + return gtk_image_new_from_icon_name (icon_name, size); #elif !HAVE_GTK3 return gtk_image_new_from_stock (stock, size); diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index e9d23756..9df05f2d 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -330,7 +330,11 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, item = gtk_menu_item_new (); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); if (custom_icon) + { image = menu_icon_image_from_data_icons (custom_icon, menu_icon_theme_variant ()); + if (!image) + image = menu_icon_image_from_data_icons (custom_icon, "light"); + } if (!image && icon_name) image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); else if (img) diff --git a/src/fe-gtk/plugin-tray.c b/src/fe-gtk/plugin-tray.c index 9aa7104e..3971e796 100644 --- a/src/fe-gtk/plugin-tray.c +++ b/src/fe-gtk/plugin-tray.c @@ -43,8 +43,8 @@ typedef struct _GtkStatusIcon GtkStatusIcon; #include #endif #endif -#define ICON_TRAY_PREFERENCES "preferences-system" -#define ICON_TRAY_QUIT "application-exit" +#define ICON_TRAY_PREFERENCES "zc-menu-preferences" +#define ICON_TRAY_QUIT "zc-menu-quit" #else #define ICON_TRAY_PREFERENCES GTK_STOCK_PREFERENCES #define ICON_TRAY_QUIT GTK_STOCK_QUIT diff --git a/src/fe-gtk/plugingui.c b/src/fe-gtk/plugingui.c index 9d739a66..100f404a 100644 --- a/src/fe-gtk/plugingui.c +++ b/src/fe-gtk/plugingui.c @@ -65,7 +65,7 @@ plugingui_get_target_session (void) } #if HAVE_GTK3 -#define ICON_PLUGIN_LOAD "document-open" +#define ICON_PLUGIN_LOAD "zc-menu-load-plugin" #define ICON_PLUGIN_UNLOAD "edit-delete" #define ICON_PLUGIN_RELOAD "view-refresh" #endif diff --git a/src/fe-gtk/rawlog.c b/src/fe-gtk/rawlog.c index 89174cd2..dc8c1c1f 100644 --- a/src/fe-gtk/rawlog.c +++ b/src/fe-gtk/rawlog.c @@ -43,8 +43,8 @@ #include "fkeys.h" #if HAVE_GTK3 -#define ICON_RAWLOG_CLEAR "edit-clear" -#define ICON_RAWLOG_SAVE_AS "document-save-as" +#define ICON_RAWLOG_CLEAR "zc-menu-clear" +#define ICON_RAWLOG_SAVE_AS "zc-menu-save" #endif #if !HAVE_GTK3 #define ICON_RAWLOG_CLEAR GTK_STOCK_CLEAR diff --git a/src/fe-gtk/urlgrab.c b/src/fe-gtk/urlgrab.c index 6e481924..f9471756 100644 --- a/src/fe-gtk/urlgrab.c +++ b/src/fe-gtk/urlgrab.c @@ -34,9 +34,9 @@ #include "urlgrab.h" #if HAVE_GTK3 -#define ICON_URLGRAB_CLEAR "edit-clear" +#define ICON_URLGRAB_CLEAR "zc-menu-clear" #define ICON_URLGRAB_COPY "edit-copy" -#define ICON_URLGRAB_SAVE_AS "document-save-as" +#define ICON_URLGRAB_SAVE_AS "zc-menu-save" #endif #if !HAVE_GTK3 #define ICON_URLGRAB_CLEAR GTK_STOCK_CLEAR From ebf695abdf2c5248db9d4b3bd0889647e2ee8638 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 17 Feb 2026 23:56:49 -0700 Subject: [PATCH 25/38] Standardized GTK3 menu-related icon constants to the bundled zc-menu-* namespace so menu actions stop depending on mixed system-theme icon names (edit-copy, view-refresh, etc.) and instead use the same internal set. This was updated in channel list, plugin manager, URL grabber, and spell-entry menu definitions. Updated GTK3 icon rendering paths in affected UI helpers to call gtkutil_image_new_from_stock(...), which is the path that resolves zc-menu-* resources correctly and consistently from data/icons/menu (instead of raw theme lookup). Added new icons to the shared bundled menu icon set (light/dark) for copy, delete, add, remove, spell-check, and refresh, and registered them in the GResource manifest so they are always available at runtime. --- data/icons/menu/dark/add.svg | 3 +++ data/icons/menu/dark/copy.svg | 3 +++ data/icons/menu/dark/delete.svg | 3 +++ data/icons/menu/dark/refresh.svg | 3 +++ data/icons/menu/dark/remove.svg | 3 +++ data/icons/menu/dark/spell-check.svg | 3 +++ data/icons/menu/light/add.svg | 3 +++ data/icons/menu/light/copy.svg | 3 +++ data/icons/menu/light/delete.svg | 3 +++ data/icons/menu/light/refresh.svg | 3 +++ data/icons/menu/light/remove.svg | 3 +++ data/icons/menu/light/spell-check.svg | 3 +++ data/zoitechat.gresource.xml | 12 ++++++++++++ src/fe-gtk/chanlist.c | 8 ++++---- src/fe-gtk/plugingui.c | 6 +++--- src/fe-gtk/sexy-spell-entry.c | 8 ++++---- src/fe-gtk/urlgrab.c | 2 +- 17 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 data/icons/menu/dark/add.svg create mode 100644 data/icons/menu/dark/copy.svg create mode 100644 data/icons/menu/dark/delete.svg create mode 100644 data/icons/menu/dark/refresh.svg create mode 100644 data/icons/menu/dark/remove.svg create mode 100644 data/icons/menu/dark/spell-check.svg create mode 100644 data/icons/menu/light/add.svg create mode 100644 data/icons/menu/light/copy.svg create mode 100644 data/icons/menu/light/delete.svg create mode 100644 data/icons/menu/light/refresh.svg create mode 100644 data/icons/menu/light/remove.svg create mode 100644 data/icons/menu/light/spell-check.svg diff --git a/data/icons/menu/dark/add.svg b/data/icons/menu/dark/add.svg new file mode 100644 index 00000000..bcf1c2c2 --- /dev/null +++ b/data/icons/menu/dark/add.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/dark/copy.svg b/data/icons/menu/dark/copy.svg new file mode 100644 index 00000000..936b5ebd --- /dev/null +++ b/data/icons/menu/dark/copy.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/dark/delete.svg b/data/icons/menu/dark/delete.svg new file mode 100644 index 00000000..df61c508 --- /dev/null +++ b/data/icons/menu/dark/delete.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/dark/refresh.svg b/data/icons/menu/dark/refresh.svg new file mode 100644 index 00000000..a325b64e --- /dev/null +++ b/data/icons/menu/dark/refresh.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/dark/remove.svg b/data/icons/menu/dark/remove.svg new file mode 100644 index 00000000..63494850 --- /dev/null +++ b/data/icons/menu/dark/remove.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/dark/spell-check.svg b/data/icons/menu/dark/spell-check.svg new file mode 100644 index 00000000..24ebc5be --- /dev/null +++ b/data/icons/menu/dark/spell-check.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/light/add.svg b/data/icons/menu/light/add.svg new file mode 100644 index 00000000..4f91008c --- /dev/null +++ b/data/icons/menu/light/add.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/light/copy.svg b/data/icons/menu/light/copy.svg new file mode 100644 index 00000000..7fb9ada5 --- /dev/null +++ b/data/icons/menu/light/copy.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/light/delete.svg b/data/icons/menu/light/delete.svg new file mode 100644 index 00000000..d90217ac --- /dev/null +++ b/data/icons/menu/light/delete.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/light/refresh.svg b/data/icons/menu/light/refresh.svg new file mode 100644 index 00000000..735b7a2d --- /dev/null +++ b/data/icons/menu/light/refresh.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/light/remove.svg b/data/icons/menu/light/remove.svg new file mode 100644 index 00000000..c5c69f7c --- /dev/null +++ b/data/icons/menu/light/remove.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/light/spell-check.svg b/data/icons/menu/light/spell-check.svg new file mode 100644 index 00000000..af7af94a --- /dev/null +++ b/data/icons/menu/light/spell-check.svg @@ -0,0 +1,3 @@ + diff --git a/data/zoitechat.gresource.xml b/data/zoitechat.gresource.xml index 8ff44484..b42f4044 100644 --- a/data/zoitechat.gresource.xml +++ b/data/zoitechat.gresource.xml @@ -33,7 +33,13 @@ icons/menu/light/chanlist.svg icons/menu/light/preferences.svg icons/menu/light/clear.svg + icons/menu/light/copy.svg + icons/menu/light/delete.svg + icons/menu/light/add.svg + icons/menu/light/remove.svg + icons/menu/light/spell-check.svg icons/menu/light/save.svg + icons/menu/light/refresh.svg icons/menu/light/search.svg icons/menu/light/find.svg icons/menu/light/help.svg @@ -51,7 +57,13 @@ icons/menu/dark/chanlist.svg icons/menu/dark/preferences.svg icons/menu/dark/clear.svg + icons/menu/dark/copy.svg + icons/menu/dark/delete.svg + icons/menu/dark/add.svg + icons/menu/dark/remove.svg + icons/menu/dark/spell-check.svg icons/menu/dark/save.svg + icons/menu/dark/refresh.svg icons/menu/dark/search.svg icons/menu/dark/find.svg icons/menu/dark/help.svg diff --git a/src/fe-gtk/chanlist.c b/src/fe-gtk/chanlist.c index 22bec3b0..6a739dbc 100644 --- a/src/fe-gtk/chanlist.c +++ b/src/fe-gtk/chanlist.c @@ -47,9 +47,9 @@ #if HAVE_GTK3 #define ICON_CHANLIST_JOIN "zc-menu-join" -#define ICON_CHANLIST_COPY "edit-copy" +#define ICON_CHANLIST_COPY "zc-menu-copy" #define ICON_CHANLIST_FIND "zc-menu-find" -#define ICON_CHANLIST_REFRESH "view-refresh" +#define ICON_CHANLIST_REFRESH "zc-menu-refresh" #define ICON_CHANLIST_SAVE "zc-menu-save" #endif #if !HAVE_GTK3 @@ -132,7 +132,7 @@ chanlist_icon_button (const char *label, const char *icon_name, button = gtk_button_new_with_mnemonic (label); #if HAVE_GTK3 - image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); + image = gtkutil_image_new_from_stock (icon_name, GTK_ICON_SIZE_MENU); #elif !HAVE_GTK3 image = gtk_image_new_from_stock (icon_name, GTK_ICON_SIZE_MENU); #endif @@ -160,7 +160,7 @@ chanlist_icon_menu_item (const char *label, const char *icon_name, icon_name_gtk3 = gtkutil_icon_name_from_stock (icon_name); if (!icon_name_gtk3) icon_name_gtk3 = icon_name; - image = icon_name_gtk3 ? gtk_image_new_from_icon_name (icon_name_gtk3, GTK_ICON_SIZE_MENU) : NULL; + image = icon_name_gtk3 ? gtkutil_image_new_from_stock (icon_name_gtk3, GTK_ICON_SIZE_MENU) : NULL; label_widget = gtk_label_new_with_mnemonic (label); if (image) gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0); diff --git a/src/fe-gtk/plugingui.c b/src/fe-gtk/plugingui.c index 100f404a..91ad6814 100644 --- a/src/fe-gtk/plugingui.c +++ b/src/fe-gtk/plugingui.c @@ -66,8 +66,8 @@ plugingui_get_target_session (void) #if HAVE_GTK3 #define ICON_PLUGIN_LOAD "zc-menu-load-plugin" -#define ICON_PLUGIN_UNLOAD "edit-delete" -#define ICON_PLUGIN_RELOAD "view-refresh" +#define ICON_PLUGIN_UNLOAD "zc-menu-delete" +#define ICON_PLUGIN_RELOAD "zc-menu-refresh" #endif #if !HAVE_GTK3 #define ICON_PLUGIN_LOAD GTK_STOCK_REVERT_TO_SAVED @@ -85,7 +85,7 @@ plugingui_icon_button (GtkWidget *box, const char *label, GtkWidget *image; button = gtk_button_new_with_mnemonic (label); - image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); + image = gtkutil_image_new_from_stock (icon_name, GTK_ICON_SIZE_MENU); gtk_button_set_image (GTK_BUTTON (button), image); gtk_button_set_use_underline (GTK_BUTTON (button), TRUE); gtk_container_add (GTK_CONTAINER (box), button); diff --git a/src/fe-gtk/sexy-spell-entry.c b/src/fe-gtk/sexy-spell-entry.c index 74a1ff8e..1ba37786 100644 --- a/src/fe-gtk/sexy-spell-entry.c +++ b/src/fe-gtk/sexy-spell-entry.c @@ -60,9 +60,9 @@ #endif #if HAVE_GTK3 -#define ICON_ADD "list-add" -#define ICON_REMOVE "list-remove" -#define ICON_SPELL_CHECK "tools-check-spelling" +#define ICON_ADD "zc-menu-add" +#define ICON_REMOVE "zc-menu-remove" +#define ICON_SPELL_CHECK "zc-menu-spell-check" #endif #if !HAVE_GTK3 #define ICON_ADD GTK_STOCK_ADD @@ -737,7 +737,7 @@ sexy_spell_entry_icon_menu_item (const char *label, const char *stock_name) item = gtk_menu_item_new (); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); if (icon_name) - image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); + image = gtkutil_image_new_from_stock (icon_name, GTK_ICON_SIZE_MENU); label_widget = gtk_label_new_with_mnemonic (label); if (image) gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0); diff --git a/src/fe-gtk/urlgrab.c b/src/fe-gtk/urlgrab.c index f9471756..f71f7f60 100644 --- a/src/fe-gtk/urlgrab.c +++ b/src/fe-gtk/urlgrab.c @@ -35,7 +35,7 @@ #if HAVE_GTK3 #define ICON_URLGRAB_CLEAR "zc-menu-clear" -#define ICON_URLGRAB_COPY "edit-copy" +#define ICON_URLGRAB_COPY "zc-menu-copy" #define ICON_URLGRAB_SAVE_AS "zc-menu-save" #endif #if !HAVE_GTK3 From bdfabcf800854838caf3764da5a351b5d00d16fb Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 00:00:59 -0700 Subject: [PATCH 26/38] Standardized GTK3 menu icon resolution so stock-style menu icons are first mapped to the bundled zc-menu-* names (which are backed by data/icons/menu/...), but only for menu-sized icon requests. This keeps non-menu button icons unaffected while making menu icons consistent. Updated menu construction paths to resolve both zc-menu-* and legacy gtk-* stock names through one custom mapping before loading icons from the bundled menu icon assets, with fallback to light theme assets and then theme icon names. This affects both quick/user menus and standard icon menu items. --- src/fe-gtk/gtkutil.c | 58 ++++++++++++++++++++++++++++++++- src/fe-gtk/menu.c | 77 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 131 insertions(+), 4 deletions(-) diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index e0074ea0..eda10867 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -62,6 +62,53 @@ struct file_req int flags; /* FRF_* flags */ }; +#if HAVE_GTK3 +static const char * +gtkutil_menu_custom_icon_from_stock (const char *stock_name) +{ + static const struct + { + const char *stock; + const char *custom_icon; + } icon_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-refresh", "zc-menu-refresh" }, + { "gtk-justify-left", "zc-menu-search" }, + { "gtk-find", "zc-menu-find" }, + { "gtk-help", "zc-menu-help" }, + { "gtk-about", "zc-menu-about" }, + }; + size_t i; + + if (!stock_name) + return NULL; + + for (i = 0; i < G_N_ELEMENTS (icon_map); i++) + { + if (strcmp (stock_name, icon_map[i].stock) == 0) + return icon_map[i].custom_icon; + } + + return NULL; +} +#endif + #if HAVE_GTK3 const char * gtkutil_icon_name_from_stock (const char *stock_name) @@ -197,7 +244,16 @@ gtkutil_image_new_from_stock (const char *stock, GtkIconSize size) { #if HAVE_GTK3 GtkWidget *image; - const char *icon_name = gtkutil_icon_name_from_stock (stock); + const char *icon_name; + + icon_name = gtkutil_icon_name_from_stock (stock); + if (size == GTK_ICON_SIZE_MENU) + { + const char *menu_icon_name = gtkutil_menu_custom_icon_from_stock (stock); + + 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/menu.c b/src/fe-gtk/menu.c index 9df05f2d..4ed52c70 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -276,6 +276,74 @@ menu_toggle_item (char *label, GtkWidget *menu, void *callback, void *userdata, #if HAVE_GTK3 static const char *menu_icon_theme_variant (void); static GtkWidget *menu_icon_image_from_data_icons (const char *icon_name, const char *theme_variant); + +static const char * +menu_custom_icon_from_stock (const char *stock_name) +{ + static const struct + { + const char *stock; + const char *custom; + } icon_map[] = { + { "zc-menu-new", "new" }, + { "zc-menu-network-list", "network-list" }, + { "zc-menu-load-plugin", "load-plugin" }, + { "zc-menu-detach", "detach" }, + { "zc-menu-close", "close" }, + { "zc-menu-quit", "quit" }, + { "zc-menu-disconnect", "disconnect" }, + { "zc-menu-connect", "connect" }, + { "zc-menu-join", "join" }, + { "zc-menu-chanlist", "chanlist" }, + { "zc-menu-preferences", "preferences" }, + { "zc-menu-clear", "clear" }, + { "zc-menu-copy", "copy" }, + { "zc-menu-delete", "delete" }, + { "zc-menu-add", "add" }, + { "zc-menu-remove", "remove" }, + { "zc-menu-spell-check", "spell-check" }, + { "zc-menu-save", "save" }, + { "zc-menu-refresh", "refresh" }, + { "zc-menu-search", "search" }, + { "zc-menu-find", "find" }, + { "zc-menu-help", "help" }, + { "zc-menu-about", "about" }, + { "gtk-new", "new" }, + { "gtk-index", "network-list" }, + { "gtk-revert-to-saved", "load-plugin" }, + { "gtk-redo", "detach" }, + { "gtk-close", "close" }, + { "gtk-quit", "quit" }, + { "gtk-disconnect", "disconnect" }, + { "gtk-connect", "connect" }, + { "gtk-jump-to", "join" }, + { "gtk-preferences", "preferences" }, + { "gtk-clear", "clear" }, + { "gtk-copy", "copy" }, + { "gtk-delete", "delete" }, + { "gtk-add", "add" }, + { "gtk-remove", "remove" }, + { "gtk-spell-check", "spell-check" }, + { "gtk-save", "save" }, + { "gtk-refresh", "refresh" }, + { "gtk-justify-left", "search" }, + { "gtk-find", "find" }, + { "gtk-help", "help" }, + { "gtk-about", "about" }, + }; + size_t i; + + if (!stock_name) + return NULL; + + for (i = 0; i < G_N_ELEMENTS (icon_map); i++) + { + if (strcmp (stock_name, icon_map[i].stock) == 0) + return icon_map[i].custom; + } + + return NULL; +} #endif GtkWidget * @@ -316,7 +384,8 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, icon_name = gtkutil_icon_name_from_stock (icon); if (!icon_name) icon_name = icon; - if (g_str_has_prefix (icon_name, "zc-menu-")) + custom_icon = menu_custom_icon_from_stock (icon); + if (!custom_icon && g_str_has_prefix (icon_name, "zc-menu-")) custom_icon = icon_name + strlen ("zc-menu-"); #endif #if !HAVE_GTK3 @@ -2239,9 +2308,11 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) { #if HAVE_GTK3 icon_name = stock_name; - if (g_str_has_prefix (icon_name, "zc-menu-")) - { + custom_icon = menu_custom_icon_from_stock (stock_name); + if (!custom_icon && g_str_has_prefix (icon_name, "zc-menu-")) custom_icon = icon_name + strlen ("zc-menu-"); + if (custom_icon) + { theme_variant = menu_icon_theme_variant (); image = menu_icon_image_from_data_icons (custom_icon, theme_variant); if (!image) From b419804ddb0ab7597463eb850bed319717132bdd Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 00:05:44 -0700 Subject: [PATCH 27/38] Updated GTK3 icon resolution so gtkutil_image_new_from_stock() now preserves zc-menu-* icon IDs (when no stock-to-theme mapping exists), allowing those items to load directly from the data/icons/menu resource set instead of falling back inconsistently to theme icon names. Updated channel list popup menu icon creation to pass the original icon ID directly into the shared loader, so those menu items use the same icon pipeline and set as other menus (data/icons/menu). --- src/fe-gtk/chanlist.c | 6 +----- src/fe-gtk/gtkutil.c | 2 ++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/fe-gtk/chanlist.c b/src/fe-gtk/chanlist.c index 6a739dbc..eec1cbae 100644 --- a/src/fe-gtk/chanlist.c +++ b/src/fe-gtk/chanlist.c @@ -153,14 +153,10 @@ chanlist_icon_menu_item (const char *label, const char *icon_name, GtkWidget *box; GtkWidget *image = NULL; GtkWidget *label_widget; - const char *icon_name_gtk3; item = gtk_menu_item_new (); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - icon_name_gtk3 = gtkutil_icon_name_from_stock (icon_name); - if (!icon_name_gtk3) - icon_name_gtk3 = icon_name; - image = icon_name_gtk3 ? gtkutil_image_new_from_stock (icon_name_gtk3, GTK_ICON_SIZE_MENU) : NULL; + image = icon_name ? gtkutil_image_new_from_stock (icon_name, GTK_ICON_SIZE_MENU) : NULL; label_widget = gtk_label_new_with_mnemonic (label); if (image) gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0); diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index eda10867..7794b050 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -247,6 +247,8 @@ gtkutil_image_new_from_stock (const char *stock, GtkIconSize size) const char *icon_name; 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 = gtkutil_menu_custom_icon_from_stock (stock); From e347fdc899f3319537c433a3e955610d116a39b8 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 00:09:56 -0700 Subject: [PATCH 28/38] Unified GTK3 menu-item icon loading to use the same helper path everywhere (gtkutil_image_new_from_stock(..., GTK_ICON_SIZE_MENU)), so stock/menu icon names consistently resolve through the shared custom menu icon logic (which uses data/icons/menu first, then fallback). This was applied in menu_quick_item. Unified main menubar icon creation to the same helper in create_icon_menu, removing the separate/duplicated icon-mapping and platform-specific loading logic from menu.c. --- src/fe-gtk/menu.c | 201 +--------------------------------------------- 1 file changed, 3 insertions(+), 198 deletions(-) diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 4ed52c70..8882e553 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -273,79 +273,6 @@ menu_toggle_item (char *label, GtkWidget *menu, void *callback, void *userdata, return item; } -#if HAVE_GTK3 -static const char *menu_icon_theme_variant (void); -static GtkWidget *menu_icon_image_from_data_icons (const char *icon_name, const char *theme_variant); - -static const char * -menu_custom_icon_from_stock (const char *stock_name) -{ - static const struct - { - const char *stock; - const char *custom; - } icon_map[] = { - { "zc-menu-new", "new" }, - { "zc-menu-network-list", "network-list" }, - { "zc-menu-load-plugin", "load-plugin" }, - { "zc-menu-detach", "detach" }, - { "zc-menu-close", "close" }, - { "zc-menu-quit", "quit" }, - { "zc-menu-disconnect", "disconnect" }, - { "zc-menu-connect", "connect" }, - { "zc-menu-join", "join" }, - { "zc-menu-chanlist", "chanlist" }, - { "zc-menu-preferences", "preferences" }, - { "zc-menu-clear", "clear" }, - { "zc-menu-copy", "copy" }, - { "zc-menu-delete", "delete" }, - { "zc-menu-add", "add" }, - { "zc-menu-remove", "remove" }, - { "zc-menu-spell-check", "spell-check" }, - { "zc-menu-save", "save" }, - { "zc-menu-refresh", "refresh" }, - { "zc-menu-search", "search" }, - { "zc-menu-find", "find" }, - { "zc-menu-help", "help" }, - { "zc-menu-about", "about" }, - { "gtk-new", "new" }, - { "gtk-index", "network-list" }, - { "gtk-revert-to-saved", "load-plugin" }, - { "gtk-redo", "detach" }, - { "gtk-close", "close" }, - { "gtk-quit", "quit" }, - { "gtk-disconnect", "disconnect" }, - { "gtk-connect", "connect" }, - { "gtk-jump-to", "join" }, - { "gtk-preferences", "preferences" }, - { "gtk-clear", "clear" }, - { "gtk-copy", "copy" }, - { "gtk-delete", "delete" }, - { "gtk-add", "add" }, - { "gtk-remove", "remove" }, - { "gtk-spell-check", "spell-check" }, - { "gtk-save", "save" }, - { "gtk-refresh", "refresh" }, - { "gtk-justify-left", "search" }, - { "gtk-find", "find" }, - { "gtk-help", "help" }, - { "gtk-about", "about" }, - }; - size_t i; - - if (!stock_name) - return NULL; - - for (i = 0; i < G_N_ELEMENTS (icon_map); i++) - { - if (strcmp (stock_name, icon_map[i].stock) == 0) - return icon_map[i].custom; - } - - return NULL; -} -#endif - GtkWidget * menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, gpointer userdata, char *icon) @@ -353,8 +280,6 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, GtkWidget *img, *item; char *path; #if HAVE_GTK3 - const char *icon_name = NULL; - const char *custom_icon = NULL; GtkWidget *box; GtkWidget *image = NULL; GtkWidget *label_widget; @@ -381,12 +306,7 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, else { #if HAVE_GTK3 - icon_name = gtkutil_icon_name_from_stock (icon); - if (!icon_name) - icon_name = icon; - custom_icon = menu_custom_icon_from_stock (icon); - if (!custom_icon && g_str_has_prefix (icon_name, "zc-menu-")) - custom_icon = icon_name + strlen ("zc-menu-"); + img = gtkutil_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); #endif #if !HAVE_GTK3 img = gtk_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); @@ -398,15 +318,7 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, #if HAVE_GTK3 item = gtk_menu_item_new (); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - if (custom_icon) - { - image = menu_icon_image_from_data_icons (custom_icon, menu_icon_theme_variant ()); - if (!image) - image = menu_icon_image_from_data_icons (custom_icon, "light"); - } - if (!image && icon_name) - image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); - else if (img) + if (img) image = img; label_widget = gtk_label_new_with_mnemonic (label); if (image) @@ -2084,91 +1996,6 @@ menu_about (GtkWidget *wid, gpointer sess) #define ICON_ABOUT GTK_STOCK_ABOUT #endif -#if HAVE_GTK3 -static const char * -menu_icon_theme_variant (void) -{ - GtkSettings *settings; - gboolean prefer_dark = FALSE; - char *theme_name = NULL; - char *theme_name_lower = NULL; - const char *theme_variant = "light"; - - settings = gtk_settings_get_default (); - if (settings) - { - g_object_get (G_OBJECT (settings), "gtk-application-prefer-dark-theme", &prefer_dark, NULL); - g_object_get (G_OBJECT (settings), "gtk-theme-name", &theme_name, NULL); - } - - if (theme_name) - theme_name_lower = g_ascii_strdown (theme_name, -1); - if (prefer_dark || (theme_name_lower && g_strrstr (theme_name_lower, "dark"))) - theme_variant = "dark"; - - g_free (theme_name_lower); - g_free (theme_name); - - return theme_variant; -} - -#ifdef WIN32 -static GtkWidget * -menu_icon_image_from_data_icons (const char *icon_name, const char *theme_variant) -{ - GtkWidget *image = NULL; - GdkPixbuf *custom_pixbuf = NULL; - char *base_path = g_win32_get_package_installation_directory_of_module (NULL); - - if (base_path) - { - char *icons_menu_path = g_build_filename (base_path, "share", "icons", "menu", theme_variant, NULL); - char *filename = g_strconcat (icon_name, ".svg", NULL); - char *icon_path = g_build_filename (icons_menu_path, filename, NULL); - - if (g_file_test (icon_path, G_FILE_TEST_EXISTS)) - { - custom_pixbuf = gdk_pixbuf_new_from_file (icon_path, NULL); - if (custom_pixbuf) - { - image = gtk_image_new_from_pixbuf (custom_pixbuf); - g_object_unref (custom_pixbuf); - } - } - - g_free (icon_path); - g_free (filename); - g_free (icons_menu_path); - g_free (base_path); - } - - return image; -} -#else -static GtkWidget * -menu_icon_image_from_data_icons (const char *icon_name, const char *theme_variant) -{ - GtkWidget *image = NULL; - GdkPixbuf *custom_pixbuf; - char *resource_path = g_strdup_printf ("/icons/menu/%s/%s.svg", theme_variant, icon_name); - - if (g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL)) - { - custom_pixbuf = gdk_pixbuf_new_from_resource (resource_path, NULL); - if (custom_pixbuf) - { - image = gtk_image_new_from_pixbuf (custom_pixbuf); - g_object_unref (custom_pixbuf); - } - } - - g_free (resource_path); - - return image; -} -#endif -#endif - static struct mymenu mymenu[] = { {N_("_ZoiteChat"), 0, 0, M_NEWMENU, MENU_ID_ZOITECHAT, 0, 1}, {N_("Network Li_st"), menu_open_server_list, ICON_NETWORK_LIST, M_MENUSTOCK, 0, 0, 1, GDK_KEY_s}, @@ -2296,9 +2123,6 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) GtkWidget *box; GtkWidget *label_widget; GtkWidget *image = NULL; - const char *icon_name; - const char *custom_icon = NULL; - const char *theme_variant = "light"; #endif #if !HAVE_GTK3 GtkWidget *img; @@ -2307,26 +2131,7 @@ create_icon_menu (char *labeltext, void *stock_name, int is_stock) if (is_stock) { #if HAVE_GTK3 - icon_name = stock_name; - custom_icon = menu_custom_icon_from_stock (stock_name); - if (!custom_icon && g_str_has_prefix (icon_name, "zc-menu-")) - custom_icon = icon_name + strlen ("zc-menu-"); - if (custom_icon) - { - theme_variant = menu_icon_theme_variant (); - image = menu_icon_image_from_data_icons (custom_icon, theme_variant); - if (!image) - image = menu_icon_image_from_data_icons (custom_icon, "light"); - } - - if (!image) - { - icon_name = gtkutil_icon_name_from_stock (stock_name); - if (!icon_name) - icon_name = stock_name; - if (icon_name && !custom_icon) - image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); - } + image = gtkutil_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); #endif #if !HAVE_GTK3 img = gtk_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); From fcf00ebd8fc1c78a09fe53ac31ebe80b16d6903a Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 00:16:04 -0700 Subject: [PATCH 29/38] Updated menu-item icon resolution in menu_quick_item() to always go through gtkutil_image_new_from_stock(..., GTK_ICON_SIZE_MENU) when not loading from a file path, so icon-bearing menu items consistently use the same icon pipeline. Standardized the main menu icon identifiers to the zc-menu-* set (the icon set backed by data/icons/menu) across builds, instead of splitting between custom IDs and GTK stock IDs. Updated create_icon_menu() to use the same stock-to-image helper for stock-backed menu entries, so all menu icons follow the same resolution logic. Added a non-GTK3 compatibility mapper that converts zc-menu-* icon IDs to GTK stock names before calling gtk_image_new_from_stock, keeping behavior consistent on older GTK platforms while still using the unified zc-menu-* identifiers in menu definitions. --- src/fe-gtk/gtkutil.c | 50 +++++++++++++++++++++++++++++++++++++++++ src/fe-gtk/menu.c | 53 +++++--------------------------------------- 2 files changed, 56 insertions(+), 47 deletions(-) diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index 7794b050..1a005c66 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -109,6 +109,54 @@ gtkutil_menu_custom_icon_from_stock (const char *stock_name) } #endif +#if !HAVE_GTK3 +static const char * +gtkutil_stock_from_menu_custom_icon (const char *custom_icon) +{ + static const struct + { + const char *custom_icon; + const char *stock; + } icon_map[] = { + { "zc-menu-new", GTK_STOCK_NEW }, + { "zc-menu-network-list", GTK_STOCK_INDEX }, + { "zc-menu-load-plugin", GTK_STOCK_REVERT_TO_SAVED }, + { "zc-menu-detach", GTK_STOCK_REDO }, + { "zc-menu-close", GTK_STOCK_CLOSE }, + { "zc-menu-quit", GTK_STOCK_QUIT }, + { "zc-menu-disconnect", GTK_STOCK_DISCONNECT }, + { "zc-menu-connect", GTK_STOCK_CONNECT }, + { "zc-menu-join", GTK_STOCK_JUMP_TO }, + { "zc-menu-chanlist", GTK_STOCK_INDEX }, + { "zc-menu-preferences", GTK_STOCK_PREFERENCES }, + { "zc-menu-clear", GTK_STOCK_CLEAR }, + { "zc-menu-copy", GTK_STOCK_COPY }, + { "zc-menu-delete", GTK_STOCK_DELETE }, + { "zc-menu-add", GTK_STOCK_ADD }, + { "zc-menu-remove", GTK_STOCK_REMOVE }, + { "zc-menu-spell-check", GTK_STOCK_SPELL_CHECK }, + { "zc-menu-save", GTK_STOCK_SAVE }, + { "zc-menu-refresh", GTK_STOCK_REFRESH }, + { "zc-menu-search", GTK_STOCK_JUSTIFY_LEFT }, + { "zc-menu-find", GTK_STOCK_FIND }, + { "zc-menu-help", GTK_STOCK_HELP }, + { "zc-menu-about", GTK_STOCK_ABOUT }, + }; + size_t i; + + if (!custom_icon) + return NULL; + + for (i = 0; i < G_N_ELEMENTS (icon_map); i++) + { + if (strcmp (custom_icon, icon_map[i].custom_icon) == 0) + return icon_map[i].stock; + } + + return custom_icon; +} +#endif + #if HAVE_GTK3 const char * gtkutil_icon_name_from_stock (const char *stock_name) @@ -263,6 +311,8 @@ gtkutil_image_new_from_stock (const char *stock, GtkIconSize size) return gtk_image_new_from_icon_name (icon_name, size); #elif !HAVE_GTK3 + if (stock && g_str_has_prefix (stock, "zc-menu-")) + stock = gtkutil_stock_from_menu_custom_icon (stock); return gtk_image_new_from_stock (stock, size); #endif } diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 8882e553..d2e7cc08 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -304,14 +304,7 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, if (access (path, R_OK) == 0) img = gtk_image_new_from_file (path); else - { -#if HAVE_GTK3 img = gtkutil_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); -#endif -#if !HAVE_GTK3 - img = gtk_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); -#endif - } g_free (path); } @@ -1957,7 +1950,6 @@ menu_about (GtkWidget *wid, gpointer sess) gtk_widget_show_all (GTK_WIDGET(dialog)); } -#if HAVE_GTK3 #define ICON_NEW "zc-menu-new" #define ICON_NETWORK_LIST "zc-menu-network-list" #define ICON_LOAD_PLUGIN "zc-menu-load-plugin" @@ -1975,26 +1967,6 @@ menu_about (GtkWidget *wid, gpointer sess) #define ICON_FIND "zc-menu-find" #define ICON_HELP "zc-menu-help" #define ICON_ABOUT "zc-menu-about" -#endif -#if !HAVE_GTK3 -#define ICON_NEW GTK_STOCK_NEW -#define ICON_NETWORK_LIST GTK_STOCK_INDEX -#define ICON_LOAD_PLUGIN GTK_STOCK_REVERT_TO_SAVED -#define ICON_DETACH GTK_STOCK_REDO -#define ICON_CLOSE GTK_STOCK_CLOSE -#define ICON_QUIT GTK_STOCK_QUIT -#define ICON_DISCONNECT GTK_STOCK_DISCONNECT -#define ICON_CONNECT GTK_STOCK_CONNECT -#define ICON_JOIN GTK_STOCK_JUMP_TO -#define ICON_CHANLIST GTK_STOCK_INDEX -#define ICON_PREFERENCES GTK_STOCK_PREFERENCES -#define ICON_CLEAR GTK_STOCK_CLEAR -#define ICON_SAVE GTK_STOCK_SAVE -#define ICON_SEARCH GTK_STOCK_JUSTIFY_LEFT -#define ICON_FIND GTK_STOCK_FIND -#define ICON_HELP GTK_STOCK_HELP -#define ICON_ABOUT GTK_STOCK_ABOUT -#endif static struct mymenu mymenu[] = { {N_("_ZoiteChat"), 0, 0, M_NEWMENU, MENU_ID_ZOITECHAT, 0, 1}, @@ -2119,43 +2091,30 @@ GtkWidget * create_icon_menu (char *labeltext, void *stock_name, int is_stock) { GtkWidget *item; + GtkWidget *img = NULL; #if HAVE_GTK3 GtkWidget *box; GtkWidget *label_widget; - GtkWidget *image = NULL; -#endif -#if !HAVE_GTK3 - GtkWidget *img; #endif if (is_stock) { -#if HAVE_GTK3 - image = gtkutil_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); -#endif -#if !HAVE_GTK3 - img = gtk_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); -#endif + img = gtkutil_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); } else { -#if HAVE_GTK3 - image = gtk_image_new_from_pixbuf (*((GdkPixbuf **)stock_name)); -#endif -#if !HAVE_GTK3 img = gtk_image_new_from_pixbuf (*((GdkPixbuf **)stock_name)); -#endif } #if HAVE_GTK3 item = gtk_menu_item_new (); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); label_widget = gtk_label_new_with_mnemonic (labeltext); - if (image) - gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0); + if (img) + gtk_box_pack_start (GTK_BOX (box), img, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), label_widget, FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (item), box); - if (image) - gtk_widget_show (image); + if (img) + gtk_widget_show (img); gtk_widget_show (label_widget); gtk_widget_show (box); #else From 17f239e6fccd98efeb8511594d1eaba1486f744b Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 00:24:43 -0700 Subject: [PATCH 30/38] Unified tray menu icon definitions to always use the zc-menu-* identifiers (instead of conditional stock GTK icons), so Preferences/Quit resolve through the same menu icon set on all builds. Unified plugin manager action icons to use zc-menu-load-plugin, zc-menu-delete, and zc-menu-refresh across platforms. Unified channel list action icons to only use the zc-menu-* icon names (join/copy/find/refresh/save), matching data/icons/menu usage. Unified spell-entry menu action icons to only use zc-menu-add, zc-menu-remove, and zc-menu-spell-check. --- src/fe-gtk/chanlist.c | 9 --------- src/fe-gtk/plugin-tray.c | 6 ++---- src/fe-gtk/plugingui.c | 7 ------- src/fe-gtk/sexy-spell-entry.c | 7 ------- 4 files changed, 2 insertions(+), 27 deletions(-) diff --git a/src/fe-gtk/chanlist.c b/src/fe-gtk/chanlist.c index eec1cbae..098b7f7d 100644 --- a/src/fe-gtk/chanlist.c +++ b/src/fe-gtk/chanlist.c @@ -45,20 +45,11 @@ #include "custom-list.h" -#if HAVE_GTK3 #define ICON_CHANLIST_JOIN "zc-menu-join" #define ICON_CHANLIST_COPY "zc-menu-copy" #define ICON_CHANLIST_FIND "zc-menu-find" #define ICON_CHANLIST_REFRESH "zc-menu-refresh" #define ICON_CHANLIST_SAVE "zc-menu-save" -#endif -#if !HAVE_GTK3 -#define ICON_CHANLIST_JOIN GTK_STOCK_JUMP_TO -#define ICON_CHANLIST_COPY GTK_STOCK_COPY -#define ICON_CHANLIST_FIND GTK_STOCK_FIND -#define ICON_CHANLIST_REFRESH GTK_STOCK_REFRESH -#define ICON_CHANLIST_SAVE GTK_STOCK_SAVE_AS -#endif enum { diff --git a/src/fe-gtk/plugin-tray.c b/src/fe-gtk/plugin-tray.c index 3971e796..ff83f0e0 100644 --- a/src/fe-gtk/plugin-tray.c +++ b/src/fe-gtk/plugin-tray.c @@ -43,12 +43,10 @@ typedef struct _GtkStatusIcon GtkStatusIcon; #include #endif #endif +#endif + #define ICON_TRAY_PREFERENCES "zc-menu-preferences" #define ICON_TRAY_QUIT "zc-menu-quit" -#else -#define ICON_TRAY_PREFERENCES GTK_STOCK_PREFERENCES -#define ICON_TRAY_QUIT GTK_STOCK_QUIT -#endif #ifndef WIN32 #include diff --git a/src/fe-gtk/plugingui.c b/src/fe-gtk/plugingui.c index 91ad6814..d12f9df7 100644 --- a/src/fe-gtk/plugingui.c +++ b/src/fe-gtk/plugingui.c @@ -64,16 +64,9 @@ plugingui_get_target_session (void) return NULL; } -#if HAVE_GTK3 #define ICON_PLUGIN_LOAD "zc-menu-load-plugin" #define ICON_PLUGIN_UNLOAD "zc-menu-delete" #define ICON_PLUGIN_RELOAD "zc-menu-refresh" -#endif -#if !HAVE_GTK3 -#define ICON_PLUGIN_LOAD GTK_STOCK_REVERT_TO_SAVED -#define ICON_PLUGIN_UNLOAD GTK_STOCK_DELETE -#define ICON_PLUGIN_RELOAD GTK_STOCK_REFRESH -#endif #if HAVE_GTK3 static GtkWidget * diff --git a/src/fe-gtk/sexy-spell-entry.c b/src/fe-gtk/sexy-spell-entry.c index 1ba37786..36cb0f28 100644 --- a/src/fe-gtk/sexy-spell-entry.c +++ b/src/fe-gtk/sexy-spell-entry.c @@ -59,16 +59,9 @@ #endif #endif -#if HAVE_GTK3 #define ICON_ADD "zc-menu-add" #define ICON_REMOVE "zc-menu-remove" #define ICON_SPELL_CHECK "zc-menu-spell-check" -#endif -#if !HAVE_GTK3 -#define ICON_ADD GTK_STOCK_ADD -#define ICON_REMOVE GTK_STOCK_REMOVE -#define ICON_SPELL_CHECK GTK_STOCK_SPELL_CHECK -#endif /* * Bunch of poop to make enchant into a runtime dependency rather than a From f6b78bd167ed560920412dc773c478bec7cc6318 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 00:32:42 -0700 Subject: [PATCH 31/38] Standardized GTK menu-icon fallback mapping so stock names for Save As, Previous, and Next now resolve through the bundled zc-menu-* icon family (and map back correctly on GTK2), ensuring these menu actions use the same icon set path as the rest of your menu icons. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated search controls in the main UI to use zc-menu-previous / zc-menu-next and to load through gtkutil_image_new_from_stock(...), so those menu-sized icons are rendered from the same data/icons/menu resources instead of theme-dependent icon names. Updated URL Grabber and Raw Log โ€œSave Asโ€ icon constants to use zc-menu-save-as for consistency with the menu icon set. Added new menu SVGs (save-as, previous, next) in both light and dark variants, and registered all of them in the GResource manifest so theyโ€™re available cross-platform from the bundled resource system. --- data/icons/menu/dark/next.svg | 3 +++ data/icons/menu/dark/previous.svg | 3 +++ data/icons/menu/dark/save-as.svg | 6 ++++++ data/icons/menu/light/next.svg | 3 +++ data/icons/menu/light/previous.svg | 3 +++ data/icons/menu/light/save-as.svg | 6 ++++++ data/zoitechat.gresource.xml | 6 ++++++ src/fe-gtk/gtkutil.c | 6 ++++++ src/fe-gtk/maingui.c | 10 +++++----- src/fe-gtk/rawlog.c | 2 +- src/fe-gtk/urlgrab.c | 2 +- 11 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 data/icons/menu/dark/next.svg create mode 100644 data/icons/menu/dark/previous.svg create mode 100644 data/icons/menu/dark/save-as.svg create mode 100644 data/icons/menu/light/next.svg create mode 100644 data/icons/menu/light/previous.svg create mode 100644 data/icons/menu/light/save-as.svg diff --git a/data/icons/menu/dark/next.svg b/data/icons/menu/dark/next.svg new file mode 100644 index 00000000..9a61599d --- /dev/null +++ b/data/icons/menu/dark/next.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/dark/previous.svg b/data/icons/menu/dark/previous.svg new file mode 100644 index 00000000..1f6c39a0 --- /dev/null +++ b/data/icons/menu/dark/previous.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/dark/save-as.svg b/data/icons/menu/dark/save-as.svg new file mode 100644 index 00000000..642442d0 --- /dev/null +++ b/data/icons/menu/dark/save-as.svg @@ -0,0 +1,6 @@ + diff --git a/data/icons/menu/light/next.svg b/data/icons/menu/light/next.svg new file mode 100644 index 00000000..e2427e28 --- /dev/null +++ b/data/icons/menu/light/next.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/light/previous.svg b/data/icons/menu/light/previous.svg new file mode 100644 index 00000000..bf85619d --- /dev/null +++ b/data/icons/menu/light/previous.svg @@ -0,0 +1,3 @@ + diff --git a/data/icons/menu/light/save-as.svg b/data/icons/menu/light/save-as.svg new file mode 100644 index 00000000..a0e43f07 --- /dev/null +++ b/data/icons/menu/light/save-as.svg @@ -0,0 +1,6 @@ + diff --git a/data/zoitechat.gresource.xml b/data/zoitechat.gresource.xml index b42f4044..0be80d77 100644 --- a/data/zoitechat.gresource.xml +++ b/data/zoitechat.gresource.xml @@ -39,9 +39,12 @@ icons/menu/light/remove.svg icons/menu/light/spell-check.svg icons/menu/light/save.svg + icons/menu/light/save-as.svg icons/menu/light/refresh.svg icons/menu/light/search.svg icons/menu/light/find.svg + icons/menu/light/previous.svg + icons/menu/light/next.svg icons/menu/light/help.svg icons/menu/light/about.svg @@ -63,9 +66,12 @@ icons/menu/dark/remove.svg icons/menu/dark/spell-check.svg icons/menu/dark/save.svg + icons/menu/dark/save-as.svg icons/menu/dark/refresh.svg icons/menu/dark/search.svg icons/menu/dark/find.svg + icons/menu/dark/previous.svg + icons/menu/dark/next.svg icons/menu/dark/help.svg icons/menu/dark/about.svg diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index 1a005c66..4076afc8 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -88,9 +88,12 @@ gtkutil_menu_custom_icon_from_stock (const char *stock_name) { "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" }, }; @@ -136,9 +139,12 @@ gtkutil_stock_from_menu_custom_icon (const char *custom_icon) { "zc-menu-remove", GTK_STOCK_REMOVE }, { "zc-menu-spell-check", GTK_STOCK_SPELL_CHECK }, { "zc-menu-save", GTK_STOCK_SAVE }, + { "zc-menu-save-as", GTK_STOCK_SAVE_AS }, { "zc-menu-refresh", GTK_STOCK_REFRESH }, { "zc-menu-search", GTK_STOCK_JUSTIFY_LEFT }, { "zc-menu-find", GTK_STOCK_FIND }, + { "zc-menu-previous", GTK_STOCK_GO_BACK }, + { "zc-menu-next", GTK_STOCK_GO_FORWARD }, { "zc-menu-help", GTK_STOCK_HELP }, { "zc-menu-about", GTK_STOCK_ABOUT }, }; diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index e40a0e0b..20dad6b8 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -63,8 +63,8 @@ #if HAVE_GTK3 #define ICON_TAB_DETACH "zc-menu-detach" #define ICON_TAB_CLOSE "zc-menu-close" -#define ICON_TAB_PREVIOUS "go-previous" -#define ICON_TAB_NEXT "go-next" +#define ICON_TAB_PREVIOUS "zc-menu-previous" +#define ICON_TAB_NEXT "zc-menu-next" #define ICON_ENTRY_ERROR "dialog-error" #endif #if !HAVE_GTK3 @@ -3464,7 +3464,7 @@ mg_create_search(session *sess, GtkWidget *box) close = gtk_button_new (); #if HAVE_GTK3 - gtk_button_set_image (GTK_BUTTON (close), gtk_image_new_from_icon_name (ICON_TAB_CLOSE, GTK_ICON_SIZE_MENU)); + gtk_button_set_image (GTK_BUTTON (close), gtkutil_image_new_from_stock (ICON_TAB_CLOSE, GTK_ICON_SIZE_MENU)); #endif #if !HAVE_GTK3 gtk_button_set_image (GTK_BUTTON (close), gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU)); @@ -3489,7 +3489,7 @@ mg_create_search(session *sess, GtkWidget *box) previous = gtk_button_new (); #if HAVE_GTK3 - gtk_button_set_image (GTK_BUTTON (previous), gtk_image_new_from_icon_name (ICON_TAB_PREVIOUS, GTK_ICON_SIZE_MENU)); + gtk_button_set_image (GTK_BUTTON (previous), gtkutil_image_new_from_stock (ICON_TAB_PREVIOUS, GTK_ICON_SIZE_MENU)); #endif #if !HAVE_GTK3 gtk_button_set_image (GTK_BUTTON (previous), gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_MENU)); @@ -3501,7 +3501,7 @@ mg_create_search(session *sess, GtkWidget *box) next = gtk_button_new (); #if HAVE_GTK3 - gtk_button_set_image (GTK_BUTTON (next), gtk_image_new_from_icon_name (ICON_TAB_NEXT, GTK_ICON_SIZE_MENU)); + gtk_button_set_image (GTK_BUTTON (next), gtkutil_image_new_from_stock (ICON_TAB_NEXT, GTK_ICON_SIZE_MENU)); #endif #if !HAVE_GTK3 gtk_button_set_image (GTK_BUTTON (next), gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU)); diff --git a/src/fe-gtk/rawlog.c b/src/fe-gtk/rawlog.c index dc8c1c1f..7a3438cf 100644 --- a/src/fe-gtk/rawlog.c +++ b/src/fe-gtk/rawlog.c @@ -44,7 +44,7 @@ #if HAVE_GTK3 #define ICON_RAWLOG_CLEAR "zc-menu-clear" -#define ICON_RAWLOG_SAVE_AS "zc-menu-save" +#define ICON_RAWLOG_SAVE_AS "zc-menu-save-as" #endif #if !HAVE_GTK3 #define ICON_RAWLOG_CLEAR GTK_STOCK_CLEAR diff --git a/src/fe-gtk/urlgrab.c b/src/fe-gtk/urlgrab.c index f71f7f60..3b919ef5 100644 --- a/src/fe-gtk/urlgrab.c +++ b/src/fe-gtk/urlgrab.c @@ -36,7 +36,7 @@ #if HAVE_GTK3 #define ICON_URLGRAB_CLEAR "zc-menu-clear" #define ICON_URLGRAB_COPY "zc-menu-copy" -#define ICON_URLGRAB_SAVE_AS "zc-menu-save" +#define ICON_URLGRAB_SAVE_AS "zc-menu-save-as" #endif #if !HAVE_GTK3 #define ICON_URLGRAB_CLEAR GTK_STOCK_CLEAR From 45d4025ad795abc649f25641fef54f6b3a060109 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 00:38:18 -0700 Subject: [PATCH 32/38] =?UTF-8?q?Updated=20the=20built-in=20popup=20menu?= =?UTF-8?q?=20defaults=20to=20stop=20using=20mixed=20legacy=20GTK=20stock?= =?UTF-8?q?=20icon=20names=20and=20instead=20use=20the=20app=E2=80=99s=20u?= =?UTF-8?q?nified=20zc-menu-*=20icon=20IDs=20(backed=20by=20data/icons/men?= =?UTF-8?q?u=20resources).=20Specifically=20changed:=20Open=20Dialog=20Win?= =?UTF-8?q?dow,=20Send=20a=20File,=20User=20Info=20(WhoIs),=20Add=20to=20F?= =?UTF-8?q?riends=20List,=20and=20Ignore.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/zoitechat.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/common/zoitechat.c b/src/common/zoitechat.c index dbb6e749..10ce8bc1 100644 --- a/src/common/zoitechat.c +++ b/src/common/zoitechat.c @@ -1332,11 +1332,11 @@ xchat_init (void) "NAME ENDSUB\n" "CMD \n\n"\ "NAME ENDSUB\n" "CMD \n\n", - _("_Open Dialog Window"), "gtk-go-up", - _("_Send a File" ELLIPSIS), "gtk-floppy", - _("_User Info (WhoIs)"), "gtk-info", - _("_Add to Friends List" ELLIPSIS), "gtk-add", - _("_Ignore"), "gtk-stop", + _("_Open Dialog Window"), "zc-menu-new", + _("_Send a File" ELLIPSIS), "zc-menu-save", + _("_User Info (WhoIs)"), "zc-menu-about", + _("_Add to Friends List" ELLIPSIS), "zc-menu-add", + _("_Ignore"), "zc-menu-remove", _("O_perator Actions"), _("Give Ops"), From 5df6f68cd90d47aaab739d06dfd42c035d4976e3 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 00:41:55 -0700 Subject: [PATCH 33/38] Unified menu icon loading so zc-menu-* icons can be loaded directly from the bundled data/icons/menu/light/*.svg resource set via a new helper (gtkutil_menu_icon_pixbuf_new), instead of depending only on platform stock themes. This makes menu icon resolution consistent across platforms for the custom menu icon namespace. Updated the GTK2 (!HAVE_GTK3) code path in gtkutil_image_new_from_stock to first try the bundled zc-menu-* SVG resource icons and only fall back to GTK stock icons if a bundled icon cannot be loaded. --- src/fe-gtk/gtkutil.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index 4076afc8..5033d873 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -163,6 +163,22 @@ gtkutil_stock_from_menu_custom_icon (const char *custom_icon) } #endif +static GdkPixbuf * +gtkutil_menu_icon_pixbuf_new (const char *icon_name) +{ + GdkPixbuf *pixbuf = NULL; + char *resource_path; + + if (!icon_name || !g_str_has_prefix (icon_name, "zc-menu-")) + return NULL; + + resource_path = g_strdup_printf ("/icons/menu/light/%s.svg", icon_name + strlen ("zc-menu-")); + pixbuf = gdk_pixbuf_new_from_resource_at_scale (resource_path, -1, -1, TRUE, NULL); + g_free (resource_path); + + return pixbuf; +} + #if HAVE_GTK3 const char * gtkutil_icon_name_from_stock (const char *stock_name) @@ -317,6 +333,18 @@ gtkutil_image_new_from_stock (const char *stock, GtkIconSize size) return gtk_image_new_from_icon_name (icon_name, size); #elif !HAVE_GTK3 + if (stock && g_str_has_prefix (stock, "zc-menu-")) + { + GdkPixbuf *pixbuf = gtkutil_menu_icon_pixbuf_new (stock); + + if (pixbuf) + { + GtkWidget *image = gtk_image_new_from_pixbuf (pixbuf); + g_object_unref (pixbuf); + return image; + } + } + if (stock && g_str_has_prefix (stock, "zc-menu-")) stock = gtkutil_stock_from_menu_custom_icon (stock); return gtk_image_new_from_stock (stock, size); From 3ccd8c44b3c2da144e7d31e193db15e7044cf92f Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 00:47:10 -0700 Subject: [PATCH 34/38] Added a centralized menu icon resolver in menu.c so menu items consistently prefer the bundled zc-menu-* resource icons (from data/icons/menu) instead of relying on platform/theme fallback behavior. This includes: checking whether a matching zc-menu-* resource exists, preserving support for absolute file paths and /... relative icon paths, mapping plain icon names (for example, copy) to zc-menu-copy when available. Updated menu_quick_item() to use the new resolver (menu_icon_widget_new) for all icon-bearing quick/popup menu entries, making icon rendering behavior consistent across platforms. --- src/fe-gtk/menu.c | 69 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index d2e7cc08..81cda565 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -65,6 +65,60 @@ static GSList *submenu_list; +static gboolean +menu_icon_exists_in_resource (const char *icon_name) +{ + char *resource_path; + gboolean found; + + if (!icon_name || !g_str_has_prefix (icon_name, "zc-menu-")) + return FALSE; + + resource_path = g_strdup_printf ("/icons/menu/light/%s.svg", icon_name + strlen ("zc-menu-")); + found = g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL); + g_free (resource_path); + + return found; +} + +static GtkWidget * +menu_icon_widget_new (const char *icon) +{ + GtkWidget *img = NULL; + char *path; + + if (!icon) + return NULL; + + if (access (icon, R_OK) == 0) + return gtk_image_new_from_file (icon); + + path = g_build_filename (get_xdir (), icon, NULL); + if (access (path, R_OK) == 0) + { + img = gtk_image_new_from_file (path); + } + else if (g_str_has_prefix (icon, "zc-menu-") || g_str_has_prefix (icon, "gtk-")) + { + img = gtkutil_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); + } + else + { + char *menu_icon_name = g_strdup_printf ("zc-menu-%s", icon); + + if (menu_icon_exists_in_resource (menu_icon_name)) + img = gtkutil_image_new_from_stock (menu_icon_name, GTK_ICON_SIZE_MENU); + else + img = gtkutil_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); + + g_free (menu_icon_name); + } + + g_free (path); + + return img; +} + static GtkWidget * menu_new (void) { @@ -278,7 +332,6 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, gpointer userdata, char *icon) { GtkWidget *img, *item; - char *path; #if HAVE_GTK3 GtkWidget *box; GtkWidget *image = NULL; @@ -294,19 +347,7 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, /*if (flags & XCMENU_MARKUP) item = gtk_image_menu_item_new_with_markup (label); else*/ - img = NULL; - if (access (icon, R_OK) == 0) /* try fullpath */ - img = gtk_image_new_from_file (icon); - else - { - /* try relative to */ - path = g_build_filename (get_xdir (), icon, NULL); - if (access (path, R_OK) == 0) - img = gtk_image_new_from_file (path); - else - img = gtkutil_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); - g_free (path); - } + img = menu_icon_widget_new (icon); #if HAVE_GTK3 item = gtk_menu_item_new (); From e214c76bdf3919b93d31f0e45f1e2c0cfa6181e8 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 00:52:49 -0700 Subject: [PATCH 35/38] Unified GTK3 menu icon resolution so menu-sized icons now consistently map to the bundled zc-menu-* icon set (from data/icons/menu) even when callers pass freedesktop icon names (like edit-copy, go-next) instead of legacy stock IDs. This removes the mixed behavior where some items came from system themes while others came from bundled resources. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a new icon-nameโ†’zc-menu-* mapping helper and wired it into gtkutil_image_new_from_stock() as a fallback path for GTK_ICON_SIZE_MENU, after the existing stock-name mapping. --- src/fe-gtk/gtkutil.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index 5033d873..8c772908 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -110,6 +110,54 @@ gtkutil_menu_custom_icon_from_stock (const char *stock_name) return NULL; } + +static const char * +gtkutil_menu_custom_icon_from_icon_name (const char *icon_name) +{ + static const struct + { + const char *icon; + const char *custom_icon; + } icon_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" }, + { "network-workgroup", "zc-menu-chanlist" }, + }; + size_t i; + + if (!icon_name) + return NULL; + + for (i = 0; i < G_N_ELEMENTS (icon_map); i++) + { + if (strcmp (icon_name, icon_map[i].icon) == 0) + return icon_map[i].custom_icon; + } + + return NULL; +} #endif #if !HAVE_GTK3 @@ -323,6 +371,9 @@ gtkutil_image_new_from_stock (const char *stock, GtkIconSize size) { const char *menu_icon_name = gtkutil_menu_custom_icon_from_stock (stock); + if (!menu_icon_name) + menu_icon_name = gtkutil_menu_custom_icon_from_icon_name (icon_name); + if (menu_icon_name) icon_name = menu_icon_name; } From dbc517de99ed52a83a5af15324ce256467a93e16 Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 00:57:58 -0700 Subject: [PATCH 36/38] Updated channel list icon button creation to always use gtkutil_image_new_from_stock(..., GTK_ICON_SIZE_MENU) so it follows the same zc-menu-* icon resolution path on all GTK targets instead of mixing direct stock-image calls. Updated the GTK2 channel list context-menu icon path to use the same helper, removing direct gtk_image_new_from_stock usage for menu icons. Updated the GTK2 spell-entry popup icon path to use gtkutil_image_new_from_stock, aligning it with the same menu icon set/mapping pipeline used elsewhere (data/icons/menu). --- src/fe-gtk/chanlist.c | 6 +----- src/fe-gtk/sexy-spell-entry.c | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/fe-gtk/chanlist.c b/src/fe-gtk/chanlist.c index 098b7f7d..6453fbdf 100644 --- a/src/fe-gtk/chanlist.c +++ b/src/fe-gtk/chanlist.c @@ -122,11 +122,7 @@ chanlist_icon_button (const char *label, const char *icon_name, GtkWidget *image; button = gtk_button_new_with_mnemonic (label); -#if HAVE_GTK3 image = gtkutil_image_new_from_stock (icon_name, GTK_ICON_SIZE_MENU); -#elif !HAVE_GTK3 - image = gtk_image_new_from_stock (icon_name, GTK_ICON_SIZE_MENU); -#endif gtk_button_set_image (GTK_BUTTON (button), image); gtk_button_set_use_underline (GTK_BUTTON (button), TRUE); g_signal_connect (G_OBJECT (button), "clicked", callback, userdata); @@ -157,7 +153,7 @@ chanlist_icon_menu_item (const char *label, const char *icon_name, GtkWidget *image; item = gtk_image_menu_item_new_with_mnemonic (label); - image = gtk_image_new_from_stock (icon_name, GTK_ICON_SIZE_MENU); + image = gtkutil_image_new_from_stock (icon_name, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); #endif g_signal_connect (G_OBJECT (item), "activate", callback, userdata); diff --git a/src/fe-gtk/sexy-spell-entry.c b/src/fe-gtk/sexy-spell-entry.c index 36cb0f28..c94e1d13 100644 --- a/src/fe-gtk/sexy-spell-entry.c +++ b/src/fe-gtk/sexy-spell-entry.c @@ -740,7 +740,7 @@ sexy_spell_entry_icon_menu_item (const char *label, const char *stock_name) GtkWidget *image; item = gtk_image_menu_item_new_with_label (label); - image = gtk_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); + image = gtkutil_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); #endif From 6ce7de23a38bb8f17f0fc7bc4423244cef2e774a Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 01:16:03 -0700 Subject: [PATCH 37/38] Switched menu resource loading to use bundled PNG assets (instead of SVG paths) for zc-menu-* icons, so menu icon resolution is consistent and no longer depends on SVG/icon-theme availability on different platforms (including Win32 builds). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated the GResource manifest so all menu icons now come from data/icons/menu/{light,dark} PNG files and are embedded with to-pixdata preprocessing, ensuring the app uses one unified internal icon set across platforms. Generated and added PNG assets for both light and dark menu icon variants under data/icons/menu/ to back the new resource paths used by the GTK menu code. Fixed menu icon resource detection to fall back from PNG to SVG when probing zc-menu-* entries, so menu item icon lookup no longer fails just because one format is unavailable at runtime. Updated GTK menu icon loading to use gdk_pixbuf_new_from_resource (instead of ..._at_scale) and added explicit fallback order across variant/light and PNG/SVG resources, which addresses the โ€œred no-entry squareโ€ missing-icon behavior you reported. Kept compatibility with your previous menu resource setup while making loading more resilient on Win32 and other environments where resource/pixbuf behavior differs. --- data/icons/menu/dark/about.png | Bin 0 -> 498 bytes data/icons/menu/dark/add.png | Bin 0 -> 462 bytes data/icons/menu/dark/chanlist.png | Bin 0 -> 409 bytes data/icons/menu/dark/clear.png | Bin 0 -> 362 bytes data/icons/menu/dark/close.png | Bin 0 -> 445 bytes data/icons/menu/dark/connect.png | Bin 0 -> 399 bytes data/icons/menu/dark/copy.png | Bin 0 -> 330 bytes data/icons/menu/dark/delete.png | Bin 0 -> 305 bytes data/icons/menu/dark/detach.png | Bin 0 -> 343 bytes data/icons/menu/dark/disconnect.png | Bin 0 -> 415 bytes data/icons/menu/dark/find.png | Bin 0 -> 360 bytes data/icons/menu/dark/help.png | Bin 0 -> 579 bytes data/icons/menu/dark/join.png | Bin 0 -> 360 bytes data/icons/menu/dark/load-plugin.png | Bin 0 -> 377 bytes data/icons/menu/dark/network-list.png | Bin 0 -> 409 bytes data/icons/menu/dark/new.png | Bin 0 -> 401 bytes data/icons/menu/dark/next.png | Bin 0 -> 245 bytes data/icons/menu/dark/preferences.png | Bin 0 -> 405 bytes data/icons/menu/dark/previous.png | Bin 0 -> 286 bytes data/icons/menu/dark/quit.png | Bin 0 -> 432 bytes data/icons/menu/dark/refresh.png | Bin 0 -> 457 bytes data/icons/menu/dark/remove.png | Bin 0 -> 424 bytes data/icons/menu/dark/save-as.png | Bin 0 -> 470 bytes data/icons/menu/dark/save.png | Bin 0 -> 398 bytes data/icons/menu/dark/search.png | Bin 0 -> 337 bytes data/icons/menu/dark/spell-check.png | Bin 0 -> 327 bytes data/icons/menu/light/about.png | Bin 0 -> 514 bytes data/icons/menu/light/add.png | Bin 0 -> 486 bytes data/icons/menu/light/chanlist.png | Bin 0 -> 407 bytes data/icons/menu/light/clear.png | Bin 0 -> 364 bytes data/icons/menu/light/close.png | Bin 0 -> 458 bytes data/icons/menu/light/connect.png | Bin 0 -> 425 bytes data/icons/menu/light/copy.png | Bin 0 -> 344 bytes data/icons/menu/light/delete.png | Bin 0 -> 306 bytes data/icons/menu/light/detach.png | Bin 0 -> 356 bytes data/icons/menu/light/disconnect.png | Bin 0 -> 448 bytes data/icons/menu/light/find.png | Bin 0 -> 401 bytes data/icons/menu/light/help.png | Bin 0 -> 587 bytes data/icons/menu/light/join.png | Bin 0 -> 369 bytes data/icons/menu/light/load-plugin.png | Bin 0 -> 388 bytes data/icons/menu/light/network-list.png | Bin 0 -> 407 bytes data/icons/menu/light/new.png | Bin 0 -> 415 bytes data/icons/menu/light/next.png | Bin 0 -> 349 bytes data/icons/menu/light/preferences.png | Bin 0 -> 426 bytes data/icons/menu/light/previous.png | Bin 0 -> 357 bytes data/icons/menu/light/quit.png | Bin 0 -> 452 bytes data/icons/menu/light/refresh.png | Bin 0 -> 458 bytes data/icons/menu/light/remove.png | Bin 0 -> 465 bytes data/icons/menu/light/save-as.png | Bin 0 -> 480 bytes data/icons/menu/light/save.png | Bin 0 -> 408 bytes data/icons/menu/light/search.png | Bin 0 -> 365 bytes data/icons/menu/light/spell-check.png | Bin 0 -> 355 bytes data/zoitechat.gresource.xml | 104 ++++++++++++------------- src/fe-gtk/gtkutil.c | 27 +++++-- src/fe-gtk/menu.c | 8 +- 55 files changed, 81 insertions(+), 58 deletions(-) create mode 100644 data/icons/menu/dark/about.png create mode 100644 data/icons/menu/dark/add.png create mode 100644 data/icons/menu/dark/chanlist.png create mode 100644 data/icons/menu/dark/clear.png create mode 100644 data/icons/menu/dark/close.png create mode 100644 data/icons/menu/dark/connect.png create mode 100644 data/icons/menu/dark/copy.png create mode 100644 data/icons/menu/dark/delete.png create mode 100644 data/icons/menu/dark/detach.png create mode 100644 data/icons/menu/dark/disconnect.png create mode 100644 data/icons/menu/dark/find.png create mode 100644 data/icons/menu/dark/help.png create mode 100644 data/icons/menu/dark/join.png create mode 100644 data/icons/menu/dark/load-plugin.png create mode 100644 data/icons/menu/dark/network-list.png create mode 100644 data/icons/menu/dark/new.png create mode 100644 data/icons/menu/dark/next.png create mode 100644 data/icons/menu/dark/preferences.png create mode 100644 data/icons/menu/dark/previous.png create mode 100644 data/icons/menu/dark/quit.png create mode 100644 data/icons/menu/dark/refresh.png create mode 100644 data/icons/menu/dark/remove.png create mode 100644 data/icons/menu/dark/save-as.png create mode 100644 data/icons/menu/dark/save.png create mode 100644 data/icons/menu/dark/search.png create mode 100644 data/icons/menu/dark/spell-check.png create mode 100644 data/icons/menu/light/about.png create mode 100644 data/icons/menu/light/add.png create mode 100644 data/icons/menu/light/chanlist.png create mode 100644 data/icons/menu/light/clear.png create mode 100644 data/icons/menu/light/close.png create mode 100644 data/icons/menu/light/connect.png create mode 100644 data/icons/menu/light/copy.png create mode 100644 data/icons/menu/light/delete.png create mode 100644 data/icons/menu/light/detach.png create mode 100644 data/icons/menu/light/disconnect.png create mode 100644 data/icons/menu/light/find.png create mode 100644 data/icons/menu/light/help.png create mode 100644 data/icons/menu/light/join.png create mode 100644 data/icons/menu/light/load-plugin.png create mode 100644 data/icons/menu/light/network-list.png create mode 100644 data/icons/menu/light/new.png create mode 100644 data/icons/menu/light/next.png create mode 100644 data/icons/menu/light/preferences.png create mode 100644 data/icons/menu/light/previous.png create mode 100644 data/icons/menu/light/quit.png create mode 100644 data/icons/menu/light/refresh.png create mode 100644 data/icons/menu/light/remove.png create mode 100644 data/icons/menu/light/save-as.png create mode 100644 data/icons/menu/light/save.png create mode 100644 data/icons/menu/light/search.png create mode 100644 data/icons/menu/light/spell-check.png diff --git a/data/icons/menu/dark/about.png b/data/icons/menu/dark/about.png new file mode 100644 index 0000000000000000000000000000000000000000..08b64db1e2a455b6371a4fab845ff09995f3956a GIT binary patch literal 498 zcmVU8H&IO)noc2RR((NdE zr{{v>bV>IAi=f?(R+y181)BgChwv$Z#$BKLg@WTvCGdjaD=fbQ3`I~ez>(sX{6xqO zfSee!o?puS!lcNa-;F#!tT&s@*_hDp{`5|wA9_~o#E%-DABKOz@O|QEMyX_^tdXxS z&$mmZ(oKvJH5gmdvtl>b7u#CSOdsVj0uf1R&6;-N9Gf+5TGL5Bi^bwKz=}XNMI`n$ zx^+6eWo;Nm4#$*$Z0H(mT6~AO<0x8s$RH~+NSRY*{k!q6WZ+|TD>zP|wOL^GDQ_Xy z0O`4|+Z_>*yi=V?>?R6KvR12=g~W2!N!k&CnhuHTJU72sO-KkH=t`Vtv#+Zl-egkP zn>a|Fp!bE=egkl(-An2y{l`_jU)l z(19e=2grpda;)NH7C*_>Y@T#vb{d?D%!)%(9Vfer&4Y;eZ3;-@)@@3;w5^fxt+r9cG z0gvuabd;y7wfTt6t75Yk$8ovAKUb>*IyU>7&5MeYnQxZxr4*ZK5^RGo=<;)(1qcA# zTVOd1a;LvukV+Tvna#Kb4W~oCy)EYRS43ogj`zRn4S`ayt1k3VnE(I)07*qoM6N<$ Ef`W9=C;$Ke literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/chanlist.png b/data/icons/menu/dark/chanlist.png new file mode 100644 index 0000000000000000000000000000000000000000..9aac1a2015210f0a2f9e1dccb3d3ac0c00f24451 GIT binary patch literal 409 zcmV;K0cQS*P)YRoW03!5aEJO z^o4~kFEY@KDT}?Lv^o!kU&7=Gk(yZ}m-AO}(VMke=;py-xc{Sp)DMU?gs&q% z3wRfxk<&QtOKi1TktTh@gol-_5w*c`>NG3&{s}$+1&f7c%xZU300000NkvXXu0mjf Dhk3Vh literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/clear.png b/data/icons/menu/dark/clear.png new file mode 100644 index 0000000000000000000000000000000000000000..d3a1c607504e2546e9a93547c0da9c46b3fcc5cb GIT binary patch literal 362 zcmV-w0hRuVP)WIfU?yOq7=IjsE=}r&~ ze=RT=Onf!TGXSrA%51u_)$MMKYXzcc6pCk$08!^tuo=r)Gcq<}lndwCswj$@5 zxqxcAM`#aZyL=jFoU?StFH63trgyGp%h@jub;ziu|0N%3(?yf+%7UEiP74E%R|0xmaXzc*C>umAu607*qo IM6N<$g6fx=)Bpeg literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/close.png b/data/icons/menu/dark/close.png new file mode 100644 index 0000000000000000000000000000000000000000..6e9bb61ae0e031d0644b2b7676948fb753c5344b GIT binary patch literal 445 zcmV;u0Yd(XP)PQ=gd8mA^ImcU1+UK%v{M5L{aqW zI8J}T!1Kep!E_Fy{E9>S3_i5&^6kt(Yh8+=-T<8D74EXsG1LKo6ULxy+xCYc!bxxG1i+`uwAMFr zyswzANhO^i2sY-oCLMWqgCXq_Q>0Yvjp9w)zTeve<4PXMvU^D(0_eDAo0oG20@rnm ng+ig4r3MgKmi4~kkiX*_57Dg?Ml6J@00000NkvXXu0mjfC_u_p literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/connect.png b/data/icons/menu/dark/connect.png new file mode 100644 index 0000000000000000000000000000000000000000..d80b55aa62777465e18f4103d962ce481097ae8a GIT binary patch literal 399 zcmV;A0dW3_P)LU9yR_e8E6j>tQ^G6CJMW zKFs-23kHwJ8$1m(8nx?WEu|Tc#;oV9U5WfK6!AVB$9_ilhY;_rYE>ocDf#fcmsR16 t0|4=S8JO5GS8F!QgM}2Nk);6tz!&jNq$4)b=1u?r002ovPDHLkV1fj7u4@1Q literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/copy.png b/data/icons/menu/dark/copy.png new file mode 100644 index 0000000000000000000000000000000000000000..f0dab355c8108e19b431afa17dfa8ac790a1ed4b GIT binary patch literal 330 zcmV-Q0k!^#P)cxiearLe85Vx!`(t@fL&>`Zc>V4BrgQ02@N};C{Y1+~(rFtx#2$&bf3w zZ^LIgeK|6a+ro2uE5#VVc~rnG`KnIj*jg-$0-b73b4iSyB*_lS@M*6*84`Uo1Qq5% zJVs=2hBe6Gw0zy{c>v%pBKYP?1s7FVPRaX9{<@yCh@p7v_j{`@fh5VwDH<>~g#Vv_ zt)4*9`>nu+kKgiQJin^ah!~>4P1t*53-Iw%#uu~4Yz+E&2LTlf!iHJ}X_~q`r`?#K ceu;n2CzD20^MauvumAu607*qoM6N<$g0M=F>;M1& literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/delete.png b/data/icons/menu/dark/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..511142cc98ccda95bbf4abc01d1e3614dedf7c5a GIT binary patch literal 305 zcmV-10nYx3P)Csl7wIL0T_hVJSI)7qF0= z!Q8>xRstbKBn(L(h?)NhyAe|C211J9tLA_6<{SP8{Cly^{EqPs&Ub)TIdYipFGKj) z3y3k^tP^{d*)3gHzP&dXgfRJglkWmHZhfPk;5rAP?e~>jG-9=JYXKNE zt}vS~9tk{<7)a=rA>vcQvw+u5`{HFcpEs4`LYqRTJOi<|tZKdEWG4sY4SoS|3G%BN zwFFcg0=OnL1XK=91=a%6x_Ha7pHW>nrDCy%bt3%&pif6k`pCWF00000NkvXXu0mjf DgoJ)~ literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/detach.png b/data/icons/menu/dark/detach.png new file mode 100644 index 0000000000000000000000000000000000000000..edbf3997882c816b917b7775de2caeba903dd2be GIT binary patch literal 343 zcmV-d0jU0oP)PSqpppv+ zVqu||5G-Pw8@T^(+@HeALfnzvAX&q18mmn4nt3yChW~-32lFu+X=QEQ_W^7XH01?B z8L5|Wqdg$`J#S$0QHY7NdGYiDjl@ego}AXkh?Dd#w&{H>Z~bHJ(kyoVq%r}rqKfL9 z>XX6{(6vq8du66sF9NLf2Oy3F>`vV^k$Cmy{6{woZf6Pp0kepVqTneCgF{Hqlo9|f zQ2pQQvkE4EEi~$_xGHJ~U~jY29+a78L1%asabcZ*sFDlX7tDD#Z2b`zTI35-!;RBp piF;KaNx(4a1UK8{*P_ZxiXWR5XJ2rC@v8s;002ovPDHLkV1lJ;lq~=N literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/disconnect.png b/data/icons/menu/dark/disconnect.png new file mode 100644 index 0000000000000000000000000000000000000000..f77be0caa0038ef58ec7ebba2d3db894cc88070c GIT binary patch literal 415 zcmV;Q0bu@#P)yDM|i^ZHr zMA5GVlxkOm*a2hL%_KPWba>n^P_0t; z^`)}|;NF;#laUMabok`?!EVAm-8%GiD4q@n3wut(J*C5rh@`$9_`Y8Tu)rj@3Ac)c zIzUGNoM91Wxe*|%^+WH4red0tFQkV9cVSqXWuE(B@f9Pr$SjWXTlpv@^@?e#iT}WL z9~X^uHvrH(-v|iIZyD3Jv+c10qYi!$v9V1e?NVv^d^m@Hj(4%PsIN$05`O>y002ov JPDHLkV1ia9wDbS~ literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/find.png b/data/icons/menu/dark/find.png new file mode 100644 index 0000000000000000000000000000000000000000..43ab987623f526d04dcf30f92fc5b708f8915cb8 GIT binary patch literal 360 zcmV-u0hj)XP)$@i@_~sOFk5k@D1r;uc3D>z+(||3 z)(=iYnn z1O731*nx=H&0a5S_9fTdA{qP@L9^LA#e`HTm<5oDet#vf5(cc5N^bj5g0}Bpf#w>( zt_T)wg?1oxEDLEJ$~^#%C^b{eIqzbO8dr|MuLe8Y7XX$*!73ro!cgByCU~9TYihmr zx!W!LM!8PYF-ZvPX#nd<3{IwwErB?mu<+=>L2CK^%hY-mz&F!v1xah8qc|8T6DNdf zrkHo$A4p)r42khsfSUkLMwRzX+COd9&U#*F{QjRFleG~&rZcYV$2I@=_yrN;(qCyp RD#ZW*002ovPDHLkV1f_w2L1p5 literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/join.png b/data/icons/menu/dark/join.png new file mode 100644 index 0000000000000000000000000000000000000000..609076718aa5038ca215945116be57c125a541fd GIT binary patch literal 360 zcmV-u0hj)XP)0{fshAa}X2{7_!D z)M~Y7V71o><8%vH1ol8?`xThHVfO{}Fbhuw_Fy2vH#zet#%*Mm$#49`C`vX}*b(GP z(Q#mY#G_)ZZRZnwQK$2AX1qcPm=pBgiCM6=+#V+T_j(7^msk#6)V8ny0000Z;U7U$!H#f6wf$L7EQ*>G2GZ5M`zzeNY3S>zHkBU4K%7*>H zEem)F!*UzIt9OI>MlBNHR49=^7DuLH*F|K1oEx|&j^j`T;W>fQSpN;c8XyBGTIb_6 z_zw!ScSBL{UV~PvH2|=eZ}bv#3}6euGeA?X*FFH;ce`dK&r`l>z2wtf{e(jI$A4`W z_=*(u1z@MytX^qtDncCTB)xGxfm8tWi$x?OE+!y5@XP_h)vRI%mg;h0uKF-ZJ0YRoW03!5aEJO z^o4~kFEY@KDT}?Lv^o!kU&7=Gk(yZ}m-AO}(VMke=;py-xc{Sp)DMU?gs&q% z3wRfxk<&QtOKi1TktTh@gol-_5w*c`>NG3&{s}$+1&f7c%xZU300000NkvXXu0mjf Dhk3Vh literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/new.png b/data/icons/menu/dark/new.png new file mode 100644 index 0000000000000000000000000000000000000000..24e226c906f3cf289a11456a90d3572f0cebd30a GIT binary patch literal 401 zcmV;C0dD?@P){Zq!LyMk5F#K&d!D!SR}Suf&M4;xVw31EQeQxc91D2v3m=AB5}y#Y v`Ikmesl3i)vtM(=-nZMCmqKCoEhN4HT&95c;3e5StFu3c;`?(Gar)lhHa<*umtzpsRF{d$Z`NZ#KZ^g1$wFR&C|M(}I zc`GN#o)f?Xm-B59RZTC1}XGiZ{L*@dt<#F@O%k_QNbgg;AQhtVU&WVfqe*gPA q|Gkt>zVdKyWXW8aC0c?1Z1b!|I@k0THB1M(n!(f6&t;ucLK6UKbYn6A literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/preferences.png b/data/icons/menu/dark/preferences.png new file mode 100644 index 0000000000000000000000000000000000000000..c33104d32d10676c99a59ed306676aa2f875cb22 GIT binary patch literal 405 zcmV;G0c!qo*-+KEN(>Rh$noXT; zN6}iGd!T3$=dCDOHO{XBbGhz{cxi-TuR1zxSPZKP`@1tc!-=xPUR8-5fgUMj zZ@8(xrsM&Y7tZBQrwSNaoo+?I8-iEHQRo)cSDXv(Fb2j8Gt2&KC97hCV8$)xw(YFl z>0eTHK*3|oaSQq52@jI+KdSS#R-}Mwn_<{3DS4~VYZ8QVlPYEBviIX$NjK39lQO{% zC00000NkvXXu0mjfS2D1s literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/previous.png b/data/icons/menu/dark/previous.png new file mode 100644 index 0000000000000000000000000000000000000000..fbbe0dbfa59aea0459ff0cbbbcfa9ce10c943d0b GIT binary patch literal 286 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_aJzX3_ zEPAg_vh`zjBe{oRI#EDbF#-mL5mQk8Fdp0fpB zySS`lk>D*x#g-qZ(tn<`=l>zTXBO{_!*|Y{+7k9;mNUomt8VY3cCe?-UG{a;`bd{! zx99F=FW_x2HI=ljt;`YJsc@}4$@EiUYTC`r{+f;$L2bcoZ<*;Y7W%Nhf4p?2Ewe>2 zUw4(!p0~ytADp{FR=j=~{kqJYVUgslJ6!vVk6bnvdVTt!%a)%y9w#occB5Y@5_YSAVlTC|B45xHqq z|44$`2lfXfauxLx6zt8LahfKgkYt=2V@f)s?xF(+-aYrc^X}yVe+i}3Y`{^T_^4(J z@ypI}XP8HX1;emcYnHXtX(j^(=RlLPzA`dETFy2T$}wM@g^g`ZQ2ANeTLS|e$C-lf zUxB#fzNXH@0iPdl7Xa=BaBZ6AcqE|FAYBrtM0@?z>FAMWy0S zC&s)YfHg3R43vKM#wLJW2JVsxv8QR;`@n$Co^h#OP6gqFf#pB~_=%Vbx}GW!kvD9` a|G_tt4VcF-n+)Xu0000M=eK`(HrlV(>rcn$ zqi>!ccCFw3GT>(hmu3*H8DLonR${LMJ`BTr@78>I1VI!%r)U0v5zRD)NG4$~9vdOP!NMAQYw-m>Kq7?r z2C)((gf$BiM5L;3kLvjYQ&-w6otf!aI!P_+-dp#ad+GxJ4R#BvYFWh1D1%7_G*EvR zhLtOltv?&sM!Kk8cLl5`HhkZ*CTsDZY)NuVa;W`APkUo#YS z5H^Z>tr52ofK&O$9(q#^d$z4O0ayoc(e8nQ-G3zyei^SF3QEMiR}2`_tY%DIJ+RG4 z;rj`_FEa7jO1f9X9?RQ7Ebg(Zi6q|<1Z#w@7;%S5lGJ{3uZ_l-P27=!%h@jE7mDpH zM%+9VJ0Qk0(rji0LI4jQSdYTWS(_)F$RvumX%9|(7M1+%KwsZANnbSH|KS5v2%_nu SFC^js0000p`$XNK+;8|2p9wYPEV%DA1034G?Qn8h#Iqdl`mdG9=7I!aj)iMU^5~{Wo>yLy{z6v4G(1 zor7p(0TzA0Y1tn+s~^5QfKux0n_)>%XjFJ=Gi=_hEz3|&d+Y7E_Zd*>p8|Aj$_y%U z^g(R>vG%g4S1?IL(fkeoAOD45l8EDvAYUx3fM@}lhgc^G z!EMBGw|?t#1<#m+Xe};O)**h)w>TE?P2{c<%9tu3th775w*sE!Tf`8yDLgmCuX_dP z*v#$wUl*}|0Rb1r;5>>dUvj;_7|lRLMk=&)p8)t6A#>S`HTEh=lBG0Lg~ah40VBN= zxR;8DcdkT()Q#rz8#1p(N8@=%N2jyp^3~(QxeU?sh9smFU literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/save.png b/data/icons/menu/dark/save.png new file mode 100644 index 0000000000000000000000000000000000000000..841b26c676cff836d8197413530b9e558276a803 GIT binary patch literal 398 zcmV;90df9`P)Aa}k~T%JSYg)rk_I=yyn zs|6B^OTrcv@IvAMq1Qjy}I z_XaIsTO(N)qfz<-Kv~(eF;q6+YT9)grnYG>oUGQOFB2i~+t?{p2 j@c0t71g-p4f8yLuZ-+V&`Sa?WZ)OEW7aOa2RG0Rq7<^|}! zpz_X4a9#cSZfWb_ri>V!?+~w!^cF%4{4gZUn_X8)}c^L zLt_O>)TCF>0AfI0yCW)W<%uZm1H;=G^D)wXR|E%HvV4Xi=(=txaFBWN Z@daDoWDE9+hcW;F002ovPDHLkV1h5okTL)O literal 0 HcmV?d00001 diff --git a/data/icons/menu/light/about.png b/data/icons/menu/light/about.png new file mode 100644 index 0000000000000000000000000000000000000000..e1b584328988e6c517bbb2dadb79a3054d9f2e17 GIT binary patch literal 514 zcmV+d0{#7oP)XG`SOM<%3;GAT zl0Q&4uxEq7MmDU7-SMF;wLl1&rZq$ivP5m?U2~_MX8b6a$W7kl&3*Trd+)jL0sm?2 zc~UI)-9KsGvTc3PKSia|`X_>W4+=vfu0&!Mz|D^PtAZ;o;(X(9>r+pHV6^ZQbn76# z5L%8R|GoJ=i5@BRIe;8gr)vAVTM0(enGH_Uo$s%bhPo^d`d1WW!d(z?;UWOfJZe-|iBSqMg&;W9<^OV<>Hm*r$GQ z_p|jzx{0d@MEDrMS@_}IX-b3D$mXod7b7E+{k_1$!^MmOHqO@oT#5j&OJcpX{PU$Q ziMq9TCE(1(5)}g!_p&P!QWlI(6hOQIcy4NU1OtgDmYL8S1gFC4&h}pkVv_ih*qr$c zK(^yPYnR=cuT}R>((#w5KH~-X@P)ugK~y-6%~DNE8&MQJ_sxKRA+1TCsV&aL>?FJ~?INXG@CRhoeQ|Bq zMOwP`2MB^Iq3Bw1C0a<62whdfq@bN?jUPXtP)g?A@}`LyO+uG?;BvW_^X@zMya(Jh zXlS=wwsTj%N*ba-AdW~M{cOt5z*h9%0a@3ZBjQys9)WSzWu*Z=fxzqV_;4@D7s(>$ zsFwuZfyRL)Ix_Sd850851c9p1w42QrUkqQST(+gF0_l2dy_R&mB@@@`@@ie?)d^6s z1{6$O{(fdSQAEoLeKT=%5&gkiFmgFJc-rgPeX@3-seSgX)|QTXLqv)hDjx27o6Ot@ z{l_0-iFCRv;NBD$wD#HiI8HU z{Q(bx)L7Ld+s6C;P<)A_=RqVs0DSuIPh89CBkQVp0=5Bsgy!Y2b@<)%GlkNm=ycwJ zr~<(Y$-h8}^D*R
o?1Uvz7-sL<1&?2VAz_0Ho`6EoLSlQ_xvx0frRIIJ9pU0rf*?phQ<&s-cVtfz<9URDpi>O_32eTh|O#n&?Z1rt2L>FEu ztS)wME_13?s=x3?!&A~9HKL<>PMO*+5I`~pj{*1{j;KM=9; z9|$&n6*huGKm+1wAsWy^LT>Mk?A-}L?=X-e0}Hcn-p^+OE^rilW(QPVEQinc zSCQY_AA``cPROo6t7*YVr$3&Mm7KkWmNx*R!Y9lxuO4KKC*sU`%B-#f()9fC?sB`o z-4x#SV1llvMNoEdb)o%#ETbLv&Aj}ra=p`Up$_8?9?nXcLjkG>PwQall-yUus!Fe?gqQfW~uZ!p~>Iz4N)qV({pTr)&Kwi07*qoM6N<$f*AY8 AhX4Qo literal 0 HcmV?d00001 diff --git a/data/icons/menu/light/connect.png b/data/icons/menu/light/connect.png new file mode 100644 index 0000000000000000000000000000000000000000..4f73f890218dac5517aa1ff3ac040948615e605a GIT binary patch literal 425 zcmV;a0apHrP)LO~QgGjENor&ZH?^>*GdD&up7H{rZ3pgf@11+@oI4lzBiOGuwk@Jf zcR{;PbAbjjneIppV%BOzN|6Rb3c$p7`W?W9FjTsHm#cZ}xi^TetZz#tii}|mpd(2< zp$%Zi0FqtFixDfi<*Oj3Usj?B;BscXdzjDXJKjRevH~9zItS5?lsr*?%r*uTNGZ|` zsQHmK9LI4@cj^E@(=gP@;0U%Yz_3T4GcP$F-wkT($EDKMClO8o>;oy|r@_)|I}9Mi z70Y?a9kW&Gn60w62{+U&fXSFu>1{~pqk4Z+^<61J5d#H-&(u#zaZ1xZL=@xeo39z5ab9V*ctPv1vzOW?Jxnof`bCj0f6X7MuwN7uaQ}pYr z_Bl<{>>I$#2wyBsLg3VUS}qDpo)qQuJ?a8@D9@u&ypGgeR2>Dk9WknUrWv4bPxm+F zEnc18ApCa-mX!QIKrS*=aO1ZCS>b>v#}C3|WKTak zPhv;mKY(4AZhv1=ng1;t;33>ZU!Se4@FZ-!=aLH36zHWpyPQ)*0000007*qoM6N<$ Ef*4|fX8-^I literal 0 HcmV?d00001 diff --git a/data/icons/menu/light/detach.png b/data/icons/menu/light/detach.png new file mode 100644 index 0000000000000000000000000000000000000000..3f4a2e38b59f8e666c2aee3a3266c4ea69292780 GIT binary patch literal 356 zcmV-q0h|7bP)K}SiFOugDlQ^6$x zrC4C07Ql6u1})(HW4wVla%OzV{;M4#)gsEoR|P2 z1gZW-$8X+4{)ZAk!^nr?lYGj^z-S*Ka!7m^`iT$*F*-LNM zmAJCN0N|{W&9CXB6|7Z|C2uFS(*%~GXk_Vat0aCiq+D=QDN%&WK0vl?(IIyzbPd8D_<#&@Q7ufInYd+gHH)BSe;Ana`kgbJ0sbiZHWH1h zzDnI~UT=qc%Sa>|zXJI6NsV(g4nhn-f7AU8;6znK{Q4qOwB|Fb;R{aBbD?I5Fa^j} zE?LMt0IdOtG&sv@dStHa1b(x#P_rNyM09#*r1q_ex~})WNZT=_T;QCAN>|Bp+XS4e zaRQ2Fu@rJo3q-c80K+iqJ$1(lfQq7s?e-@`qbdlC67taOEFm|Du%iXStwdA#{MoCN zH~_E&#FQ4mdtdVaurWay(=J@5cRwH$?}RW#qygCd`px@>ev}prua5^KvJ+yJ(&-qR zm>nH-j=1bjw*wM6Fw}@>)9&&(2AtmWr^lkX((eDjqt6T}LOgT>Hzhb@u9A_gb_IM+ qK(gM4PBB^rW7R?~b@U~M|E)JJ&wb}dbf>2P0000PiiMq( zXk|L>1UoG(ZLA{Nd+BVvLr63sVi7^odp9yMfsmh3EPU`_-rLzXI}7|<#I1Q#_+1}$ z8itk35-0~C+O%F7yj$@K=e+_{yD%+hi$G@pZXy9^gi?!VTF&O+fK)01V4n!5WzWri zMAU*%YViOZG<$ll5Kqh`LZyApyc{T%2J_-q2i@v0%m+kQnmJMO3y*zQ=m!RO{Z&`M zQ*@*Va4jIUT7J0OmdQe?L((g9R`ShaX8^T}2|KyLOeY|^&>>%n7bwbrd5wVUXU|O! z3=o+1+&V(efe>pLj4BBC0G1dyu6XVahQZ|Y?6|O{4cj?1Er$)uIqEeS!$2-KLZ+O( vmZyIbP=9;LkB-F{ir(wBYT;L}_;Y*$nxSw0y&Nck00000NkvXXu0mjfE3c*? literal 0 HcmV?d00001 diff --git a/data/icons/menu/light/help.png b/data/icons/menu/light/help.png new file mode 100644 index 0000000000000000000000000000000000000000..55032857ab7a7b883359dfb031403db462aef3b7 GIT binary patch literal 587 zcmV-R0<`^!P)?|3WAD5yL1xc(lkmpYpTTZ9!V)yYH>-EChvZ7-)n4A4G8*8_s4h6 z_kHKw3;biS>rFZx8Q5r?Fw1hEy@_0|`Bwz}=Tc{s(isxt0FLb)e;4qD_L;4G&aZbR zh@Veg2K79MZ-h*1t=1I~6N^!3eGfnkBBS2wyL=0y+AA9{A+PP--ixBu04Z}qc?vCe zdi>}$f^R_1$CJZ-zY!>?}2{b%J5i(epE1Le5u=4t?@0gkt@k+A*BDI=J`Dwus`C0_z?#lx5t zPg;)wT&1Xo=1v3!60vx4_@q}{-UwJoB|#&ma$B4oDo+Bu1@eZwntvOnggI0pMg=~9 zI{nqmM(U9ci$q@#@Rj#*X<=V0UIMV?uDsuD)8M6Vd=}wUB5}Q^m0YuHQ+2y~x3wP} zOgjSH2k;z#?r=f-%o?AY_V#Rx#MyOboW`LizrfDUEColX^rJ2hX(R<=4&Zj6ww7qv zH>;*HAx8<0y2ZlM9|;1I;E@=gc@seI-tku0b~9^~@6hQW!G0JE*MiUF6_<_3!OZ_X Zegb&{!EsU*rPlxe002ovPDHLkV1fbK1yuk5 literal 0 HcmV?d00001 diff --git a/data/icons/menu/light/join.png b/data/icons/menu/light/join.png new file mode 100644 index 0000000000000000000000000000000000000000..29a7d38ffae6029589a3245ad9ea3464c7190d2d GIT binary patch literal 369 zcmV-%0gnEOP)Q-V%f6v#cv0|2)G!mI!T zzl5ca;js4xU?VLk&)*@iB7%JqZeDE$*Jb&sS(n2W%pqo_kVW^MfIOUW*suc*uulSy! i*=;v3P6m1Z2|fT3;%E76;crd=0000U0rf*?phQ<&s-cVtfz<9URDpi>O_32eTh|O#n&?Z1rt2L>FEu ztS)wME_(k z>m~YDdtP2|jw`+fTFlr4^NME-<54J>y1zbqZf=PNH^x3&GU6@(hamJx3+eDgGT3aO zGz1B%JQOa9Zcfva9{{BRM5V|=P#c;C-8x)vRtFOUdd>BVz^BMo;Qh38HfT1 zGb!sW8EE>%zMzVGe>BbI2 zZkO}tsb;M}hfuu8-=tLia{(ybW>?!XfDM+rtxv#gF%TRXn;vy2i?3>{nK~y-6V_+C)z>Fc{;J_l!CE>0jC;ssH^XLBv8Nh@tpz!*q3&a2a z+g^WT*&?d#z(cYD4@BAbF#P|&l#zkKjqBg{{mOb)V)zVT#3invWl{hC|NnXh28R28 z85rE3Tt9i6xG;c%53ipb;1`p9&&a?K&cwhF&MzXf|Kppd&l!kx0UXF{m_;!#GR|jU zVEDLL+hU@(}(-{G$i z76w8h5d#%-Uuz-h4~u$D3}R^_3=Q{_Tb^9)W93Uu^1l1NbM8IgIl#Y0G@f2H@ta23 z#BrSNm@_%72P01cy+V-42{NgzYTbu)=y3&hM0klTdXGq({cCy?`c#m#BRz7SjX zo^%xG!E;3^CcScgx7DAuNcFP2qckRr#?A@Zq*N+30bG4~_qjwqYB%n6kY|63cZ{lv UG}OsFI{*Lx07*qoM6N<$f(Z$5^7#=+Mhb+fLNVBN61JCPk zEL#}<|KFzY`lk!JJPSU}%6e8}e|~@8%D}*2!tnq9(g&jKd(hP|;?gXyZl=h<#JGcj zfkBP&Kf|O4H%=BZFfgDvAEy^&G%R%)m>7>RFfge8XZT(Y?`rpK|#$@<3HoS zqYMlT>QLaBeAn#yHNCOW5Urby1#LqSG00000NkvXXu0mjf D$+eZD literal 0 HcmV?d00001 diff --git a/data/icons/menu/light/quit.png b/data/icons/menu/light/quit.png new file mode 100644 index 0000000000000000000000000000000000000000..165393d0d1a7f35c3912867405a8abbd2cfe7cf3 GIT binary patch literal 452 zcmV;#0XzPQP)ZO~(4C_3E}5RjDxKr4O-v|}waVyqR#pfcYT zAW6zFF%B4%^9rxKR)97%vb_A?^0=_qsP236puS5p5L~a uX$#;ffb{pcW~Nka+>=5!+p_iit3Cl;!*qR@DUopi000098tNKVRjYFI zG{*v=y3aW8sSfPta=R~Xcc|Y8<@4!>t_g;HQ&9oh2Ez^DzAgvsV3Y;0S|h9&`-)m( z$(TjE*yWvx2&O$^Tr*>$pe5`DE#auK7-zzzB+BVJ-#Sv&P661FeAWBEuGag6mKcYz$h3IdV8rwlMeWt~_^as))389E0qAx5 z!x4OguE(E^3%8$WB3!<328=tZ*k+p>e?+v|5|WKS4zjIssEmcDzihNN=ySm61(4hV z-~sRm@J2yPuKzkggP6tX(^ZlpC`hK7h5VUysmXf&v9HXhf* zPj90NB1Rx~NS)ta8pptv^KXNYIXp$gNicfAxGS>)0B0dEm%ljKtK^HyARLj?1m1?i zfhInUyp;*MOF-);&=C~vgrY-}^~J>Fx?xJ&Fo!q1^oF8x(}>C}kkD!-=ze@3cR7wj zOI{6}4=jQa4x9GacTWEmqasjLxVugjjEGzyB3W6?%$dBESu;%e;IN1QIIQ-7K_0L2 z7X%R3PM|akq`LflGT`1+ud+8b6#R71$wFB*9@w2tNA9NUSoZY55i0=aN`ImR?dR0C zRdYw+k_f9U9fAIqcK>PdrSR$=1!JSVt!=(_5Y0efw)ni8tI&f#Fb3oV3nU5X2XJ5J z_yAlH)4Xk^_p1!4hlCayycrS9gKor1JIhU|(B(21S{s3_+UAy-m zxa@Ceai`+0;?hM43SwN8(AvaJiMmi!5W#4J&o`%BlZP+yX$lSucR0+PnKN^NSDJXi zz{tl=r{c7}l>9f+a(?kUTMi_MC(KoY zeZ#4)Kmr;m6SxMsq8jeD4l(bmiID@_9YEAoeD-R>frAUsU}DGS-|xkcq!beNo|9 z4LO0)B|s+ZhkTKMg01TK58w2}UI1X3itD4|?hi=ajeI*GT>@Qjb%(%C{a!+El+Inx z;CR1~9ahp40x@P4>aHVX{sb+>)KUpl3^DVl)@QxRk0000<c&yhyW8fD-Vr`E-2Xd4E00006#NB7u@S!vu_vpw?SzIg6uinF zDd!Nm25=S8J0NQU+;#lsdTM}$@>aJoWF3NhNDw^;9sq0-IP3b&L(GEm^2(yEQSW-@ zL}^1;o6|`bV;0!qFl5ObkGSkl0tRm{w+l|5$jJL3=(T>e#h>E~wMicons/tree_server.png icons/tree_util.png - icons/menu/light/new.svg - icons/menu/light/network-list.svg - icons/menu/light/load-plugin.svg - icons/menu/light/detach.svg - icons/menu/light/close.svg - icons/menu/light/quit.svg - icons/menu/light/disconnect.svg - icons/menu/light/connect.svg - icons/menu/light/join.svg - icons/menu/light/chanlist.svg - icons/menu/light/preferences.svg - icons/menu/light/clear.svg - icons/menu/light/copy.svg - icons/menu/light/delete.svg - icons/menu/light/add.svg - icons/menu/light/remove.svg - icons/menu/light/spell-check.svg - icons/menu/light/save.svg - icons/menu/light/save-as.svg - icons/menu/light/refresh.svg - icons/menu/light/search.svg - icons/menu/light/find.svg - icons/menu/light/previous.svg - icons/menu/light/next.svg - icons/menu/light/help.svg - icons/menu/light/about.svg + icons/menu/light/new.png + icons/menu/light/network-list.png + icons/menu/light/load-plugin.png + icons/menu/light/detach.png + icons/menu/light/close.png + icons/menu/light/quit.png + icons/menu/light/disconnect.png + icons/menu/light/connect.png + icons/menu/light/join.png + icons/menu/light/chanlist.png + icons/menu/light/preferences.png + icons/menu/light/clear.png + icons/menu/light/copy.png + icons/menu/light/delete.png + icons/menu/light/add.png + icons/menu/light/remove.png + icons/menu/light/spell-check.png + icons/menu/light/save.png + icons/menu/light/save-as.png + icons/menu/light/refresh.png + icons/menu/light/search.png + icons/menu/light/find.png + icons/menu/light/previous.png + icons/menu/light/next.png + icons/menu/light/help.png + icons/menu/light/about.png - icons/menu/dark/new.svg - icons/menu/dark/network-list.svg - icons/menu/dark/load-plugin.svg - icons/menu/dark/detach.svg - icons/menu/dark/close.svg - icons/menu/dark/quit.svg - icons/menu/dark/disconnect.svg - icons/menu/dark/connect.svg - icons/menu/dark/join.svg - icons/menu/dark/chanlist.svg - icons/menu/dark/preferences.svg - icons/menu/dark/clear.svg - icons/menu/dark/copy.svg - icons/menu/dark/delete.svg - icons/menu/dark/add.svg - icons/menu/dark/remove.svg - icons/menu/dark/spell-check.svg - icons/menu/dark/save.svg - icons/menu/dark/save-as.svg - icons/menu/dark/refresh.svg - icons/menu/dark/search.svg - icons/menu/dark/find.svg - icons/menu/dark/previous.svg - icons/menu/dark/next.svg - icons/menu/dark/help.svg - icons/menu/dark/about.svg + icons/menu/dark/new.png + icons/menu/dark/network-list.png + icons/menu/dark/load-plugin.png + icons/menu/dark/detach.png + icons/menu/dark/close.png + icons/menu/dark/quit.png + icons/menu/dark/disconnect.png + icons/menu/dark/connect.png + icons/menu/dark/join.png + icons/menu/dark/chanlist.png + icons/menu/dark/preferences.png + icons/menu/dark/clear.png + icons/menu/dark/copy.png + icons/menu/dark/delete.png + icons/menu/dark/add.png + icons/menu/dark/remove.png + icons/menu/dark/spell-check.png + icons/menu/dark/save.png + icons/menu/dark/save-as.png + icons/menu/dark/refresh.png + icons/menu/dark/search.png + icons/menu/dark/find.png + icons/menu/dark/previous.png + icons/menu/dark/next.png + icons/menu/dark/help.png + icons/menu/dark/about.png diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index 8c772908..fd3c3617 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -220,8 +220,14 @@ gtkutil_menu_icon_pixbuf_new (const char *icon_name) if (!icon_name || !g_str_has_prefix (icon_name, "zc-menu-")) return NULL; - resource_path = g_strdup_printf ("/icons/menu/light/%s.svg", icon_name + strlen ("zc-menu-")); - pixbuf = gdk_pixbuf_new_from_resource_at_scale (resource_path, -1, -1, TRUE, NULL); + resource_path = g_strdup_printf ("/icons/menu/light/%s.png", icon_name + strlen ("zc-menu-")); + pixbuf = gdk_pixbuf_new_from_resource (resource_path, NULL); + if (!pixbuf) + { + g_free (resource_path); + resource_path = g_strdup_printf ("/icons/menu/light/%s.svg", icon_name + strlen ("zc-menu-")); + pixbuf = gdk_pixbuf_new_from_resource (resource_path, NULL); + } g_free (resource_path); return pixbuf; @@ -326,14 +332,25 @@ gtkutil_menu_icon_image_new (const char *icon_name, GtkIconSize size) return NULL; variant = gtkutil_menu_icon_theme_variant (); - resource_path = g_strdup_printf ("/icons/menu/%s/%s.svg", variant, icon_name + strlen ("zc-menu-")); + resource_path = g_strdup_printf ("/icons/menu/%s/%s.png", variant, icon_name + strlen ("zc-menu-")); if (!g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL)) { g_free (resource_path); - resource_path = g_strdup_printf ("/icons/menu/light/%s.svg", icon_name + strlen ("zc-menu-")); + resource_path = g_strdup_printf ("/icons/menu/light/%s.png", icon_name + strlen ("zc-menu-")); } - pixbuf = gdk_pixbuf_new_from_resource_at_scale (resource_path, -1, -1, TRUE, NULL); + pixbuf = gdk_pixbuf_new_from_resource (resource_path, NULL); + if (!pixbuf) + { + g_free (resource_path); + resource_path = g_strdup_printf ("/icons/menu/%s/%s.svg", variant, icon_name + strlen ("zc-menu-")); + if (!g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL)) + { + g_free (resource_path); + resource_path = g_strdup_printf ("/icons/menu/light/%s.svg", icon_name + strlen ("zc-menu-")); + } + pixbuf = gdk_pixbuf_new_from_resource (resource_path, NULL); + } if (pixbuf) { image = gtk_image_new_from_pixbuf (pixbuf); diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 81cda565..32364b53 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -74,8 +74,14 @@ menu_icon_exists_in_resource (const char *icon_name) if (!icon_name || !g_str_has_prefix (icon_name, "zc-menu-")) return FALSE; - resource_path = g_strdup_printf ("/icons/menu/light/%s.svg", icon_name + strlen ("zc-menu-")); + resource_path = g_strdup_printf ("/icons/menu/light/%s.png", icon_name + strlen ("zc-menu-")); found = g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL); + if (!found) + { + g_free (resource_path); + resource_path = g_strdup_printf ("/icons/menu/light/%s.svg", icon_name + strlen ("zc-menu-")); + found = g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL, NULL, NULL); + } g_free (resource_path); return found; From 7568c73062c7c98a8a8b217e794aa3503fa3420b Mon Sep 17 00:00:00 2001 From: deepend Date: Wed, 18 Feb 2026 01:30:45 -0700 Subject: [PATCH 38/38] Updated the Network List Connect button icon on GTK3 to use the bundled zc-menu-connect asset, which avoids theme-dependent missing network-connect behavior. Added a Help menu _Update entry with a dedicated zc-menu-update icon constant, so Windows builds can display an appropriate update icon in the Help menu. Extended icon mapping/fallback logic so emoji/update icons resolve correctly across stock/icon-name paths (zc-menu-emoji, zc-menu-update) including GTK2 stock fallback compatibility. Added zc-menu-emoji to the input entry fallback icon list so the emoji affordance has a deterministic built-in fallback when theme emoji icons are missing. Added new update and emoji icon assets in both SVG and PNG for light/dark variants, and registered the PNG resources in the gresource manifest for runtime loading. --- data/icons/menu/dark/emoji.png | Bin 0 -> 536 bytes data/icons/menu/dark/emoji.svg | 1 + data/icons/menu/dark/update.png | Bin 0 -> 499 bytes data/icons/menu/dark/update.svg | 1 + data/icons/menu/light/emoji.png | Bin 0 -> 589 bytes data/icons/menu/light/emoji.svg | 1 + data/icons/menu/light/update.png | Bin 0 -> 503 bytes data/icons/menu/light/update.svg | 1 + data/zoitechat.gresource.xml | 4 ++++ src/fe-gtk/gtkutil.c | 6 ++++++ src/fe-gtk/maingui.c | 1 + src/fe-gtk/menu.c | 2 ++ src/fe-gtk/servlistgui.c | 2 +- 13 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 data/icons/menu/dark/emoji.png create mode 100644 data/icons/menu/dark/emoji.svg create mode 100644 data/icons/menu/dark/update.png create mode 100644 data/icons/menu/dark/update.svg create mode 100644 data/icons/menu/light/emoji.png create mode 100644 data/icons/menu/light/emoji.svg create mode 100644 data/icons/menu/light/update.png create mode 100644 data/icons/menu/light/update.svg diff --git a/data/icons/menu/dark/emoji.png b/data/icons/menu/dark/emoji.png new file mode 100644 index 0000000000000000000000000000000000000000..c95918dd02f5ce754b03b94f79bcd5d98922c5df GIT binary patch literal 536 zcmV+z0_XjSP)Y+$ z)oN8t{H=#vF9;zfwd%bB$P(a8oL5yB&<*00*MlI4ZzM?5^dUv|i5-0z_mU4jJ^N|v z`Pdy~eBo49AD<{a_Jni(eS|;=QPZloS8BfDOzey(GmzmU-Jg09gZeXJ7$&Ahi%YF~ zYv$#fh7DNf8(~LZD;V_GiWU{ zy7xAq%J(nY&Dqopa_=snrLZ%F0tezXIH^@{ztr5|Ol*_ftzi(%+B;Y5f(~NHa8CE9Ru47tW~$X{Iz#{fNs>Hpi2Q6; zW!$!gS=rOb_~NMy=ekO>dCvKd5d{T0oesBqCRhe#!8wBz(Ad(Bzh1n2D@0K=ZsOJh a|AJpC#ljia%?}6w0000 \ No newline at end of file diff --git a/data/icons/menu/dark/update.png b/data/icons/menu/dark/update.png new file mode 100644 index 0000000000000000000000000000000000000000..83680b92ff283bda232c6947172218af8fdda593 GIT binary patch literal 499 zcmVh~+^@bKrTpZyzX};bvquyT`I8q!9<^@#Zn#H{Y8X;D1|D z6i>~Yn14%(G2R!EZ2)%wtO7V8xu&Y$N#0gf$+B$2a+lgbRlO8rd@dr7>!%rjDS&~h zHfd+hxo=J2T42T)4^`E`Uqocfd%v1xnJIV%U}z+&x~!^cgIj7YA%ty`TdMkYI-Nf3 z_xnFvwX)P>#|0f5T@CQT34?GTYuTx{1()ND2z&ztC+tJq223nAp@CcBG_F%AIS z1#q0_d6*L}+v002ovPDHLkV1ksO-M;_; literal 0 HcmV?d00001 diff --git a/data/icons/menu/dark/update.svg b/data/icons/menu/dark/update.svg new file mode 100644 index 00000000..61794d66 --- /dev/null +++ b/data/icons/menu/dark/update.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/icons/menu/light/emoji.png b/data/icons/menu/light/emoji.png new file mode 100644 index 0000000000000000000000000000000000000000..d8fe5cdb234a367e05c12f9c81e6fe3aa86c007c GIT binary patch literal 589 zcmV-T0Ca6c9+e%lT=RbIn*MaHR$D(HkjZ2YD{}1J^($g>I>R5BjA5 zaev2@0uVxIZ-Ppt(k48%jiw(I%r1A}?T7Hru<_mxIEGJKJ`>+zJuK$CMU#``qaBN; zPpX1&><9;ow=DSj&4)MZKHPp{!{UMnV<`@9KDN!xEqZ73(^U5vrh1PA51OYc2*e>yII!7z;A&lp{krfI4q;%l}l<~B2o!Dv!= z_`){V8eYq?;k2&n8$E;jcb&`Sl5EdxRj!9h;51Knki+}7!>?4U)gS#m1EH#Ff}Ou^ b_!sN}tv|ZzgE@_(00000NkvXXu0mjfhxQd0 literal 0 HcmV?d00001 diff --git a/data/icons/menu/light/emoji.svg b/data/icons/menu/light/emoji.svg new file mode 100644 index 00000000..989062b8 --- /dev/null +++ b/data/icons/menu/light/emoji.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/icons/menu/light/update.png b/data/icons/menu/light/update.png new file mode 100644 index 0000000000000000000000000000000000000000..c06163f42d33c33ecc7d54c08503131e3e4ca3ef GIT binary patch literal 503 zcmVf3tflvI)X!B&|w{SP0_6Eh|^7jikz-p!R9> ze=wZ{TMH2z!N&GVPmtR^-ug$;O;x=I+yEAUPrwD>J8)f9XTamR0ZEda&GY<;s@^HD{s6y$)v88SC&0HV zcN+at6vaysvE~oJdJqH)S(X`tP2gi$=K<&DBt%hUl-Gg&cs#y68jXH6$pI@37XBOq z5qV&gMda>@W+s!#tyZgb-U8SW5ho18rJ6yz-8O@+0dLbZt*F)*4u__Dzhs(<$R*cx zZP?y11J`vgmbJV52O@IWRQSICwPrAz&GtpaKE|C+C$PIb&kxE!*NEeIRaM)-cCXj_ zS$i-T48GVLRlPEuPJdW|7z2yt*?f3ohcFC%&-2!bqId{g z1zu%Y_M(GW%WJacGdc5POh9h0mm`u_OpIQI_002ovPDHLkV1iJ}>N)@b literal 0 HcmV?d00001 diff --git a/data/icons/menu/light/update.svg b/data/icons/menu/light/update.svg new file mode 100644 index 00000000..b423fa58 --- /dev/null +++ b/data/icons/menu/light/update.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/zoitechat.gresource.xml b/data/zoitechat.gresource.xml index b85d7163..93f45143 100644 --- a/data/zoitechat.gresource.xml +++ b/data/zoitechat.gresource.xml @@ -47,6 +47,8 @@ icons/menu/light/next.png icons/menu/light/help.png icons/menu/light/about.png + icons/menu/light/update.png + icons/menu/light/emoji.png icons/menu/dark/new.png icons/menu/dark/network-list.png @@ -74,5 +76,7 @@ icons/menu/dark/next.png icons/menu/dark/help.png icons/menu/dark/about.png + icons/menu/dark/update.png + icons/menu/dark/emoji.png diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index fd3c3617..21e53573 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -96,6 +96,7 @@ gtkutil_menu_custom_icon_from_stock (const char *stock_name) { "gtk-go-forward", "zc-menu-next" }, { "gtk-help", "zc-menu-help" }, { "gtk-about", "zc-menu-about" }, + { "gtk-convert", "zc-menu-emoji" }, }; size_t i; @@ -143,6 +144,9 @@ gtkutil_menu_custom_icon_from_icon_name (const char *icon_name) { "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" }, }; size_t i; @@ -195,6 +199,8 @@ gtkutil_stock_from_menu_custom_icon (const char *custom_icon) { "zc-menu-next", GTK_STOCK_GO_FORWARD }, { "zc-menu-help", GTK_STOCK_HELP }, { "zc-menu-about", GTK_STOCK_ABOUT }, + { "zc-menu-emoji", GTK_STOCK_CONVERT }, + { "zc-menu-update", GTK_STOCK_REFRESH }, }; size_t i; diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index 20dad6b8..522bf769 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -3545,6 +3545,7 @@ mg_create_entry (session *sess, GtkWidget *box) "face-smile", "insert-emoticon-symbolic", "insert-emoticon", + "zc-menu-emoji", NULL }; const char *emoji_fallback_icon_name; diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 32364b53..3c1275b9 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -2014,6 +2014,7 @@ menu_about (GtkWidget *wid, gpointer sess) #define ICON_FIND "zc-menu-find" #define ICON_HELP "zc-menu-help" #define ICON_ABOUT "zc-menu-about" +#define ICON_UPDATE "zc-menu-update" static struct mymenu mymenu[] = { {N_("_ZoiteChat"), 0, 0, M_NEWMENU, MENU_ID_ZOITECHAT, 0, 1}, @@ -2109,6 +2110,7 @@ static struct mymenu mymenu[] = { {N_("_Help"), 0, 0, M_NEWMENU, 0, 0, 1}, /* 74 */ {N_("_Contents"), menu_docs, ICON_HELP, M_MENUSTOCK, 0, 0, 1, GDK_KEY_F1}, + {N_("_Update"), menu_docs, ICON_UPDATE, M_MENUSTOCK, 0, 0, 1}, {N_("_About"), menu_about, ICON_ABOUT, M_MENUSTOCK, 0, 0, 1}, {0, 0, 0, M_END, 0, 0, 0}, diff --git a/src/fe-gtk/servlistgui.c b/src/fe-gtk/servlistgui.c index 2a014be6..230238f7 100644 --- a/src/fe-gtk/servlistgui.c +++ b/src/fe-gtk/servlistgui.c @@ -40,7 +40,7 @@ #define SERVLIST_Y_PADDING 0 /* vertical padding in the network editor */ #if HAVE_GTK3 -#define ICON_SERVLIST_CONNECT "network-connect" +#define ICON_SERVLIST_CONNECT "zc-menu-connect" #define ICON_SERVLIST_ADD "list-add" #define ICON_SERVLIST_REMOVE "list-remove" #define ICON_SERVLIST_CLOSE "window-close"