7 Commits

Author SHA1 Message Date
51e9ac15df fix zoitechat.svg 2026-04-01 00:21:44 -06:00
deepend-tildeclub
4df579e0d3 Merge pull request #185 from ZoiteChat/improve-appimage-URI-folder-opening
Sanitize Linux open env for AppImage, add safer fallbacks
2026-04-01 00:15:53 -06:00
2cf69d2e67 Sanitize Linux open env for AppImage, add safer fallbacks 2026-03-31 23:26:40 -06:00
deepend-tildeclub
64bffd0dc8 Merge pull request #184 from ZoiteChat/add-gtk3-themes-windows-installer
Theme: Adding themes users can select at install time.
2026-03-31 19:38:40 -06:00
deepend-tildeclub
b451240dfd Merge pull request #181 from ZoiteChat/prefs-option-disable-tab-close-button
Add pref for tab close buttons
2026-03-31 19:30:26 -06:00
41cc1f617f Theme: Adding themes users can select at install time. 2026-03-31 19:28:45 -06:00
ed671eac25 Add pref for tab close buttons 2026-03-31 18:10:28 -06:00
7 changed files with 142 additions and 43 deletions

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -445,6 +445,7 @@ const struct prefs vars[] =
{"gui_dark_mode", P_OFFINT (hex_gui_dark_mode), TYPE_INT}, {"gui_dark_mode", P_OFFINT (hex_gui_dark_mode), TYPE_INT},
{"gui_gtk3_variant", P_OFFINT (hex_gui_gtk3_variant), TYPE_INT}, {"gui_gtk3_variant", P_OFFINT (hex_gui_gtk3_variant), TYPE_INT},
{"gui_tab_layout", P_OFFINT (hex_gui_tab_layout), TYPE_INT}, {"gui_tab_layout", P_OFFINT (hex_gui_tab_layout), TYPE_INT},
{"gui_tab_closebuttons", P_OFFINT (hex_gui_tab_closebuttons), TYPE_BOOL},
{"gui_tab_middleclose", P_OFFINT (hex_gui_tab_middleclose), TYPE_BOOL}, {"gui_tab_middleclose", P_OFFINT (hex_gui_tab_middleclose), TYPE_BOOL},
{"gui_tab_newtofront", P_OFFINT (hex_gui_tab_newtofront), TYPE_INT}, {"gui_tab_newtofront", P_OFFINT (hex_gui_tab_newtofront), TYPE_INT},
{"gui_tab_pos", P_OFFINT (hex_gui_tab_pos), TYPE_INT}, {"gui_tab_pos", P_OFFINT (hex_gui_tab_pos), TYPE_INT},
@@ -777,6 +778,7 @@ load_default_config(void)
prefs.hex_gui_tab_chans = 1; prefs.hex_gui_tab_chans = 1;
prefs.hex_gui_tab_dialogs = 1; prefs.hex_gui_tab_dialogs = 1;
prefs.hex_gui_tab_icons = 1; prefs.hex_gui_tab_icons = 1;
prefs.hex_gui_tab_closebuttons = 1;
prefs.hex_gui_tab_middleclose = 1; prefs.hex_gui_tab_middleclose = 1;
prefs.hex_gui_tab_server = 1; prefs.hex_gui_tab_server = 1;
prefs.hex_gui_tab_sort = 1; prefs.hex_gui_tab_sort = 1;

View File

@@ -265,6 +265,7 @@ struct zoitechatprefs
int hex_gui_search_pos; int hex_gui_search_pos;
int hex_gui_slist_select; int hex_gui_slist_select;
int hex_gui_tab_layout; int hex_gui_tab_layout;
int hex_gui_tab_closebuttons;
int hex_gui_tab_middleclose; int hex_gui_tab_middleclose;
int hex_gui_tab_newtofront; int hex_gui_tab_newtofront;
int hex_gui_tab_pos; int hex_gui_tab_pos;

View File

@@ -653,7 +653,7 @@ tab_click_cb (GtkWidget *wid, GdkEventButton *event, chan *ch)
if (event->button == 1 && event->type == GDK_BUTTON_PRESS) if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
{ {
close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button"); close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button");
if (close_button && if (prefs.hex_gui_tab_closebuttons && close_button &&
gtk_widget_translate_coordinates (close_button, wid, 0, 0, &close_x, &close_y)) gtk_widget_translate_coordinates (close_button, wid, 0, 0, &close_x, &close_y))
{ {
gtk_widget_get_allocation (close_button, &close_alloc); gtk_widget_get_allocation (close_button, &close_alloc);
@@ -679,7 +679,7 @@ tab_close_motion_cb (GtkWidget *wid, GdkEventMotion *event, chan *ch)
gboolean hover = FALSE; gboolean hover = FALSE;
close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button"); close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button");
if (close_button && if (prefs.hex_gui_tab_closebuttons && close_button &&
gtk_widget_translate_coordinates (close_button, wid, 0, 0, &close_x, &close_y)) gtk_widget_translate_coordinates (close_button, wid, 0, 0, &close_x, &close_y))
{ {
gtk_widget_get_allocation (close_button, &close_alloc); gtk_widget_get_allocation (close_button, &close_alloc);
@@ -714,7 +714,7 @@ tab_close_leave_cb (GtkWidget *wid, GdkEventCrossing *event, chan *ch)
GtkWidget *close_button; GtkWidget *close_button;
close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button"); close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button");
if (close_button) if (prefs.hex_gui_tab_closebuttons && close_button)
gtk_widget_unset_state_flags (close_button, GTK_STATE_FLAG_PRELIGHT); gtk_widget_unset_state_flags (close_button, GTK_STATE_FLAG_PRELIGHT);
if (gtk_widget_get_window (wid)) if (gtk_widget_get_window (wid))
gdk_window_set_cursor (gtk_widget_get_window (wid), NULL); gdk_window_set_cursor (gtk_widget_get_window (wid), NULL);
@@ -780,6 +780,8 @@ cv_tabs_add (chanview *cv, chan *ch, char *name, GtkTreeIter *parent)
G_CALLBACK (tab_toggled_cb), ch); G_CALLBACK (tab_toggled_cb), ch);
g_object_set_data (G_OBJECT (but), "u", ch->userdata); g_object_set_data (G_OBJECT (but), "u", ch->userdata);
gtk_widget_show_all (hbox); gtk_widget_show_all (hbox);
if (!prefs.hex_gui_tab_closebuttons)
gtk_widget_hide (close_button);
tab_add_real (cv, but, ch); tab_add_real (cv, but, ch);

View File

@@ -1308,17 +1308,38 @@ maybe_escape_uri (const char *uri)
return g_strdup (uri); return g_strdup (uri);
} }
#ifndef WIN32
static gchar **
fe_open_url_env_sanitized (void)
{
gchar **env = g_get_environ ();
const char *vars[] = {"LD_LIBRARY_PATH", "LD_PRELOAD", "APPDIR", "APPIMAGE", "ARGV0", NULL};
int i;
for (i = 0; vars[i]; i++)
{
gchar **tmp_env = env;
env = g_environ_unsetenv (tmp_env, vars[i]);
if (env != tmp_env)
g_strfreev (tmp_env);
}
return env;
}
#endif
static void static void
fe_open_url_inner (const char *url) fe_open_url_inner (const char *url)
{ {
GError *error = NULL; GError *error = NULL;
char *escaped_url = maybe_escape_uri (url); char *escaped_url = maybe_escape_uri (url);
gboolean opened = g_app_info_launch_default_for_uri (escaped_url, NULL, &error); gboolean opened = FALSE;
#ifdef WIN32
opened = g_app_info_launch_default_for_uri (escaped_url, NULL, &error);
if (!opened) if (!opened)
{ {
g_clear_error (&error); g_clear_error (&error);
#ifdef WIN32
gunichar2 *url_utf16 = g_utf8_to_utf16 (escaped_url, -1, NULL, NULL, NULL); gunichar2 *url_utf16 = g_utf8_to_utf16 (escaped_url, -1, NULL, NULL, NULL);
if (url_utf16 != NULL) if (url_utf16 != NULL)
@@ -1326,22 +1347,11 @@ fe_open_url_inner (const char *url)
opened = ((INT_PTR) ShellExecuteW (0, L"open", url_utf16, NULL, NULL, SW_SHOWNORMAL)) > 32; opened = ((INT_PTR) ShellExecuteW (0, L"open", url_utf16, NULL, NULL, SW_SHOWNORMAL)) > 32;
g_free (url_utf16); g_free (url_utf16);
} }
}
#else #else
{
gchar *xdg_open_argv[] = {(gchar *) "xdg-open", escaped_url, NULL}; gchar *xdg_open_argv[] = {(gchar *) "xdg-open", escaped_url, NULL};
gchar **spawn_env = NULL; gchar **spawn_env = fe_open_url_env_sanitized ();
spawn_env = g_get_environ ();
{
gchar **tmp_env = spawn_env;
spawn_env = g_environ_unsetenv (tmp_env, "LD_LIBRARY_PATH");
if (spawn_env != tmp_env)
g_strfreev (tmp_env);
tmp_env = spawn_env;
spawn_env = g_environ_unsetenv (tmp_env, "LD_PRELOAD");
if (spawn_env != tmp_env)
g_strfreev (tmp_env);
}
if (g_spawn_async (NULL, xdg_open_argv, spawn_env, if (g_spawn_async (NULL, xdg_open_argv, spawn_env,
G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
@@ -1354,19 +1364,26 @@ fe_open_url_inner (const char *url)
g_clear_error (&error); g_clear_error (&error);
} }
if (!opened && gtk_show_uri_on_window (NULL, escaped_url, GDK_CURRENT_TIME, &error))
{
opened = TRUE;
}
else if (!opened)
{
g_clear_error (&error);
}
g_strfreev (spawn_env); g_strfreev (spawn_env);
#endif
} }
if (!opened)
{
opened = g_app_info_launch_default_for_uri (escaped_url, NULL, &error);
if (!opened)
g_clear_error (&error);
}
if (!opened && gtk_show_uri_on_window (NULL, escaped_url, GDK_CURRENT_TIME, &error))
{
opened = TRUE;
}
else if (!opened)
{
g_clear_error (&error);
}
#endif
if (!opened) if (!opened)
{ {
g_warning ("Unable to open URL '%s' using system default application", escaped_url); g_warning ("Unable to open URL '%s' using system default application", escaped_url);

View File

@@ -330,6 +330,7 @@ static const setting tabs_settings[] =
{ST_TOGGLE, N_("Show icons in the channel tree"), P_OFFINTNL(hex_gui_tab_icons), 0, 0, 0}, {ST_TOGGLE, N_("Show icons in the channel tree"), P_OFFINTNL(hex_gui_tab_icons), 0, 0, 0},
{ST_TOGGLE, N_("Show dotted lines in the channel tree"), P_OFFINTNL(hex_gui_tab_dots), 0, 0, 0}, {ST_TOGGLE, N_("Show dotted lines in the channel tree"), P_OFFINTNL(hex_gui_tab_dots), 0, 0, 0},
{ST_TOGGLE, N_("Scroll mouse-wheel to change tabs"), P_OFFINTNL (hex_gui_tab_scrollchans), 0, 0, 0}, {ST_TOGGLE, N_("Scroll mouse-wheel to change tabs"), P_OFFINTNL (hex_gui_tab_scrollchans), 0, 0, 0},
{ST_TOGGLE, N_("Show close button on tabs"), P_OFFINTNL(hex_gui_tab_closebuttons), 0, 0, 0},
{ST_TOGGLE, N_("Middle click to close tab"), P_OFFINTNL(hex_gui_tab_middleclose), 0, 0, 0}, {ST_TOGGLE, N_("Middle click to close tab"), P_OFFINTNL(hex_gui_tab_middleclose), 0, 0, 0},
{ST_TOGGLE, N_("Smaller text"), P_OFFINTNL(hex_gui_tab_small), 0, 0, 0}, {ST_TOGGLE, N_("Smaller text"), P_OFFINTNL(hex_gui_tab_small), 0, 0, 0},
{ST_MENU, N_("Focus new tabs:"), P_OFFINTNL(hex_gui_tab_newtofront), 0, focusnewtabsmenu, 0}, {ST_MENU, N_("Focus new tabs:"), P_OFFINTNL(hex_gui_tab_newtofront), 0, focusnewtabsmenu, 0},
@@ -2186,6 +2187,8 @@ setup_apply (struct zoitechatprefs *pr)
noapply = TRUE; noapply = TRUE;
if (DIFF (hex_gui_tab_icons)) if (DIFF (hex_gui_tab_icons))
noapply = TRUE; noapply = TRUE;
if (DIFF (hex_gui_tab_closebuttons))
noapply = TRUE;
if (DIFF (hex_gui_tab_server)) if (DIFF (hex_gui_tab_server))
noapply = TRUE; noapply = TRUE;
if (DIFF (hex_gui_tab_small)) if (DIFF (hex_gui_tab_small))

View File

@@ -61,6 +61,9 @@ Name: "langs"; Description: "Language Interfaces"; Types: custom; Flags: disable
Name: "langs\lua"; Description: "Lua"; Types: normal custom; Flags: disablenouninstallwarning Name: "langs\lua"; Description: "Lua"; Types: normal custom; Flags: disablenouninstallwarning
Name: "langs\perl"; Description: "Perl (requires Perl 5.42)"; Types: custom; Flags: disablenouninstallwarning Name: "langs\perl"; Description: "Perl (requires Perl 5.42)"; Types: custom; Flags: disablenouninstallwarning
Name: "langs\python"; Description: "Python (requires Python 3.14.3)"; Types: custom; Flags: disablenouninstallwarning Name: "langs\python"; Description: "Python (requires Python 3.14.3)"; Types: custom; Flags: disablenouninstallwarning
Name: "themes"; Description: "GTK3 Themes"; Types: normal minimal custom; Flags: disablenouninstallwarning
Name: "themes\windows10"; Description: "Windows 10"; Types: normal minimal custom; Flags: disablenouninstallwarning
Name: "themes\windows10dark"; Description: "Windows 10 Dark"; Types: normal minimal custom; Flags: disablenouninstallwarning
Name: "deps"; Description: "Dependencies"; Types: custom; Flags: disablenouninstallwarning Name: "deps"; Description: "Dependencies"; Types: custom; Flags: disablenouninstallwarning
Name: "deps\vcredist2015"; Description: "Visual C++ Redistributable 2015"; Types: normal minimal custom; Flags: disablenouninstallwarning Name: "deps\vcredist2015"; Description: "Visual C++ Redistributable 2015"; Types: normal minimal custom; Flags: disablenouninstallwarning
@@ -88,6 +91,11 @@ Filename: "{tmp}\perl.msi"; StatusMsg: "Installing Perl"; Components: langs\perl
Filename: "{tmp}\python.msi"; StatusMsg: "Installing Python"; Components: langs\python; Flags: shellexec skipifdoesntexist; Tasks: not portable Filename: "{tmp}\python.msi"; StatusMsg: "Installing Python"; Components: langs\python; Flags: shellexec skipifdoesntexist; Tasks: not portable
Filename: "{tmp}\python.exe"; Parameters: "InstallAllUsers=1 PrependPath=1"; StatusMsg: "Installing Python"; Components: langs\python; Flags: shellexec skipifdoesntexist; Tasks: not portable Filename: "{tmp}\python.exe"; Parameters: "InstallAllUsers=1 PrependPath=1"; StatusMsg: "Installing Python"; Components: langs\python; Flags: shellexec skipifdoesntexist; Tasks: not portable
Filename: "{tmp}\spelling-dicts.exe"; Parameters: "/verysilent"; StatusMsg: "Installing Spelling Dictionaries"; Components: spell; Flags: skipifdoesntexist; Tasks: not portable Filename: "{tmp}\spelling-dicts.exe"; Parameters: "/verysilent"; StatusMsg: "Installing Spelling Dictionaries"; Components: spell; Flags: skipifdoesntexist; Tasks: not portable
Filename: "{sys}\WindowsPowerShell\v1.0\powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -Command ""Expand-Archive -LiteralPath '{tmp}\Windows-10-3.2.1.zip' -DestinationPath '{userappdata}\ZoiteChat\gtk3-themes' -Force"""; StatusMsg: "Installing GTK3 Theme: Windows 10"; Components: themes\windows10; Flags: runhidden waituntilterminated skipifdoesntexist
Filename: "{sys}\WindowsPowerShell\v1.0\powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -Command ""Expand-Archive -LiteralPath '{tmp}\Windows-10-Dark-3.2.1-dark.zip' -DestinationPath '{userappdata}\ZoiteChat\gtk3-themes' -Force"""; StatusMsg: "Installing GTK3 Theme: Windows 10 Dark"; Components: themes\windows10dark; Flags: runhidden waituntilterminated skipifdoesntexist
[Dirs]
Name: "{userappdata}\ZoiteChat\gtk3-themes"; Components: themes
[Files] [Files]
Source: "portable-mode"; DestDir: "{app}"; Tasks: portable Source: "portable-mode"; DestDir: "{app}"; Tasks: portable
@@ -196,6 +204,10 @@ Name: "{commonappdata}\Microsoft\Internet Explorer\Quick Launch\ZoiteChat"; File
[Messages] [Messages]
BeveledLabel= {#APPNAM} BeveledLabel= {#APPNAM}
[UninstallDelete]
Type: filesandordirs; Name: "{userappdata}\ZoiteChat\gtk3-themes\Windows-10-3.2.1"; Components: themes\windows10
Type: filesandordirs; Name: "{userappdata}\ZoiteChat\gtk3-themes\Windows-10-Dark-3.2.1-dark"; Components: themes\windows10dark
[Code] [Code]
#ifndef USE_INNO_DOWNLOAD_PLUGIN #ifndef USE_INNO_DOWNLOAD_PLUGIN
var var
@@ -336,6 +348,12 @@ begin
begin begin
idpClearFiles; idpClearFiles;
if IsComponentSelected('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'));
if IsComponentSelected('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'));
if not IsTaskSelected('portable') then if not IsTaskSelected('portable') then
begin begin
@@ -389,12 +407,28 @@ begin
end; end;
if CurPageID = wpReady then if CurPageID = wpReady then
begin
if IsComponentSelected('themes\windows10') and not FileExists(ExpandConstant('{tmp}\Windows-10-3.2.1.zip')) then
begin
MsgBox('Windows 10 GTK3 theme could not be downloaded. Please retry setup and rerun setup.', mbError, MB_OK);
Result := False;
Exit;
end;
if IsComponentSelected('themes\windows10dark') and not FileExists(ExpandConstant('{tmp}\Windows-10-Dark-3.2.1-dark.zip')) then
begin
MsgBox('Windows 10 Dark GTK3 theme could not be downloaded. Please retry setup and rerun setup.', mbError, MB_OK);
Result := False;
Exit;
end;
if IsComponentSelected('deps\vcredist2015') and not CheckVCInstall() and not FileExists(ExpandConstant('{tmp}\vcredist.exe')) then if IsComponentSelected('deps\vcredist2015') and not CheckVCInstall() and not FileExists(ExpandConstant('{tmp}\vcredist.exe')) then
begin begin
MsgBox('Visual C++ Redistributable could not be downloaded. Please retry setup or install it manually and rerun setup.', mbError, MB_OK); MsgBox('Visual C++ Redistributable could not be downloaded. Please retry setup or install it manually and rerun setup.', mbError, MB_OK);
Result := False; Result := False;
Exit; Exit;
end; end;
end;
end; end;
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////