Compare commits

...
Author SHA1 Message Date
deepend aa52236c01 New Release: 2.18.0 2026-04-20 11:56:03 -06:00
deepend cd5b61d9d0 Use KiB/MiB units for DCC speed limits 2026-04-20 10:38:22 -06:00
deepend 4eefdd6011 Stop palette CSS from styling radio rings 2026-04-20 10:32:54 -06:00
deepend-tildeclub 21748b3133 Merge pull request #204 from ZoiteChat/flatpak-improvements
Tighten Flatpak perms, pin lgi source
2026-04-16 10:53:49 -06:00
deepend-tildeclub e7db202f88 Merge pull request #207 from ZoiteChat/domain-url-parsing
Validate host links with PSL rules
2026-04-15 02:36:09 -06:00
deepend a93e76eaf4 Add PSL fetch step to Flatpak CI 2026-04-14 15:56:43 -06:00
deepend 3c5bdb2ab2 Revert Meson PSL input wiring, keep generator fallback logic 2026-04-14 09:53:16 -06:00
deepend e49333340f Tighten Flatpak perms, pin lgi source 2026-04-12 23:43:12 -06:00
10 changed files with 190 additions and 28 deletions
+3
View File
@@ -25,6 +25,9 @@ jobs:
with: with:
submodules: true submodules: true
- name: Generate PSL list
run: curl -fsSL https://publicsuffix.org/list/public_suffix_list.dat -o src/common/public_suffix_list.dat
- name: Build Flatpak - name: Build Flatpak
id: flatpak_builder id: flatpak_builder
uses: flatpak/flatpak-github-actions/flatpak-builder@v6 uses: flatpak/flatpak-github-actions/flatpak-builder@v6
+17
View File
@@ -1,6 +1,23 @@
ZoiteChat ChangeLog ZoiteChat ChangeLog
================= =================
2.18.0 (2026-04-20)
- Added optional close buttons on tabs.
- Added Ctrl+W to close tabs and Ctrl+Shift+T to reopen recently closed tabs.
- Expanded theme import support with .hct support in colors.conf import.
- Added pevent import support from .hct theme files and improved import result messaging.
- Expanded palette and selection CSS styling for better theme consistency.
- Auto-sizes the topic bar to wrapped text for better multi-line topic handling.
- Refined command-character parsing when pasting path-like text.
- Tightened topic link detection and opening rules.
- Added Public Suffix List validation for host links to reduce bad link matches.
- Improved channel tree behavior by ignoring collapsed parent selections.
- Sanitized the Linux open environment for AppImage builds and added safer fallback handling.
- Labeled Windows installer runtimes with exact versions.
- Fixed the notification icon and corrected the Flatpak screenshot asset.
- Improved AppStream metainfo validation.
2.18.0~pre6 (2026-03-30) 2.18.0~pre6 (2026-03-30)
- Applied app theme CSS to the menubar consistently across the app. - Applied app theme CSS to the menubar consistently across the app.
@@ -29,6 +29,36 @@
<id>zoitechat.desktop</id> <id>zoitechat.desktop</id>
</provides> </provides>
<releases> <releases>
<release date="2026-04-20" version="2.18.0">
<description>
<p>Tabs and navigation:</p>
<ul>
<li>Added optional close buttons on tabs.</li>
<li>Added Ctrl+W to close tabs and Ctrl+Shift+T to reopen recently closed tabs.</li>
<li>Improved channel tree behavior by ignoring collapsed parent selections.</li>
</ul>
<p>Themes and appearance:</p>
<ul>
<li>Expanded theme import support with .hct support in colors.conf import.</li>
<li>Added pevent import support from .hct theme files and improved import result messaging.</li>
<li>Expanded palette and selection CSS styling for better theme consistency.</li>
<li>Auto-sizes the topic bar to wrapped text for better multi-line topic handling.</li>
</ul>
<p>Links and text handling:</p>
<ul>
<li>Refined command-character parsing when pasting path-like text.</li>
<li>Tightened topic link detection and opening rules.</li>
<li>Added Public Suffix List validation for host links to reduce bad link matches.</li>
</ul>
<p>Packaging and platform integration:</p>
<ul>
<li>Sanitized the Linux open environment for AppImage builds and added safer fallback handling.</li>
<li>Labeled Windows installer runtimes with exact versions.</li>
<li>Fixed the notification icon and corrected the Flatpak screenshot asset.</li>
<li>Improved AppStream metainfo validation.</li>
</ul>
</description>
</release>
<release date="2026-03-30" version="2.18.0~pre6"> <release date="2026-03-30" version="2.18.0~pre6">
<description> <description>
<p>GTK theme and UI:</p> <p>GTK theme and UI:</p>
+5 -6
View File
@@ -7,14 +7,13 @@
"command": "zoitechat", "command": "zoitechat",
"finish-args": [ "finish-args": [
"--share=ipc", "--share=ipc",
"--socket=x11", "--socket=wayland",
"--socket=fallback-x11",
"--share=network", "--share=network",
"--socket=pulseaudio", "--socket=pulseaudio",
"--filesystem=xdg-download", "--filesystem=xdg-download",
"--filesystem=xdg-data/themes:ro", "--filesystem=xdg-data/themes:ro",
"--filesystem=xdg-data/icons:ro", "--filesystem=xdg-data/icons:ro",
"--filesystem=~/.themes:ro",
"--filesystem=~/.icons:ro",
"--filesystem=xdg-run/tray-icon:create", "--filesystem=xdg-run/tray-icon:create",
"--env=GTK_CSD=1", "--env=GTK_CSD=1",
"--talk-name=org.freedesktop.Notifications", "--talk-name=org.freedesktop.Notifications",
@@ -45,9 +44,9 @@
"buildsystem": "meson", "buildsystem": "meson",
"sources": [ "sources": [
{ {
"type": "git", "type": "archive",
"url": "https://github.com/pavouk/lgi.git", "url": "https://github.com/pavouk/lgi/archive/c9b8e4473c6421f2a215d8c06c0d94b86eb0b26a.tar.gz",
"commit": "c9b8e4473c6421f2a215d8c06c0d94b86eb0b26a" "sha256": "db67b2b7ee89fa566f783486d56be7203552a997bc55f35020b57dd2776b9943"
} }
] ]
}, },
+1 -1
View File
@@ -1,5 +1,5 @@
project('zoitechat', 'c', project('zoitechat', 'c',
version: '2.18.0~pre6', version: '2.18.0',
meson_version: '>= 0.55.0', meson_version: '>= 0.55.0',
default_options: [ default_options: [
'c_std=c17', 'c_std=c17',
+1 -1
View File
@@ -19,7 +19,7 @@ else:
if not hasattr(sys, 'argv'): if not hasattr(sys, 'argv'):
sys.argv = ['<zoitechat>'] sys.argv = ['<zoitechat>']
VERSION = b'2.18.0~pre6' VERSION = b'2.18.0'
PLUGIN_NAME = ffi.new('char[]', b'Python') PLUGIN_NAME = ffi.new('char[]', b'Python')
PLUGIN_DESC = ffi.new('char[]', b'Python %d.%d scripting interface' % (sys.version_info[0], sys.version_info[1])) PLUGIN_DESC = ffi.new('char[]', b'Python %d.%d scripting interface' % (sys.version_info[0], sys.version_info[1]))
PLUGIN_VERSION = ffi.new('char[]', VERSION) PLUGIN_VERSION = ffi.new('char[]', VERSION)
+29 -9
View File
@@ -3,7 +3,10 @@ import sys
import urllib.request import urllib.request
from pathlib import Path from pathlib import Path
URL = "https://raw.githubusercontent.com/publicsuffix/list/main/public_suffix_list.dat" URLS = (
"https://raw.githubusercontent.com/publicsuffix/list/main/public_suffix_list.dat",
"https://publicsuffix.org/list/public_suffix_list.dat",
)
def parse_rules(text: str): def parse_rules(text: str):
@@ -32,19 +35,36 @@ def emit_header(path: str, rules):
def main(): def main():
if len(sys.argv) != 2: if len(sys.argv) not in (2, 3):
raise SystemExit("usage: gen-public-suffix.py <output>") raise SystemExit("usage: gen-public-suffix.py <output> [source]")
output = Path(sys.argv[1]) output = Path(sys.argv[1])
fallback = Path(__file__).with_name("public_suffix_data.h") sources = []
if len(sys.argv) == 3:
sources.append(Path(sys.argv[2]))
sources.extend(
[
Path(__file__).with_name("public_suffix_list.dat"),
Path("/usr/share/publicsuffix/public_suffix_list.dat"),
Path("/app/share/publicsuffix/public_suffix_list.dat"),
]
)
data = None
for url in URLS:
try: try:
with urllib.request.urlopen(URL, timeout=30) as resp: with urllib.request.urlopen(url, timeout=30) as resp:
data = resp.read().decode("utf-8") data = resp.read().decode("utf-8")
break
except Exception:
pass
if data is None:
for source in sources:
if source.exists():
data = source.read_text(encoding="utf-8")
break
if data is None:
raise SystemExit("unable to load public suffix list")
rules = parse_rules(data) rules = parse_rules(data)
emit_header(str(output), rules) emit_header(str(output), rules)
except Exception:
if not fallback.exists():
raise
output.write_bytes(fallback.read_bytes())
if __name__ == "__main__": if __name__ == "__main__":
+94 -1
View File
@@ -367,7 +367,7 @@ static const setting filexfer_settings[] =
{ST_TOGGLE, N_("Receive window"), P_OFFINTNL(hex_gui_autoopen_recv), 0, 0, 0}, {ST_TOGGLE, N_("Receive window"), P_OFFINTNL(hex_gui_autoopen_recv), 0, 0, 0},
{ST_TOGGLE, N_("Chat window"), P_OFFINTNL(hex_gui_autoopen_chat), 0, 0, 0}, {ST_TOGGLE, N_("Chat window"), P_OFFINTNL(hex_gui_autoopen_chat), 0, 0, 0},
{ST_HEADER, N_("Maximum File Transfer Speeds (Byte per Second)"), 0, 0, 0}, {ST_HEADER, N_("Maximum File Transfer Speeds (KiB/s or MiB/s)"), 0, 0, 0},
{ST_NUMBER, N_("One upload:"), P_OFFINTNL(hex_dcc_max_send_cps), {ST_NUMBER, N_("One upload:"), P_OFFINTNL(hex_dcc_max_send_cps),
N_("Maximum speed for one transfer"), 0, 10000000}, N_("Maximum speed for one transfer"), 0, 10000000},
{ST_NUMBER, N_("One download:"), P_OFFINTNL(hex_dcc_max_get_cps), {ST_NUMBER, N_("One download:"), P_OFFINTNL(hex_dcc_max_get_cps),
@@ -873,6 +873,67 @@ setup_create_italic_label (char *text)
return label; return label;
} }
typedef struct
{
const setting *set;
GtkSpinButton *spin;
GtkComboBox *unit;
} setup_dcc_speed_data;
static gboolean
setup_is_dcc_speed_setting (const setting *set)
{
return set->offset == P_OFFINTNL (hex_dcc_max_send_cps)
|| set->offset == P_OFFINTNL (hex_dcc_max_get_cps)
|| set->offset == P_OFFINTNL (hex_dcc_global_max_send_cps)
|| set->offset == P_OFFINTNL (hex_dcc_global_max_get_cps);
}
static int
setup_dcc_speed_multiplier (GtkComboBox *combo)
{
return gtk_combo_box_get_active (combo) == 1 ? 1024 * 1024 : 1024;
}
static void
setup_dcc_speed_spin_range (setup_dcc_speed_data *data)
{
int max = data->set->extra / setup_dcc_speed_multiplier (data->unit);
gtk_spin_button_set_range (data->spin, 0, max > 0 ? max : 0);
}
static void
setup_dcc_speed_store (setup_dcc_speed_data *data)
{
int value = gtk_spin_button_get_value_as_int (data->spin);
int speed = value * setup_dcc_speed_multiplier (data->unit);
if (speed > data->set->extra)
speed = data->set->extra;
setup_set_int (&setup_prefs, data->set, speed);
}
static void
setup_dcc_speed_spin_cb (GtkSpinButton *spin, setup_dcc_speed_data *data)
{
(void)spin;
setup_dcc_speed_store (data);
}
static void
setup_dcc_speed_unit_cb (GtkComboBox *combo, setup_dcc_speed_data *data)
{
int speed = setup_get_int (&setup_prefs, data->set);
int multiplier;
int value;
(void)combo;
setup_dcc_speed_spin_range (data);
multiplier = setup_dcc_speed_multiplier (data->unit);
value = (speed + (multiplier / 2)) / multiplier;
gtk_spin_button_set_value (data->spin, value);
setup_dcc_speed_store (data);
}
static void static void
setup_spin_cb (GtkSpinButton *spin, const setting *set) setup_spin_cb (GtkSpinButton *spin, const setting *set)
{ {
@@ -902,11 +963,43 @@ setup_create_spin (GtkWidget *table, int row, const setting *set)
g_object_set_data (G_OBJECT (wid), "lbl", label); g_object_set_data (G_OBJECT (wid), "lbl", label);
if (set->tooltip) if (set->tooltip)
gtk_widget_set_tooltip_text (wid, _(set->tooltip)); gtk_widget_set_tooltip_text (wid, _(set->tooltip));
if (setup_is_dcc_speed_setting (set))
{
GtkWidget *unit;
setup_dcc_speed_data *data = g_new0 (setup_dcc_speed_data, 1);
int speed = setup_get_int (&setup_prefs, set);
int use_mib = speed >= (1024 * 1024) && speed % (1024 * 1024) == 0;
int multiplier;
data->set = set;
data->spin = GTK_SPIN_BUTTON (wid);
unit = gtk_combo_box_text_new ();
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (unit), _("KiB/s"));
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (unit), _("MiB/s"));
gtk_combo_box_set_wrap_width (GTK_COMBO_BOX (unit), 1);
gtk_combo_box_set_active (GTK_COMBO_BOX (unit), use_mib ? 1 : 0);
data->unit = GTK_COMBO_BOX (unit);
setup_dcc_speed_spin_range (data);
multiplier = setup_dcc_speed_multiplier (data->unit);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (wid), (speed + (multiplier / 2)) / multiplier);
g_signal_connect (G_OBJECT (wid), "value-changed",
G_CALLBACK (setup_dcc_speed_spin_cb), data);
g_signal_connect (G_OBJECT (unit), "changed",
G_CALLBACK (setup_dcc_speed_unit_cb), data);
gtk_box_pack_start (GTK_BOX (rbox), wid, 0, 0, 0);
gtk_box_pack_start (GTK_BOX (rbox), unit, 0, 0, 6);
} else
{
gtk_spin_button_set_value (GTK_SPIN_BUTTON (wid), gtk_spin_button_set_value (GTK_SPIN_BUTTON (wid),
setup_get_int (&setup_prefs, set)); setup_get_int (&setup_prefs, set));
g_signal_connect (G_OBJECT (wid), "value-changed", g_signal_connect (G_OBJECT (wid), "value-changed",
G_CALLBACK (setup_spin_cb), (gpointer)set); G_CALLBACK (setup_spin_cb), (gpointer)set);
gtk_box_pack_start (GTK_BOX (rbox), wid, 0, 0, 0); gtk_box_pack_start (GTK_BOX (rbox), wid, 0, 0, 0);
}
if (set->list) if (set->list)
{ {
+2 -2
View File
@@ -34,9 +34,9 @@ static const char *theme_css_selector_light_class = "zoitechat-light";
static const char *theme_css_palette_provider_key = "zoitechat-palette-provider"; static const char *theme_css_palette_provider_key = "zoitechat-palette-provider";
static const guint theme_css_provider_priority = GTK_STYLE_PROVIDER_PRIORITY_USER; static const guint theme_css_provider_priority = GTK_STYLE_PROVIDER_PRIORITY_USER;
static const char *theme_css_palette_scope_selectors = static const char *theme_css_palette_scope_selectors =
".zoitechat-palette, .zoitechat-palette *, .zoitechat-palette box, .zoitechat-palette grid, .zoitechat-palette stack, .zoitechat-palette frame, .zoitechat-palette paned, .zoitechat-palette paned > separator, .zoitechat-palette separator, .zoitechat-palette viewport, .zoitechat-palette overlay, .zoitechat-palette revealer, .zoitechat-palette notebook, .zoitechat-palette notebook > header, .zoitechat-palette notebook > header > tabs, .zoitechat-palette notebook > header > tabs > tab, .zoitechat-palette scrolledwindow, .zoitechat-palette scrollbar, .zoitechat-palette scrollbar slider, .zoitechat-palette scrollbar trough, .zoitechat-palette treeview, .zoitechat-palette treeview.view, .zoitechat-palette treeview.view text, .zoitechat-palette treeview.view cell, .zoitechat-palette treeview.view row, .zoitechat-palette treeview header, .zoitechat-palette treeview header button, .zoitechat-palette list, .zoitechat-palette list row, .zoitechat-palette row, .zoitechat-palette textview, .zoitechat-palette textview text, .zoitechat-palette text, .zoitechat-palette entry, .zoitechat-palette entry text, .zoitechat-palette button, .zoitechat-palette button label, .zoitechat-palette check, .zoitechat-palette radio, .zoitechat-palette switch, .zoitechat-palette slider, .zoitechat-palette scale, .zoitechat-palette scale trough, .zoitechat-palette scale highlight, .zoitechat-palette spinbutton, .zoitechat-palette combobox, .zoitechat-palette combobox box, .zoitechat-palette progressbar, .zoitechat-palette progressbar trough, .zoitechat-palette levelbar, .zoitechat-palette levelbar trough, .zoitechat-palette menubar, .zoitechat-palette menu, .zoitechat-palette menuitem, .zoitechat-palette menuitem label, .zoitechat-palette toolbar, .zoitechat-palette headerbar, .zoitechat-palette label, .zoitechat-palette link, .zoitechat-palette infobar, .zoitechat-palette statusbar, .zoitechat-palette statusbar frame, .zoitechat-palette tooltip, .zoitechat-palette tooltip label"; ".zoitechat-palette, .zoitechat-palette *, .zoitechat-palette box, .zoitechat-palette grid, .zoitechat-palette stack, .zoitechat-palette frame, .zoitechat-palette paned, .zoitechat-palette paned > separator, .zoitechat-palette separator, .zoitechat-palette viewport, .zoitechat-palette overlay, .zoitechat-palette revealer, .zoitechat-palette notebook, .zoitechat-palette notebook > header, .zoitechat-palette notebook > header > tabs, .zoitechat-palette notebook > header > tabs > tab, .zoitechat-palette scrolledwindow, .zoitechat-palette scrollbar, .zoitechat-palette scrollbar slider, .zoitechat-palette scrollbar trough, .zoitechat-palette treeview, .zoitechat-palette treeview.view, .zoitechat-palette treeview.view text, .zoitechat-palette treeview.view cell, .zoitechat-palette treeview.view row, .zoitechat-palette treeview header, .zoitechat-palette treeview header button, .zoitechat-palette list, .zoitechat-palette list row, .zoitechat-palette row, .zoitechat-palette textview, .zoitechat-palette textview text, .zoitechat-palette text, .zoitechat-palette entry, .zoitechat-palette entry text, .zoitechat-palette button, .zoitechat-palette button label, .zoitechat-palette check, .zoitechat-palette switch, .zoitechat-palette slider, .zoitechat-palette scale, .zoitechat-palette scale trough, .zoitechat-palette scale highlight, .zoitechat-palette spinbutton, .zoitechat-palette combobox, .zoitechat-palette combobox box, .zoitechat-palette progressbar, .zoitechat-palette progressbar trough, .zoitechat-palette levelbar, .zoitechat-palette levelbar trough, .zoitechat-palette menubar, .zoitechat-palette menu, .zoitechat-palette menuitem, .zoitechat-palette menuitem label, .zoitechat-palette toolbar, .zoitechat-palette headerbar, .zoitechat-palette label, .zoitechat-palette link, .zoitechat-palette infobar, .zoitechat-palette statusbar, .zoitechat-palette statusbar frame, .zoitechat-palette tooltip, .zoitechat-palette tooltip label";
static const char *theme_css_palette_selection_selectors = static const char *theme_css_palette_selection_selectors =
".zoitechat-palette *:selected, .zoitechat-palette *:selected:focus, .zoitechat-palette *:selected:hover, .zoitechat-palette treeview.view:selected, .zoitechat-palette treeview.view:selected:focus, .zoitechat-palette treeview.view:selected:hover, .zoitechat-palette row:selected, .zoitechat-palette row:selected:focus, .zoitechat-palette row:selected:hover, .zoitechat-palette selection, .zoitechat-palette text selection, .zoitechat-palette entry selection, .zoitechat-palette entry text selection, .zoitechat-palette button:selected, .zoitechat-palette button:checked, .zoitechat-palette check:checked, .zoitechat-palette radio:checked, .zoitechat-palette switch:checked, .zoitechat-palette slider:active, .zoitechat-palette menuitem:selected, .zoitechat-palette menuitem:hover, .zoitechat-palette notebook > header > tabs > tab:checked, .zoitechat-palette notebook > header > tabs > tab:hover, .zoitechat-palette treeview header button:hover, .zoitechat-palette treeview header button:active, .zoitechat-palette progressbar progress, .zoitechat-palette levelbar block.filled, .zoitechat-palette:focus selection, .zoitechat-palette:focus text selection"; ".zoitechat-palette *:selected, .zoitechat-palette *:selected:focus, .zoitechat-palette *:selected:hover, .zoitechat-palette treeview.view:selected, .zoitechat-palette treeview.view:selected:focus, .zoitechat-palette treeview.view:selected:hover, .zoitechat-palette row:selected, .zoitechat-palette row:selected:focus, .zoitechat-palette row:selected:hover, .zoitechat-palette selection, .zoitechat-palette text selection, .zoitechat-palette entry selection, .zoitechat-palette entry text selection, .zoitechat-palette button:selected, .zoitechat-palette button:checked, .zoitechat-palette check:checked, .zoitechat-palette switch:checked, .zoitechat-palette slider:active, .zoitechat-palette menuitem:selected, .zoitechat-palette menuitem:hover, .zoitechat-palette notebook > header > tabs > tab:checked, .zoitechat-palette notebook > header > tabs > tab:hover, .zoitechat-palette treeview header button:hover, .zoitechat-palette treeview header button:active, .zoitechat-palette progressbar progress, .zoitechat-palette levelbar block.filled, .zoitechat-palette:focus selection, .zoitechat-palette:focus text selection";
typedef struct typedef struct
{ {
+1 -1
View File
@@ -1 +1 @@
2.18.0~pre6 2.18.0