From 314dfbbd7528b18e79005a41c0c19e7fec954460 Mon Sep 17 00:00:00 2001 From: deepend Date: Mon, 23 Feb 2026 16:11:41 -0700 Subject: [PATCH 1/5] =?UTF-8?q?Fixed=20highlight=20word=20parsing=20so=20U?= =?UTF-8?q?nicode=20symbols=20(including=20emoji=20like=20=F0=9F=90=9C)=20?= =?UTF-8?q?are=20treated=20as=20part=20of=20words=20when=20scanning=20inco?= =?UTF-8?q?ming=20text=20for=20alert=20matches,=20which=20enables=20/Extra?= =?UTF-8?q?=20words=20to=20highlight/=20entries=20containing=20emoji=20to?= =?UTF-8?q?=20work.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improved token scanning to use UTF-8-aware character classification (gunichar, g_unichar_isdigit, g_unichar_isalpha) instead of byte-only checks, avoiding split/mis-detection on multibyte characters. --- src/common/inbound.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/common/inbound.c b/src/common/inbound.c index adbe6d34..10f5cbc5 100644 --- a/src/common/inbound.c +++ b/src/common/inbound.c @@ -258,6 +258,7 @@ alert_match_text (char *text, char *masks) { unsigned char *p = text; unsigned char endchar; + gunichar ch; int res; if (masks[0] == 0) @@ -265,26 +266,36 @@ alert_match_text (char *text, char *masks) while (1) { - if (*p >= '0' && *p <= '9') + ch = g_utf8_get_char (p); + + if (g_unichar_isdigit (ch) || g_unichar_isalpha (ch)) { - p++; + p += g_utf8_skip [p[0]]; continue; } /* if it's RFC1459 , it can be inside a word */ - switch (*p) + switch (ch) { case '-': case '[': case ']': case '\\': case '`': case '^': case '{': case '}': case '_': case '|': - p++; + p += g_utf8_skip [p[0]]; + continue; + } + + /* Symbols (including emoji) can be part of highlighted words. */ + if (!g_unichar_isspace (ch) && !g_unichar_ispunct (ch) && + !g_unichar_iscntrl (ch)) + { + p += g_utf8_skip [p[0]]; continue; } /* if it's a 0, space or comma, the word has ended. */ if (*p == 0 || *p == ' ' || *p == ',' || /* if it's anything BUT a letter, the word has ended. */ - (!g_unichar_isalpha (g_utf8_get_char (p)))) + (!g_unichar_isalpha (ch))) { endchar = *p; *p = 0; From b7804fd7ebb71f9ea9a5557be027f44a23876e74 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 24 Feb 2026 08:35:23 -0700 Subject: [PATCH 2/5] Fixed the right-click nick info refresh flow in fe_userlist_update() so the submenu can keep updating after the first refresh when WHOIS-derived data is still incomplete. It now tracks a needs_refresh condition and reattaches the submenu show callback when required. This ensures user info can continue to refresh as data arrives instead of stopping after one update. --- src/fe-gtk/menu.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index f48dbb55..b94d1762 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -778,6 +778,7 @@ fe_userlist_update (session *sess, struct User *user) { GList *items, *next; GList *iter; + gboolean needs_refresh; if (!nick_submenu || !str_copy) return; @@ -801,7 +802,14 @@ fe_userlist_update (session *sess, struct User *user) g_list_free (items); /* and re-create them with new info */ - menu_create_nickinfo_menu (user, nick_submenu); + needs_refresh = menu_create_nickinfo_menu (user, nick_submenu) || + !user->hostname || !user->realname || !user->servername; + + if (needs_refresh) + { + g_signal_connect (G_OBJECT (nick_submenu), "show", + G_CALLBACK (menu_nickinfo_cb), sess); + } } void From 0935799f7d93ae4493c6fd12ae5b839cc4f7591f Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 24 Feb 2026 11:18:46 -0700 Subject: [PATCH 3/5] Updated emoji-token normalization to first apply Unicode composition normalization (G_NORMALIZE_ALL_COMPOSE) before matching, so canonically-equivalent sequences compare reliably in highlight checks. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expanded ignored codepoints during highlight token comparison to include zero-width joiner (U+200D) in addition to variation selectors (U+FE0E/U+FE0F), which helps emoji entered from different input methods still match configured “extra highlight words.” This logic is used by the alert/highlight matching path (alert_match_word) that compares configured extra words against extracted message tokens. --- src/common/inbound.c | 61 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/src/common/inbound.c b/src/common/inbound.c index 10f5cbc5..0b7ae0db 100644 --- a/src/common/inbound.c +++ b/src/common/inbound.c @@ -222,15 +222,51 @@ inbound_privmsg (server *serv, char *from, char *ip, char *text, int id, /* used for Alerts section. Masks can be separated by commas and spaces. */ +static char * +alert_normalize_word (const char *text) +{ + GString *normalized; + char *composed; + const char *p; + + composed = g_utf8_normalize (text, -1, G_NORMALIZE_ALL_COMPOSE); + if (!composed) + composed = g_strdup (text); + + normalized = g_string_sized_new (strlen (composed)); + p = composed; + + while (*p) + { + gunichar ch = g_utf8_get_char ((const guchar *)p); + + /* Ignore selector/joiner codepoints that vary by input method. */ + if (ch != 0x200D && ch != 0xFE0E && ch != 0xFE0F) + g_string_append_unichar (normalized, ch); + + p = g_utf8_next_char (p); + } + + g_free (composed); + return g_string_free (normalized, FALSE); +} + gboolean alert_match_word (char *word, char *masks) { char *p = masks; char endchar; + char *word_normalized; + char *mask_normalized; int res; + word_normalized = alert_normalize_word (word); + if (masks[0] == 0) + { + g_free (word_normalized); return FALSE; + } while (1) { @@ -239,15 +275,23 @@ alert_match_word (char *word, char *masks) { endchar = *p; *p = 0; - res = match (g_strchug (masks), word); + mask_normalized = alert_normalize_word (g_strchug (masks)); + res = match (mask_normalized, word_normalized); + g_free (mask_normalized); *p = endchar; if (res) + { + g_free (word_normalized); return TRUE; /* yes, matched! */ + } masks = p + 1; if (*p == 0) + { + g_free (word_normalized); return FALSE; + } } p++; } @@ -259,6 +303,7 @@ alert_match_text (char *text, char *masks) unsigned char *p = text; unsigned char endchar; gunichar ch; + GUnicodeType ch_type; int res; if (masks[0] == 0) @@ -267,6 +312,7 @@ alert_match_text (char *text, char *masks) while (1) { ch = g_utf8_get_char (p); + ch_type = g_unichar_type (ch); if (g_unichar_isdigit (ch) || g_unichar_isalpha (ch)) { @@ -285,17 +331,18 @@ alert_match_text (char *text, char *masks) } /* Symbols (including emoji) can be part of highlighted words. */ - if (!g_unichar_isspace (ch) && !g_unichar_ispunct (ch) && - !g_unichar_iscntrl (ch)) + if (ch_type == G_UNICODE_MATH_SYMBOL || + ch_type == G_UNICODE_CURRENCY_SYMBOL || + ch_type == G_UNICODE_MODIFIER_SYMBOL || + ch_type == G_UNICODE_OTHER_SYMBOL) { p += g_utf8_skip [p[0]]; continue; } - /* if it's a 0, space or comma, the word has ended. */ - if (*p == 0 || *p == ' ' || *p == ',' || - /* if it's anything BUT a letter, the word has ended. */ - (!g_unichar_isalpha (ch))) + /* Delimiters end the word. */ + if (*p == 0 || g_unichar_isspace (ch) || g_unichar_ispunct (ch) || + g_unichar_iscntrl (ch)) { endchar = *p; *p = 0; From 9ee8a53b9c89df580742f20e0834a4b872e54788 Mon Sep 17 00:00:00 2001 From: deepend Date: Tue, 24 Feb 2026 11:48:04 -0700 Subject: [PATCH 4/5] Moved the Flatpak display troubleshooting content from readme.md into a standalone troubleshooting.md document, as requested. Replaced the large inline README section with a single link to the new troubleshooting file to keep the README concise. --- readme.md | 3 +++ troubleshooting.md | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 troubleshooting.md diff --git a/readme.md b/readme.md index c74fea04..f1c06092 100644 --- a/readme.md +++ b/readme.md @@ -36,6 +36,9 @@ See [IRCHelp.org](http://irchelp.org) for information about IRC in general. For more information on ZoiteChat please read our [documentation](https://docs.zoitechat.zoite.net/): - [Downloads](https://zoitechat.zoite.net/download) +- [Troubleshooting](troubleshooting.md) + + --- diff --git a/troubleshooting.md b/troubleshooting.md new file mode 100644 index 00000000..23cf8c51 --- /dev/null +++ b/troubleshooting.md @@ -0,0 +1,41 @@ +# Troubleshooting + +## Flatpak + +If `flatpak run net.zoite.Zoitechat` only prints `Gtk-WARNING **: cannot open display`, +collect extra diagnostics with: + +```bash +flatpak run --devel --command=sh net.zoite.Zoitechat +``` + +Then inside that shell: + +```bash +echo "DISPLAY=$DISPLAY WAYLAND_DISPLAY=$WAYLAND_DISPLAY XDG_SESSION_TYPE=$XDG_SESSION_TYPE" +xdpyinfo >/tmp/xdpyinfo.log 2>&1 || true +env G_MESSAGES_DEBUG=all zoitechat 2>&1 | tee /tmp/zoitechat-debug.log +``` + +To inspect sandbox permissions from the host: + +```bash +flatpak info --show-permissions net.zoite.Zoitechat +flatpak override --user --show net.zoite.Zoitechat +``` + +If needed, try running with direct access to your active display stack: + +```bash +# X11 sessions +flatpak override --user --socket=x11 net.zoite.Zoitechat + +# Wayland sessions +flatpak override --user --socket=wayland net.zoite.Zoitechat +``` + +You can reset overrides after testing: + +```bash +flatpak override --user --reset net.zoite.Zoitechat +``` From 118ac25059e737c110e438a39a825ed97e95dd55 Mon Sep 17 00:00:00 2001 From: deepend-tildeclub <58404188+deepend-tildeclub@users.noreply.github.com> Date: Tue, 24 Feb 2026 14:22:01 -0700 Subject: [PATCH 5/5] Change network name check from 'Libera.Chat' to 'Zoite' --- src/fe-gtk/joind.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fe-gtk/joind.c b/src/fe-gtk/joind.c index f2644f68..fcc9909c 100644 --- a/src/fe-gtk/joind.c +++ b/src/fe-gtk/joind.c @@ -252,7 +252,7 @@ joind_show_dialog (server *serv) G_CALLBACK (joind_ok_cb), serv); if (serv->network) - if (g_ascii_strcasecmp(((ircnet*)serv->network)->name, "Libera.Chat") == 0) + if (g_ascii_strcasecmp(((ircnet*)serv->network)->name, "Zoite") == 0) { gtk_entry_set_text (GTK_ENTRY (entry1), "#zoitechat"); }