17 Commits

Author SHA1 Message Date
58208b81f2 Fix away tracking
(cherry picked from commit 87410aea50)
2026-09-15 13:04:10 -06:00
e7631701ce release: prepare 2.19.1 2026-09-15 09:28:29 -06:00
b5c3be8ff1 defer channel tree scrolling until realized
(cherry picked from commit e94ffd9d79)
2026-09-15 09:12:34 -06:00
2b9a39783b fix theme service tests
(cherry picked from commit ff4217c3d1)
2026-09-15 09:12:30 -06:00
Christopher Byrne
ecdb462ff8 meson.build: Reflect usage of 0.59 Meson features
src/fe-gtk/meson.build calls feature_opt.allowed() which wasn't
added until 0.59.

Signed-off-by: Christopher Byrne <salah.coronya@gmail.com>
(cherry picked from commit 5018a3a848)
2026-09-15 09:12:25 -06:00
Christopher Byrne
78eb1882cb data/misc/meson.build: Fix referencing possibly undefined variable "appstreamcli"
If meson is passed -Dinstall-plugin-metainfo=false, the "appstreamcli"
will not be defined, but it is later referenced in global scope, which
causes and "undefined variable" error in Meson

Signed-off-by: Christopher Byrne <salah.coronya@gmail.com>
(cherry picked from commit df1c74a91d)
2026-09-15 09:12:21 -06:00
6c95db8539 Fix channel ACTION routing after self-message handling
(cherry picked from commit bb3893d36c)
2026-09-15 09:12:16 -06:00
ThePeGaSuS
75286642df Fix CTCP ACTION not rerouting self-sent /me to correct PM window
Mirrors the PRIVMSG fix: replayed /me messages sent by our own nick
via WeeChat relay backlog were always passed with fromme=FALSE,
so they never got rerouted to the actual PM query window.

(cherry picked from commit c725adaa09)
2026-09-15 09:12:13 -06:00
ThePeGaSuS
8044b8562d Fix: private messages split into two windows over WeeChat's IRC relay
When you send a private message, ZoiteChat sometimes gets the same
message echoed back by the server so it can show it in the right
window. Whether it recognizes that echo depended on the server first
confirming a feature called "echo-message" during connection setup.

WeeChat's relay doesn't seem to confirm that feature the way other
servers (or ZNC) do, so ZoiteChat didn't recognize its own echoed
messages and treated them as brand new incoming messages from
yourself, opening a second, separate conversation window instead of
using the one you were already typing in.

This makes ZoiteChat recognize its own message by checking who sent
it, instead of only trusting that feature confirmation. That way,
sent and received messages always end up in the same conversation
window, regardless of how well the server/relay announces its
capabilities.

(cherry picked from commit 0ba523d071)
2026-09-15 09:12:09 -06:00
de6e16cbdf fix startup error on flatpak
(cherry picked from commit 36f0d7450c)
2026-09-15 09:12:02 -06:00
909309cc2e WIN32: fix installer theme download URL. 2026-08-15 12:49:58 -06:00
deepend-tildeclub
73d958911f Merge pull request #364 from ZoiteChat/master
run Ci for release branches
2026-08-15 12:10:29 -06:00
6b4a2b5406 fix unmark away option 2026-08-15 12:07:41 -06:00
cd8d1c9b10 Run Ci on Release/version branches on commit 2026-08-04 12:11:30 -06:00
deepend-tildeclub
a79fedda77 Merge pull request #360 from ZoiteChat/release/2.19
fix duplicate /msg output + Escaping of the intial slash
2026-08-04 12:10:53 -06:00
558ef7fbdf fix Escaping of the intial slash 2026-08-04 11:58:30 -06:00
7c6609a414 fix duplicate /msg output 2026-08-04 11:35:48 -06:00
15 changed files with 68 additions and 37 deletions

View File

@@ -2,7 +2,7 @@ name: AppImage Build
on:
push:
branches: [master]
branches: [master, 'release/**']
pull_request:
branches: [master]

View File

@@ -2,7 +2,7 @@ name: Flatpak Build
on:
push:
branches: [master]
branches: [master, 'release/**']
pull_request:
branches: [master]

View File

@@ -4,6 +4,7 @@ on:
push:
branches:
- master
- 'release/**'
pull_request:
branches:
- master

View File

@@ -1 +1 @@
2.19.0
2.19.1

View File

@@ -2,6 +2,7 @@ appdir = join_paths(get_option('datadir'), 'applications')
metainfodir = join_paths(get_option('datadir'), 'metainfo')
mimedir = join_paths(get_option('datadir'), 'mime', 'packages')
desktop_utils = find_program('desktop-file-validate', required: false)
appstreamcli = find_program('appstreamcli', required: false)
if get_option('gtk-frontend')
if get_option('install-appdata')
@@ -13,7 +14,6 @@ if get_option('gtk-frontend')
install_dir: metainfodir
)
appstreamcli = find_program('appstreamcli', required: false)
if appstreamcli.found()
test('Validate net.zoite.Zoitechat.appdata.xml', appstreamcli,
args: ['validate', zoitechat_appdata]

View File

@@ -1,6 +1,6 @@
project('zoitechat', 'c',
version: run_command('cat', 'VERSION', check: true).stdout().strip(),
meson_version: '>= 0.55.0',
meson_version: '>= 0.59.0',
default_options: [
'c_std=c17',
'buildtype=debugoptimized',

View File

@@ -126,7 +126,21 @@ ctcp_handle (session *sess, char *to, char *nick, char *ip,
if (ctcp_check (sess, nick, word, word_eol, word[4] + ctcp_offset))
goto generic;
inbound_action (sess, to, nick, ip, msg + 7, FALSE, tags_data->identified, tags_data);
{
gboolean private_fromme = !serv->p_cmp (nick, serv->nick) && !is_channel (serv, to);
if (private_fromme)
{
session *target = find_dialog (serv, to);
if (target)
sess = target;
else if (serv->front_session)
sess = serv->front_session;
}
inbound_action (sess, to, nick, ip, msg + 7, private_fromme, tags_data->identified, tags_data);
}
return;
}

View File

@@ -13,9 +13,9 @@ dbus_includes = [
dbus_service_dir = join_paths(get_option('datadir'), 'dbus-1/services')
if get_option('dbus-service-use-appid')
dbus_service_name = 'io.github.Hexchat'
dbus_output_file = 'io.github.Hexchat.service'
dbus_cargs = '-DDBUS_SERVICE="io.github.Hexchat"'
dbus_service_name = 'net.zoite.Zoitechat'
dbus_output_file = 'net.zoite.Zoitechat.service'
dbus_cargs = '-DDBUS_SERVICE="net.zoite.Zoitechat"'
else
dbus_service_name = 'org.zoitechat.service'
dbus_output_file = 'org.zoitechat.service.service'

View File

@@ -858,8 +858,10 @@ path_depth_from_root (const char *base, const char *path)
static gint
theme_root_candidate_compare (gconstpointer a, gconstpointer b)
{
const ThemeRootCandidate *ca = a;
const ThemeRootCandidate *cb = b;
/* g_ptr_array_sort() passes pointers to the array slots, not the values
* stored in those slots. Dereference once before comparing candidates. */
const ThemeRootCandidate *ca = *(ThemeRootCandidate * const *) a;
const ThemeRootCandidate *cb = *(ThemeRootCandidate * const *) b;
if (ca->has_index_theme != cb->has_index_theme)
return ca->has_index_theme ? -1 : 1;
if (ca->depth != cb->depth)

View File

@@ -675,7 +675,8 @@ inbound_chanmsg (server *serv, session *sess, char *chan, char *from,
if (fromme)
{
if (prefs.hex_away_auto_unmark && serv->is_away && !tags_data->timestamp)
if (prefs.hex_away_auto_unmark && serv->is_away &&
(!tags_data->timestamp || serv->have_echo_message))
sess->server->p_set_back (sess->server);
reply_context_print (sess, tags_data);
EMIT_SIGNAL_TIMESTAMP (XP_TE_UCHANMSG, sess, from, text, nickchar, NULL,

View File

@@ -3025,7 +3025,7 @@ cmd_msg (struct session *sess, char *tbuf, char *word[], char *word_eol[])
newsess->server->nick, msg + offset, TRUE, FALSE,
&no_tags);
}
else
else if (!sess->server->have_echo_message)
{
/* mask out passwords */
if (g_ascii_strcasecmp (nick, "nickserv") == 0)
@@ -5058,6 +5058,11 @@ handle_user_input (session *sess, char *text, int history, int nocommand)
handle_say (sess, text, TRUE);
return 1;
}
if (text[0] == cmd_char && text[1] == cmd_char)
{
handle_say (sess, text + 1, TRUE);
return 1;
}
for (i = 1; text[i]; i++)
{

View File

@@ -1368,7 +1368,7 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
{
if (ignore_check (word[1], IG_PRIV))
return;
if (serv->have_echo_message && !serv->p_cmp (nick, serv->nick))
if (!serv->p_cmp (nick, serv->nick))
{
session *target_sess = find_dialog (serv, to);

View File

@@ -463,8 +463,7 @@ doover:
while (list)
{
sess = list->data;
if (!sess->server->have_awaynotify)
sess->done_away_check = FALSE;
sess->done_away_check = FALSE;
list = list->next;
}
loop++;

View File

@@ -301,26 +301,35 @@ cv_tree_focus (chan *ch)
path = gtk_tree_model_get_path (model, &ch->iter);
if (path)
{
/* This full section does what
* gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0.5);
* does, except it only scrolls the window if the provided cell is
* not visible. Basic algorithm taken from gtktreeview.c */
/* obtain information to see if the cell is visible */
gtk_tree_view_get_background_area (tree, path, NULL, &cell_rect);
gtk_tree_view_get_visible_rect (tree, &vis_rect);
/* The cordinates aren't offset correctly */
gtk_tree_view_convert_widget_to_bin_window_coords ( tree, cell_rect.x, cell_rect.y, NULL, &cell_rect.y );
/* only need to scroll if out of bounds */
if (cell_rect.y < vis_rect.y ||
cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
if (!gtk_widget_get_realized (GTK_WIDGET (tree)))
{
dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * 0.5);
if (dest_y < 0)
dest_y = 0;
gtk_tree_view_scroll_to_point (tree, -1, dest_y);
/* Layout changes can restore focus before the new tree is realized.
* Let GTK track the row and scroll once its geometry is available. */
gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0.5);
}
else
{
/* This full section does what
* gtk_tree_view_scroll_to_cell (tree, path, NULL, TRUE, 0.5, 0.5);
* does, except it only scrolls the window if the provided cell is
* not visible. Basic algorithm taken from gtktreeview.c */
/* obtain information to see if the cell is visible */
gtk_tree_view_get_background_area (tree, path, NULL, &cell_rect);
gtk_tree_view_get_visible_rect (tree, &vis_rect);
/* The cordinates aren't offset correctly */
gtk_tree_view_convert_widget_to_bin_window_coords ( tree, cell_rect.x, cell_rect.y, NULL, &cell_rect.y );
/* only need to scroll if out of bounds */
if (cell_rect.y < vis_rect.y ||
cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
{
dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * 0.5);
if (dest_y < 0)
dest_y = 0;
gtk_tree_view_scroll_to_point (tree, -1, dest_y);
}
}
/* theft done, now make it focused like */
gtk_tree_view_set_cursor (tree, path, NULL, FALSE);

View File

@@ -373,10 +373,10 @@ begin
idpClearFiles;
if WizardIsComponentSelected('themes\windows10') then
idpAddFile('https://dl.zoitechat.zoite.net/themes/GTK3Themes/Windows-10-3.2.1.zip', ExpandConstant('{tmp}\Windows-10-3.2.1.zip'));
idpAddFile('https://dl.zoitechat.org/themes/GTK3Themes/Windows-10-3.2.1.zip', ExpandConstant('{tmp}\Windows-10-3.2.1.zip'));
if WizardIsComponentSelected('themes\windows10dark') then
idpAddFile('https://dl.zoitechat.zoite.net/themes/GTK3Themes/Windows-10-Dark-3.2.1-dark.zip', ExpandConstant('{tmp}\Windows-10-Dark-3.2.1-dark.zip'));
idpAddFile('https://dl.zoitechat.org/themes/GTK3Themes/Windows-10-Dark-3.2.1-dark.zip', ExpandConstant('{tmp}\Windows-10-Dark-3.2.1-dark.zip'));
if not WizardIsTaskSelected('portable') then
begin