mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-03-28 08:10:19 +00:00
Compare commits
45 Commits
zoitechat-
...
fix-tray-a
| Author | SHA1 | Date | |
|---|---|---|---|
| baaea45d43 | |||
| 8249be816a | |||
|
|
05f8b4d4b3 | ||
|
|
935c35fd43 | ||
|
|
33b18cb48d | ||
|
|
d9442d6e94 | ||
|
|
b9ac55fe7f | ||
|
|
ca558e7fa2 | ||
|
|
08f367fef0 | ||
|
|
ca5c94f75e | ||
|
|
6f4e5f95a6 | ||
| 2defd0ed42 | |||
| 86aca30744 | |||
|
|
d5f7299a8e | ||
| e73a5d4c8b | |||
|
|
ec18c95d32 | ||
| d9557c7da1 | |||
| fc90fd41be | |||
| ec5e38d1f9 | |||
| 0eb4d08daa | |||
|
|
4b365132ce | ||
| a5ff902ae2 | |||
| bd874540bb | |||
| f6e1af5701 | |||
|
|
e2bfc9b7c9 | ||
|
|
5f3f91bf1c | ||
| 6527c08e4d | |||
| a57104469d | |||
| 94f450ba67 | |||
| b9e4113c81 | |||
| 65707f53b7 | |||
| 21c73e699b | |||
| 63226a7267 | |||
| fb37810367 | |||
|
|
2b66734fa6 | ||
| 380aae139f | |||
|
|
e4e823c4d6 | ||
| d4b16d5866 | |||
| b9cfd9a9f9 | |||
| 664aa150fb | |||
| aead92d9e4 | |||
|
|
7cc5d14045 | ||
| 33fce2af2a | |||
| d26fbb6e89 | |||
| cd93fe3b0e |
@@ -1,6 +1,28 @@
|
|||||||
ZoiteChat ChangeLog
|
ZoiteChat ChangeLog
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
2.18.0~pre5 (2026-03-22)
|
||||||
|
------------------------
|
||||||
|
- Overhauled preferences/config saving: fully staged and transactional, debounced
|
||||||
|
with flush on close, write failures now surfaced.
|
||||||
|
- Overhauled GTK theme handling: live preview, correct colour reset persistence,
|
||||||
|
proper file:// import paths, consistent menubar CSS.
|
||||||
|
- Fixed GTK entry scroll artifact in the input box.
|
||||||
|
- Hardened tray menu lifetime; fixed stale pointer crash on menu destruction.
|
||||||
|
- Fixed AppIndicator tray init for Wayland/source builds; skip redundant X11
|
||||||
|
tray probe for AppIndicator builds.
|
||||||
|
- Split topic/mode rows in channel bar, tighten spacing, persist userlist column widths.
|
||||||
|
- Preserve saved right-pane size on first layout.
|
||||||
|
- Fixed sounds prefs section.
|
||||||
|
- Fixed chanview tree layout and header alignment; tighten topic URL hit-testing.
|
||||||
|
- Dropped realpath() in favour of GLib-only absolute path build.
|
||||||
|
- Made About dialog links explicit; added GPL licence URL.
|
||||||
|
- Added licence headers to new source files.
|
||||||
|
- Windows installer: fixed VC++ redist URL, added non-plugin download fallback,
|
||||||
|
switched to registry-based runtime detection.
|
||||||
|
- Made libayatana-appindicator a required dep in PKGBUILD.
|
||||||
|
- Cleaned up Meson libperl detection.
|
||||||
|
|
||||||
2.18.0~pre4 (2026-03-15)
|
2.18.0~pre4 (2026-03-15)
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,45 @@
|
|||||||
<id>zoitechat.desktop</id>
|
<id>zoitechat.desktop</id>
|
||||||
</provides>
|
</provides>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release date="2026-03-22" version="2.18.0~pre5">
|
||||||
|
<description>
|
||||||
|
<p>Preferences and config saving:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Overhauled preferences/config saving: fully staged and transactional, debounced with flush on close, write failures now surfaced.</li>
|
||||||
|
</ul>
|
||||||
|
<p>GTK theme and UI:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Overhauled GTK theme handling: live preview, correct colour reset persistence, proper <code>file://</code> import paths, consistent menubar CSS.</li>
|
||||||
|
<li>Fixed GTK entry scroll artifact in the input box.</li>
|
||||||
|
<li>Split topic/mode rows in channel bar, tighten spacing, persist userlist column widths.</li>
|
||||||
|
<li>Preserve saved right-pane size on first layout.</li>
|
||||||
|
<li>Fixed sounds prefs section.</li>
|
||||||
|
<li>Fixed chanview tree layout and header alignment; tighten topic URL hit-testing.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Tray:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Hardened tray menu lifetime; fixed stale pointer crash on menu destruction.</li>
|
||||||
|
<li>Fixed AppIndicator tray init for Wayland/source builds; skip redundant X11 tray probe for AppIndicator builds.</li>
|
||||||
|
</ul>
|
||||||
|
<p>Build and packaging:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Dropped <code>realpath()</code> in favour of GLib-only absolute path build.</li>
|
||||||
|
<li>Made About dialog links explicit; added GPL licence URL.</li>
|
||||||
|
<li>Added licence headers to new source files.</li>
|
||||||
|
<li>Windows installer: fixed VC++ redist URL, added non-plugin download fallback, switched to registry-based runtime detection.</li>
|
||||||
|
<li>Made <code>libayatana-appindicator</code> a required dep in PKGBUILD.</li>
|
||||||
|
<li>Cleaned up Meson libperl detection.</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
<release date="2026-03-22" version="2.18.0~pre5">
|
||||||
|
<description>
|
||||||
|
<p>Version metadata update:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Bumped release version references to <code>2.18.0~pre5</code> across build and packaging files.</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release date="2026-03-14" version="2.18.0~pre4">
|
<release date="2026-03-14" version="2.18.0~pre4">
|
||||||
<description>
|
<description>
|
||||||
<p>UI fixes, topic bar improvements, and selection styling updates:</p>
|
<p>UI fixes, topic bar improvements, and selection styling updates:</p>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
project('zoitechat', 'c',
|
project('zoitechat', 'c',
|
||||||
version: '2.18.0~pre4',
|
version: '2.18.0~pre5',
|
||||||
meson_version: '>= 0.55.0',
|
meson_version: '>= 0.55.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c17',
|
'c_std=c17',
|
||||||
|
|||||||
@@ -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~pre4'
|
VERSION = b'2.18.0~pre5'
|
||||||
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)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ char *sysinfo_backend_get_disk(void);
|
|||||||
char *sysinfo_backend_get_memory(void);
|
char *sysinfo_backend_get_memory(void);
|
||||||
char *sysinfo_backend_get_cpu(void);
|
char *sysinfo_backend_get_cpu(void);
|
||||||
char *sysinfo_backend_get_gpu(void);
|
char *sysinfo_backend_get_gpu(void);
|
||||||
|
char *sysinfo_backend_get_chipset(void);
|
||||||
char *sysinfo_backend_get_sound(void);
|
char *sysinfo_backend_get_sound(void);
|
||||||
char *sysinfo_backend_get_uptime(void);
|
char *sysinfo_backend_get_uptime(void);
|
||||||
char *sysinfo_backend_get_network(void);
|
char *sysinfo_backend_get_network(void);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ static zoitechat_plugin *ph;
|
|||||||
static char name[] = "Sysinfo";
|
static char name[] = "Sysinfo";
|
||||||
static char desc[] = "Display info about your hardware and OS";
|
static char desc[] = "Display info about your hardware and OS";
|
||||||
static char version[] = "1.0";
|
static char version[] = "1.0";
|
||||||
static char sysinfo_help[] = "SysInfo Usage:\n /SYSINFO [-e|-o] [CLIENT|UI|OS|CPU|RAM|DISK|VGA|SOUND|ETHERNET|UPTIME], print various details about your system or print a summary without arguments\n /SYSINFO SET <variable>\n";
|
static char sysinfo_help[] = "SysInfo Usage:\n /SYSINFO [-e|-o] [CLIENT|UI|OS|CPU|RAM|DISK|GPU|CHIPSET|SOUND|ETHERNET|UPTIME], print various details about your system or print a summary without arguments\n /SYSINFO SET <variable>\n";
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -54,16 +54,11 @@ typedef struct
|
|||||||
static char *
|
static char *
|
||||||
get_client (void)
|
get_client (void)
|
||||||
{
|
{
|
||||||
char *ui = sysinfo_backend_get_ui();
|
const char *ver = zoitechat_get_info(ph, "version");
|
||||||
const char *ver = zoitechat_get_info(ph, "version");
|
|
||||||
char *out;
|
char *out;
|
||||||
|
|
||||||
if (ui != NULL && *ui != '\0')
|
|
||||||
out = g_strdup_printf ("ZoiteChat %s (%s)", ver, ui);
|
|
||||||
else
|
|
||||||
out = g_strdup_printf ("ZoiteChat %s", ver);
|
out = g_strdup_printf ("ZoiteChat %s", ver);
|
||||||
|
|
||||||
g_free (ui);
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +69,8 @@ static hwinfo hwinfos[] = {
|
|||||||
{"cpu", "CPU", sysinfo_backend_get_cpu},
|
{"cpu", "CPU", sysinfo_backend_get_cpu},
|
||||||
{"memory", "Memory", sysinfo_backend_get_memory},
|
{"memory", "Memory", sysinfo_backend_get_memory},
|
||||||
{"storage", "Storage", sysinfo_backend_get_disk},
|
{"storage", "Storage", sysinfo_backend_get_disk},
|
||||||
{"vga", "VGA", sysinfo_backend_get_gpu},
|
{"gpu", "GPU", sysinfo_backend_get_gpu},
|
||||||
|
{"chipset", "CHIPSET", sysinfo_backend_get_chipset, TRUE},
|
||||||
{"sound", "Sound", sysinfo_backend_get_sound, TRUE},
|
{"sound", "Sound", sysinfo_backend_get_sound, TRUE},
|
||||||
{"ethernet", "Ethernet", sysinfo_backend_get_network, TRUE},
|
{"ethernet", "Ethernet", sysinfo_backend_get_network, TRUE},
|
||||||
{"uptime", "Uptime", sysinfo_backend_get_uptime},
|
{"uptime", "Uptime", sysinfo_backend_get_uptime},
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ char *sysinfo_backend_get_cpu(void)
|
|||||||
char *sysinfo_backend_get_gpu(void)
|
char *sysinfo_backend_get_gpu(void)
|
||||||
{
|
{
|
||||||
char vid_card[bsize];
|
char vid_card[bsize];
|
||||||
char agp_bridge[bsize];
|
|
||||||
char buffer[bsize];
|
char buffer[bsize];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -130,18 +129,29 @@ char *sysinfo_backend_get_gpu(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xs_parse_agpbridge (agp_bridge) != 0)
|
g_snprintf (buffer, bsize, "%s", vid_card);
|
||||||
{
|
|
||||||
g_snprintf (buffer, bsize, "%s", vid_card);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_snprintf (buffer, bsize, "%s @ %s", vid_card, agp_bridge);
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_strdup (buffer);
|
return g_strdup (buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *sysinfo_backend_get_chipset(void)
|
||||||
|
{
|
||||||
|
char agp_bridge[bsize];
|
||||||
|
char buffer[bsize];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((ret = xs_parse_agpbridge (agp_bridge)) != 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_snprintf (buffer, bsize, "%s", agp_bridge);
|
||||||
|
|
||||||
|
return g_strdup (buffer);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char *sysinfo_backend_get_sound(void)
|
char *sysinfo_backend_get_sound(void)
|
||||||
{
|
{
|
||||||
char sound[bsize];
|
char sound[bsize];
|
||||||
|
|||||||
@@ -89,6 +89,12 @@ sysinfo_backend_get_gpu (void)
|
|||||||
return sysinfo_get_gpu ();
|
return sysinfo_get_gpu ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
sysinfo_backend_get_chipset (void)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
sysinfo_backend_get_os (void)
|
sysinfo_backend_get_os (void)
|
||||||
{
|
{
|
||||||
|
|||||||
2
po/de.po
2
po/de.po
@@ -1325,7 +1325,7 @@ msgstr "%C29*%O$t%C29MOTD übersprungen%O"
|
|||||||
|
|
||||||
#: src/common/textevents.h:277
|
#: src/common/textevents.h:277
|
||||||
msgid "%C23*%O$t%C28$1%C is already in use. Retrying with %C18$2%O..."
|
msgid "%C23*%O$t%C28$1%C is already in use. Retrying with %C18$2%O..."
|
||||||
msgstr "%C23*%O$t%C28$1%C wird bereits verwendet. Erneurter Versuch mit %C18$2%O …"
|
msgstr "%C23*%O$t%C28$1%C wird bereits verwendet. Erneuter Versuch mit %C18$2%O …"
|
||||||
|
|
||||||
#: src/common/textevents.h:280
|
#: src/common/textevents.h:280
|
||||||
msgid "%C23*%O$t%C28$1%C is erroneous. Retrying with %C18$2%O..."
|
msgid "%C23*%O$t%C28$1%C is erroneous. Retrying with %C18$2%O..."
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ For more information on ZoiteChat please read our [documentation](https://docs.z
|
|||||||
<sub>
|
<sub>
|
||||||
X-Chat ("xchat") Copyright (c) 1998-2010 By Peter Zelezny.
|
X-Chat ("xchat") Copyright (c) 1998-2010 By Peter Zelezny.
|
||||||
HexChat ("hexchat") Copyright (c) 2009-2014 By Berke Viktor.
|
HexChat ("hexchat") Copyright (c) 2009-2014 By Berke Viktor.
|
||||||
|
Hexchat ("hexchat") Copyright (c) 2015-2025 By Patrick Griffis.
|
||||||
ZoiteChat ("zoitechat") Copyright (c) 2026 By deepend.
|
ZoiteChat ("zoitechat") Copyright (c) 2026 By deepend.
|
||||||
</sub>
|
</sub>
|
||||||
|
|
||||||
|
|||||||
@@ -411,6 +411,7 @@ const struct prefs vars[] =
|
|||||||
{"gui_chanlist_width_topic", P_OFFINT (hex_gui_chanlist_width_topic), TYPE_INT},
|
{"gui_chanlist_width_topic", P_OFFINT (hex_gui_chanlist_width_topic), TYPE_INT},
|
||||||
{"gui_chanlist_width_users", P_OFFINT (hex_gui_chanlist_width_users), TYPE_INT},
|
{"gui_chanlist_width_users", P_OFFINT (hex_gui_chanlist_width_users), TYPE_INT},
|
||||||
{"gui_compact", P_OFFINT (hex_gui_compact), TYPE_BOOL},
|
{"gui_compact", P_OFFINT (hex_gui_compact), TYPE_BOOL},
|
||||||
|
{"gui_ctrlq_quit", P_OFFINT (hex_gui_ctrlq_quit), TYPE_BOOL},
|
||||||
{"gui_dialog_height", P_OFFINT (hex_gui_dialog_height), TYPE_INT},
|
{"gui_dialog_height", P_OFFINT (hex_gui_dialog_height), TYPE_INT},
|
||||||
{"gui_dialog_left", P_OFFINT (hex_gui_dialog_left), TYPE_INT},
|
{"gui_dialog_left", P_OFFINT (hex_gui_dialog_left), TYPE_INT},
|
||||||
{"gui_dialog_top", P_OFFINT (hex_gui_dialog_top), TYPE_INT},
|
{"gui_dialog_top", P_OFFINT (hex_gui_dialog_top), TYPE_INT},
|
||||||
@@ -765,6 +766,7 @@ load_default_config(void)
|
|||||||
#ifdef HAVE_GTK_MAC
|
#ifdef HAVE_GTK_MAC
|
||||||
prefs.hex_gui_hide_menu = 1;
|
prefs.hex_gui_hide_menu = 1;
|
||||||
#endif
|
#endif
|
||||||
|
prefs.hex_gui_ctrlq_quit = 1;
|
||||||
prefs.hex_gui_input_attr = 1;
|
prefs.hex_gui_input_attr = 1;
|
||||||
prefs.hex_gui_input_icon = 1;
|
prefs.hex_gui_input_icon = 1;
|
||||||
prefs.hex_gui_input_nick = 1;
|
prefs.hex_gui_input_nick = 1;
|
||||||
|
|||||||
@@ -1796,6 +1796,36 @@ inbound_cap_ack (server *serv, char *nick, char *extensions,
|
|||||||
inbound_toggle_caps (serv, extensions, TRUE);
|
inbound_toggle_caps (serv, extensions, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
inbound_cap_new (server *serv, char *nick, char *extensions,
|
||||||
|
const message_tags_data *tags_data)
|
||||||
|
{
|
||||||
|
if (extensions)
|
||||||
|
{
|
||||||
|
char **tokens = g_strsplit (extensions, " ", 0);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; tokens[i]; i++)
|
||||||
|
{
|
||||||
|
char **parts = g_strsplit (tokens[i], "=", 2);
|
||||||
|
|
||||||
|
if (!g_strcmp0 (parts[0], "sts") && parts[1] && parts[1][0])
|
||||||
|
{
|
||||||
|
sts_handle_capability (serv, parts[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPACK, serv->server_session, nick, extensions,
|
||||||
|
NULL, NULL, 0, tags_data->timestamp);
|
||||||
|
|
||||||
|
inbound_toggle_caps (serv, extensions, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
inbound_cap_del (server *serv, char *nick, char *extensions,
|
inbound_cap_del (server *serv, char *nick, char *extensions,
|
||||||
const message_tags_data *tags_data)
|
const message_tags_data *tags_data)
|
||||||
|
|||||||
@@ -95,6 +95,8 @@ void inbound_cap_ls (server *serv, char *nick, char *extensions,
|
|||||||
void inbound_cap_nak (server *serv, char *extensions, const message_tags_data *tags_data);
|
void inbound_cap_nak (server *serv, char *extensions, const message_tags_data *tags_data);
|
||||||
void inbound_cap_list (server *serv, char *nick, char *extensions,
|
void inbound_cap_list (server *serv, char *nick, char *extensions,
|
||||||
const message_tags_data *tags_data);
|
const message_tags_data *tags_data);
|
||||||
|
void inbound_cap_new (server *serv, char *nick, char *extensions,
|
||||||
|
const message_tags_data *tags_data);
|
||||||
void inbound_cap_del (server *serv, char *nick, char *extensions,
|
void inbound_cap_del (server *serv, char *nick, char *extensions,
|
||||||
const message_tags_data *tags_data);
|
const message_tags_data *tags_data);
|
||||||
void inbound_sasl_authenticate (server *serv, char *data);
|
void inbound_sasl_authenticate (server *serv, char *data);
|
||||||
|
|||||||
@@ -396,10 +396,14 @@ cmd_away (struct session *sess, char *tbuf, char *word[], char *word_eol[])
|
|||||||
static int
|
static int
|
||||||
cmd_back (struct session *sess, char *tbuf, char *word[], char *word_eol[])
|
cmd_back (struct session *sess, char *tbuf, char *word[], char *word_eol[])
|
||||||
{
|
{
|
||||||
if (sess->server->is_away)
|
if (sess->server->connected)
|
||||||
{
|
{
|
||||||
sess->server->p_set_back (sess->server);
|
sess->server->p_set_back (sess->server);
|
||||||
}
|
}
|
||||||
|
else if (sess->server->reconnect_away)
|
||||||
|
{
|
||||||
|
sess->server->reconnect_away = FALSE;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PrintText (sess, _("Already marked back.\n"));
|
PrintText (sess, _("Already marked back.\n"));
|
||||||
|
|||||||
@@ -1359,12 +1359,18 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
|
|||||||
word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5],
|
word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5],
|
||||||
tags_data);
|
tags_data);
|
||||||
}
|
}
|
||||||
else if (g_ascii_strncasecmp(word[4], "LS", 2) == 0 || g_ascii_strncasecmp(word[4], "NEW", 3) == 0)
|
else if (g_ascii_strncasecmp(word[4], "LS", 2) == 0)
|
||||||
{
|
{
|
||||||
inbound_cap_ls (serv, word[1],
|
inbound_cap_ls (serv, word[1],
|
||||||
word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5],
|
word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5],
|
||||||
tags_data);
|
tags_data);
|
||||||
}
|
}
|
||||||
|
else if (g_ascii_strncasecmp(word[4], "NEW", 3) == 0)
|
||||||
|
{
|
||||||
|
inbound_cap_new (serv, word[1],
|
||||||
|
word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5],
|
||||||
|
tags_data);
|
||||||
|
}
|
||||||
else if (g_ascii_strncasecmp(word[4], "NAK", 3) == 0)
|
else if (g_ascii_strncasecmp(word[4], "NAK", 3) == 0)
|
||||||
{
|
{
|
||||||
inbound_cap_nak (serv, word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5], tags_data);
|
inbound_cap_nak (serv, word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5], tags_data);
|
||||||
|
|||||||
@@ -305,6 +305,7 @@ sts_parse_value (const char *value, guint16 *port, guint64 *duration, gboolean *
|
|||||||
{
|
{
|
||||||
char **tokens;
|
char **tokens;
|
||||||
gsize i;
|
gsize i;
|
||||||
|
char *end;
|
||||||
|
|
||||||
if (!value || !*value)
|
if (!value || !*value)
|
||||||
{
|
{
|
||||||
@@ -349,8 +350,9 @@ sts_parse_value (const char *value, guint16 *port, guint64 *duration, gboolean *
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
port_value = g_ascii_strtoll (val, NULL, 10);
|
end = NULL;
|
||||||
if (port_value > 0 && port_value <= G_MAXUINT16)
|
port_value = g_ascii_strtoll (val, &end, 10);
|
||||||
|
if (end && *end == '\0' && port_value > 0 && port_value <= G_MAXUINT16)
|
||||||
{
|
{
|
||||||
*port = (guint16) port_value;
|
*port = (guint16) port_value;
|
||||||
*has_port = TRUE;
|
*has_port = TRUE;
|
||||||
@@ -371,7 +373,12 @@ sts_parse_value (const char *value, guint16 *port, guint64 *duration, gboolean *
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
duration_value = g_ascii_strtoull (val, NULL, 10);
|
end = NULL;
|
||||||
|
duration_value = g_ascii_strtoull (val, &end, 10);
|
||||||
|
if (!end || *end != '\0')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
*duration = duration_value;
|
*duration = duration_value;
|
||||||
*has_duration = TRUE;
|
*has_duration = TRUE;
|
||||||
}
|
}
|
||||||
@@ -612,7 +619,7 @@ sts_handle_capability (struct server *serv, const char *value)
|
|||||||
{
|
{
|
||||||
time_t now = time (NULL);
|
time_t now = time (NULL);
|
||||||
time_t expires_at = now + (time_t) duration;
|
time_t expires_at = now + (time_t) duration;
|
||||||
guint16 effective_port = 0;
|
guint16 effective_port = (guint16) serv->port;
|
||||||
sts_profile *existing_profile;
|
sts_profile *existing_profile;
|
||||||
sts_profile *profile;
|
sts_profile *profile;
|
||||||
|
|
||||||
|
|||||||
217
src/common/url.c
217
src/common/url.c
@@ -35,20 +35,13 @@ GTree *url_btree = NULL;
|
|||||||
static gboolean regex_match (const GRegex *re, const char *word,
|
static gboolean regex_match (const GRegex *re, const char *word,
|
||||||
int *start, int *end);
|
int *start, int *end);
|
||||||
static const GRegex *re_url (void);
|
static const GRegex *re_url (void);
|
||||||
static const GRegex *re_url_no_scheme (void);
|
|
||||||
static const GRegex *re_host (void);
|
|
||||||
static const GRegex *re_host6 (void);
|
|
||||||
static const GRegex *re_email (void);
|
static const GRegex *re_email (void);
|
||||||
static const GRegex *re_nick (void);
|
static const GRegex *re_nick (void);
|
||||||
static const GRegex *re_channel (void);
|
static const GRegex *re_channel (void);
|
||||||
static const GRegex *re_path (void);
|
|
||||||
static gboolean match_nick (const char *word, int *start, int *end);
|
static gboolean match_nick (const char *word, int *start, int *end);
|
||||||
static gboolean match_channel (const char *word, int *start, int *end);
|
static gboolean match_channel (const char *word, int *start, int *end);
|
||||||
static gboolean match_email (const char *word, int *start, int *end);
|
|
||||||
static gboolean match_url (const char *word, int *start, int *end);
|
static gboolean match_url (const char *word, int *start, int *end);
|
||||||
static gboolean match_host (const char *word, int *start, int *end);
|
static gboolean match_email (const char *word, int *start, int *end);
|
||||||
static gboolean match_host6 (const char *word, int *start, int *end);
|
|
||||||
static gboolean match_path (const char *word, int *start, int *end);
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
url_free (char *url, void *data)
|
url_free (char *url, void *data)
|
||||||
@@ -122,6 +115,11 @@ url_add (char *urltext, int len)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (len <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
data = g_strndup (urltext, len);
|
data = g_strndup (urltext, len);
|
||||||
|
|
||||||
if (data[len - 1] == '.')
|
if (data[len - 1] == '.')
|
||||||
@@ -193,9 +191,6 @@ url_check_word (const char *word)
|
|||||||
{ match_url, WORD_URL },
|
{ match_url, WORD_URL },
|
||||||
{ match_email, WORD_EMAIL },
|
{ match_email, WORD_EMAIL },
|
||||||
{ match_channel, WORD_CHANNEL },
|
{ match_channel, WORD_CHANNEL },
|
||||||
{ match_host6, WORD_HOST6 },
|
|
||||||
{ match_host, WORD_HOST },
|
|
||||||
{ match_path, WORD_PATH },
|
|
||||||
{ match_nick, WORD_NICK },
|
{ match_nick, WORD_NICK },
|
||||||
{ NULL, 0}
|
{ NULL, 0}
|
||||||
};
|
};
|
||||||
@@ -268,45 +263,18 @@ match_channel (const char *word, int *start, int *end)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
match_url (const char *word, int *start, int *end)
|
||||||
|
{
|
||||||
|
return regex_match (re_url (), word, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
match_email (const char *word, int *start, int *end)
|
match_email (const char *word, int *start, int *end)
|
||||||
{
|
{
|
||||||
return regex_match (re_email (), word, start, end);
|
return regex_match (re_email (), word, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
match_url (const char *word, int *start, int *end)
|
|
||||||
{
|
|
||||||
if (regex_match (re_url (), word, start, end))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return regex_match (re_url_no_scheme (), word, start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
match_host (const char *word, int *start, int *end)
|
|
||||||
{
|
|
||||||
return regex_match (re_host (), word, start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
match_host6 (const char *word, int *start, int *end)
|
|
||||||
{
|
|
||||||
if (!regex_match (re_host6 (), word, start, end))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (word[*start] != '[')
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
match_path (const char *word, int *start, int *end)
|
|
||||||
{
|
|
||||||
return regex_match (re_path (), word, start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List of IRC commands for which contents (and thus possible URLs)
|
/* List of IRC commands for which contents (and thus possible URLs)
|
||||||
* are visible to the user. NOTE: Trailing blank required in each. */
|
* are visible to the user. NOTE: Trailing blank required in each. */
|
||||||
static char *commands[] = {
|
static char *commands[] = {
|
||||||
@@ -451,34 +419,7 @@ make_re (const char *grist)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HOST description --- */
|
|
||||||
/* (see miscellaneous above) */
|
|
||||||
static const GRegex *
|
|
||||||
re_host (void)
|
|
||||||
{
|
|
||||||
static GRegex *host_ret;
|
|
||||||
|
|
||||||
if (host_ret) return host_ret;
|
|
||||||
|
|
||||||
host_ret = make_re ("(" "(" HOST_URL PORT ")|(" HOST ")" ")");
|
|
||||||
|
|
||||||
return host_ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const GRegex *
|
|
||||||
re_host6 (void)
|
|
||||||
{
|
|
||||||
static GRegex *host6_ret;
|
|
||||||
|
|
||||||
if (host6_ret) return host6_ret;
|
|
||||||
|
|
||||||
host6_ret = make_re ("(" "(" IPV6ADDR ")|(" "\\[" IPV6ADDR "\\]" PORT ")" ")");
|
|
||||||
|
|
||||||
return host6_ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* URL description --- */
|
/* URL description --- */
|
||||||
#define SCHEME "(%s)"
|
|
||||||
#define LPAR "\\("
|
#define LPAR "\\("
|
||||||
#define RPAR "\\)"
|
#define RPAR "\\)"
|
||||||
#define NOPARENS "[^() \t]*"
|
#define NOPARENS "[^() \t]*"
|
||||||
@@ -489,86 +430,20 @@ re_host6 (void)
|
|||||||
"(" NOPARENS ")" \
|
"(" NOPARENS ")" \
|
||||||
")*" /* Zero or more occurrences of either of these */ \
|
")*" /* Zero or more occurrences of either of these */ \
|
||||||
"(?<![.,?!\\]])" /* Not allowed to end with these */
|
"(?<![.,?!\\]])" /* Not allowed to end with these */
|
||||||
#define USERINFO "([-a-z0-9._~%]+(:[-a-z0-9._~%]*)?@)"
|
|
||||||
|
|
||||||
/* Flags used to describe URIs (RFC 3986)
|
|
||||||
*
|
|
||||||
* Bellow is an example of what the flags match.
|
|
||||||
*
|
|
||||||
* URI_AUTHORITY - http://example.org:80/foo/bar
|
|
||||||
* ^^^^^^^^^^^^^^^^
|
|
||||||
* URI_USERINFO/URI_OPT_USERINFO - http://user@example.org:80/foo/bar
|
|
||||||
* ^^^^^
|
|
||||||
* URI_PATH - http://example.org:80/foo/bar
|
|
||||||
* ^^^^^^^^
|
|
||||||
*/
|
|
||||||
#define URI_AUTHORITY (1 << 0)
|
|
||||||
#define URI_OPT_USERINFO (1 << 1)
|
|
||||||
#define URI_USERINFO (1 << 2)
|
|
||||||
#define URI_PATH (1 << 3)
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
const char *scheme; /* scheme name. e.g. http */
|
const char *scheme;
|
||||||
const char *path_sep; /* string that begins the path */
|
|
||||||
int flags; /* see above (flag macros) */
|
|
||||||
} uri[] = {
|
} uri[] = {
|
||||||
{ "irc", "/", URI_PATH },
|
{ "http" },
|
||||||
{ "ircs", "/", URI_PATH },
|
{ "https" },
|
||||||
{ "rtsp", "/", URI_AUTHORITY | URI_PATH },
|
{ "ftp" },
|
||||||
{ "feed", "/", URI_AUTHORITY | URI_PATH },
|
{ "gopher" },
|
||||||
{ "teamspeak", "?", URI_AUTHORITY | URI_PATH },
|
{ "gemini" },
|
||||||
{ "ftp", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
{ "irc" },
|
||||||
{ "sftp", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
{ "ircs" },
|
||||||
{ "ftps", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
{ NULL }
|
||||||
{ "http", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "https", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "cvs", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "svn", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "git", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "bzr", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "rsync", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "mumble", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "ventrilo", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "xmpp", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "h323", ";", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "imap", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "pop", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "nfs", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "smb", "/", URI_AUTHORITY | URI_OPT_USERINFO | URI_PATH },
|
|
||||||
{ "gopher", "/", URI_AUTHORITY | URI_PATH },
|
|
||||||
{ "gemini", "/", URI_AUTHORITY | URI_PATH },
|
|
||||||
{ "ssh", "", URI_AUTHORITY | URI_OPT_USERINFO },
|
|
||||||
{ "sip", "", URI_AUTHORITY | URI_USERINFO },
|
|
||||||
{ "sips", "", URI_AUTHORITY | URI_USERINFO },
|
|
||||||
{ "magnet", "?", URI_PATH },
|
|
||||||
{ "mailto", "", URI_PATH },
|
|
||||||
{ "bitcoin", "", URI_PATH },
|
|
||||||
{ "gtalk", "", URI_PATH },
|
|
||||||
{ "steam", "", URI_PATH },
|
|
||||||
{ "file", "/", URI_PATH },
|
|
||||||
{ "callto", "", URI_PATH },
|
|
||||||
{ "skype", "", URI_PATH },
|
|
||||||
{ "geo", "", URI_PATH },
|
|
||||||
{ "spotify", "", URI_PATH },
|
|
||||||
{ "lastfm", "/", URI_PATH },
|
|
||||||
{ "xfire", "", URI_PATH },
|
|
||||||
{ "ts3server", "", URI_PATH },
|
|
||||||
{ NULL, "", 0}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const GRegex *
|
|
||||||
re_url_no_scheme (void)
|
|
||||||
{
|
|
||||||
static GRegex *url_ret = NULL;
|
|
||||||
|
|
||||||
if (url_ret) return url_ret;
|
|
||||||
|
|
||||||
url_ret = make_re ("(" HOST_URL OPT_PORT "/" "(" PATH ")?" ")");
|
|
||||||
|
|
||||||
return url_ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const GRegex *
|
static const GRegex *
|
||||||
re_url (void)
|
re_url (void)
|
||||||
{
|
{
|
||||||
@@ -587,27 +462,9 @@ re_url (void)
|
|||||||
g_string_append (grist_gstr, "|");
|
g_string_append (grist_gstr, "|");
|
||||||
|
|
||||||
g_string_append (grist_gstr, "(");
|
g_string_append (grist_gstr, "(");
|
||||||
g_string_append_printf (grist_gstr, "%s:", uri[i].scheme);
|
g_string_append_printf (grist_gstr, "%s://", uri[i].scheme);
|
||||||
|
g_string_append (grist_gstr, HOST_URL_OPT_TLD OPT_PORT);
|
||||||
if (uri[i].flags & URI_AUTHORITY)
|
g_string_append_printf (grist_gstr, "(/" PATH ")?");
|
||||||
g_string_append (grist_gstr, "//");
|
|
||||||
|
|
||||||
if (uri[i].flags & URI_USERINFO)
|
|
||||||
g_string_append (grist_gstr, USERINFO);
|
|
||||||
else if (uri[i].flags & URI_OPT_USERINFO)
|
|
||||||
g_string_append (grist_gstr, USERINFO "?");
|
|
||||||
|
|
||||||
if (uri[i].flags & URI_AUTHORITY)
|
|
||||||
g_string_append (grist_gstr, HOST_URL_OPT_TLD OPT_PORT);
|
|
||||||
|
|
||||||
if (uri[i].flags & URI_PATH)
|
|
||||||
{
|
|
||||||
char *sep_escaped = g_regex_escape_string (uri[i].path_sep, strlen(uri[i].path_sep));
|
|
||||||
|
|
||||||
g_string_append_printf (grist_gstr, "(" "%s" PATH ")?", sep_escaped);
|
|
||||||
|
|
||||||
g_free (sep_escaped);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_string_append (grist_gstr, ")");
|
g_string_append (grist_gstr, ")");
|
||||||
}
|
}
|
||||||
@@ -620,8 +477,9 @@ re_url (void)
|
|||||||
return url_ret;
|
return url_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EMAIL description --- */
|
#define EMAIL_LOCAL_ATOM "[\\pL\\pN!#$%&'*+/=?^_`{|}~-]+"
|
||||||
#define EMAIL "[a-z0-9][._%+-a-z0-9]+@" "(" HOST_URL ")"
|
#define EMAIL_LOCAL EMAIL_LOCAL_ATOM "(\\." EMAIL_LOCAL_ATOM ")*"
|
||||||
|
#define EMAIL EMAIL_LOCAL "@" DOMAIN TLD
|
||||||
|
|
||||||
static const GRegex *
|
static const GRegex *
|
||||||
re_email (void)
|
re_email (void)
|
||||||
@@ -680,24 +538,3 @@ re_channel (void)
|
|||||||
|
|
||||||
return channel_ret;
|
return channel_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PATH description --- */
|
|
||||||
#ifdef WIN32
|
|
||||||
/* Windows path can be .\ ..\ or C: D: etc */
|
|
||||||
#define FS_PATH "^(\\.{1,2}\\\\|[a-z]:).*"
|
|
||||||
#else
|
|
||||||
/* Linux path can be / or ./ or ../ etc */
|
|
||||||
#define FS_PATH "^(/|\\./|\\.\\./).*"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const GRegex *
|
|
||||||
re_path (void)
|
|
||||||
{
|
|
||||||
static GRegex *path_ret;
|
|
||||||
|
|
||||||
if (path_ret) return path_ret;
|
|
||||||
|
|
||||||
path_ret = make_re ("(" FS_PATH ")");
|
|
||||||
|
|
||||||
return path_ret;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ struct zoitechatprefs
|
|||||||
unsigned int hex_gui_autoopen_recv;
|
unsigned int hex_gui_autoopen_recv;
|
||||||
unsigned int hex_gui_autoopen_send;
|
unsigned int hex_gui_autoopen_send;
|
||||||
unsigned int hex_gui_compact;
|
unsigned int hex_gui_compact;
|
||||||
|
unsigned int hex_gui_ctrlq_quit;
|
||||||
unsigned int hex_gui_filesize_iec;
|
unsigned int hex_gui_filesize_iec;
|
||||||
unsigned int hex_gui_focus_omitalerts;
|
unsigned int hex_gui_focus_omitalerts;
|
||||||
unsigned int hex_gui_hide_menu;
|
unsigned int hex_gui_hide_menu;
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <dwmapi.h>
|
#include <dwmapi.h>
|
||||||
|
#include <glib/gwin32.h>
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -301,9 +302,28 @@ fe_args (int argc, char *argv[])
|
|||||||
GOptionContext *context;
|
GOptionContext *context;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
const char *desktop_id = "net.zoite.Zoitechat";
|
const char *desktop_id = "net.zoite.Zoitechat";
|
||||||
|
#ifdef WIN32
|
||||||
|
char *base_path = NULL;
|
||||||
|
char *locale_path = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_NLS
|
#ifdef ENABLE_NLS
|
||||||
|
#ifdef WIN32
|
||||||
|
base_path = g_win32_get_package_installation_directory_of_module (NULL);
|
||||||
|
if (base_path)
|
||||||
|
{
|
||||||
|
locale_path = g_build_filename (base_path, "share", "locale", NULL);
|
||||||
|
bindtextdomain (GETTEXT_PACKAGE, locale_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||||
|
}
|
||||||
|
g_free (locale_path);
|
||||||
|
g_free (base_path);
|
||||||
|
#else
|
||||||
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||||
|
#endif
|
||||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||||
textdomain (GETTEXT_PACKAGE);
|
textdomain (GETTEXT_PACKAGE);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ typedef struct session_gui
|
|||||||
GtkWidget *shbox, *shentry; /* search bar hbox */
|
GtkWidget *shbox, *shentry; /* search bar hbox */
|
||||||
gulong search_changed_signal; /* hook for search change event so blanking the box doesn't suck */
|
gulong search_changed_signal; /* hook for search change event so blanking the box doesn't suck */
|
||||||
|
|
||||||
#define MENU_ID_NUM 14
|
#define MENU_ID_NUM 15
|
||||||
GtkWidget *menu_item[MENU_ID_NUM+1]; /* some items we may change state of */
|
GtkWidget *menu_item[MENU_ID_NUM+1]; /* some items we may change state of */
|
||||||
|
|
||||||
void *chanview; /* chanview.h */
|
void *chanview; /* chanview.h */
|
||||||
|
|||||||
@@ -1888,6 +1888,20 @@ key_action_put_history (GtkWidget * wid, GdkEventKey * ent, char *d1,
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
replace_set_pos_idle (gpointer data)
|
||||||
|
{
|
||||||
|
GtkWidget *t = GTK_WIDGET (data);
|
||||||
|
gpointer pos_data = g_object_get_data (G_OBJECT (t), "zoitechat-replace-pos");
|
||||||
|
|
||||||
|
if (pos_data)
|
||||||
|
SPELL_ENTRY_SET_POS (t, GPOINTER_TO_INT (pos_data));
|
||||||
|
|
||||||
|
g_object_set_data (G_OBJECT (t), "zoitechat-replace-pos", NULL);
|
||||||
|
g_object_unref (t);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
replace_handle (GtkWidget *t)
|
replace_handle (GtkWidget *t)
|
||||||
{
|
{
|
||||||
@@ -1903,11 +1917,12 @@ replace_handle (GtkWidget *t)
|
|||||||
size_t match_len;
|
size_t match_len;
|
||||||
ptrdiff_t cursor_byte_offset;
|
ptrdiff_t cursor_byte_offset;
|
||||||
ptrdiff_t match_start_offset;
|
ptrdiff_t match_start_offset;
|
||||||
ptrdiff_t match_end_offset;
|
|
||||||
ptrdiff_t new_cursor_offset;
|
ptrdiff_t new_cursor_offset;
|
||||||
const char *best_match;
|
const char *best_match;
|
||||||
size_t best_len;
|
size_t best_len;
|
||||||
struct popup *best_pop;
|
struct popup *best_pop;
|
||||||
|
int best_rank;
|
||||||
|
ptrdiff_t best_distance;
|
||||||
|
|
||||||
text = SPELL_ENTRY_GET_TEXT (t);
|
text = SPELL_ENTRY_GET_TEXT (t);
|
||||||
|
|
||||||
@@ -1922,19 +1937,50 @@ replace_handle (GtkWidget *t)
|
|||||||
best_match = NULL;
|
best_match = NULL;
|
||||||
best_len = 0;
|
best_len = 0;
|
||||||
best_pop = NULL;
|
best_pop = NULL;
|
||||||
|
best_rank = 3;
|
||||||
|
best_distance = 0;
|
||||||
|
cursor_byte_offset = cursor_ptr - text;
|
||||||
while (list)
|
while (list)
|
||||||
{
|
{
|
||||||
pop = (struct popup *) list->data;
|
pop = (struct popup *) list->data;
|
||||||
if (pop->name[0] != '\0')
|
if (pop->name[0] != '\0')
|
||||||
{
|
{
|
||||||
size_t pop_len = strlen (pop->name);
|
size_t pop_len = strlen (pop->name);
|
||||||
const char *found = strstr (text, pop->name);
|
const char *found = text;
|
||||||
|
|
||||||
if (found && (!best_match || found < best_match))
|
while ((found = strstr (found, pop->name)) != NULL)
|
||||||
{
|
{
|
||||||
best_match = found;
|
ptrdiff_t found_offset = found - text;
|
||||||
best_len = pop_len;
|
ptrdiff_t found_end_offset = found_offset + (ptrdiff_t) pop_len;
|
||||||
best_pop = pop;
|
int rank;
|
||||||
|
ptrdiff_t distance;
|
||||||
|
|
||||||
|
if (cursor_byte_offset >= found_offset && cursor_byte_offset <= found_end_offset)
|
||||||
|
{
|
||||||
|
rank = 0;
|
||||||
|
distance = found_end_offset - cursor_byte_offset;
|
||||||
|
}
|
||||||
|
else if (found_end_offset <= cursor_byte_offset)
|
||||||
|
{
|
||||||
|
rank = 1;
|
||||||
|
distance = cursor_byte_offset - found_end_offset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rank = 2;
|
||||||
|
distance = found_offset - cursor_byte_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rank < best_rank || (rank == best_rank && distance < best_distance))
|
||||||
|
{
|
||||||
|
best_rank = rank;
|
||||||
|
best_distance = distance;
|
||||||
|
best_match = found;
|
||||||
|
best_len = pop_len;
|
||||||
|
best_pop = pop;
|
||||||
|
}
|
||||||
|
|
||||||
|
found++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
list = list->next;
|
list = list->next;
|
||||||
@@ -1952,21 +1998,17 @@ replace_handle (GtkWidget *t)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
replacement_len = strlen (pop->cmd);
|
replacement_len = strlen (pop->cmd);
|
||||||
cursor_byte_offset = cursor_ptr - text;
|
|
||||||
match_start_offset = match_start - text;
|
match_start_offset = match_start - text;
|
||||||
match_end_offset = match_start_offset + (ptrdiff_t) match_len;
|
new_cursor_offset = match_start_offset + (ptrdiff_t) replacement_len;
|
||||||
if (cursor_byte_offset <= match_start_offset)
|
|
||||||
new_cursor_offset = cursor_byte_offset;
|
|
||||||
else if (cursor_byte_offset >= match_end_offset)
|
|
||||||
new_cursor_offset = cursor_byte_offset + ((ptrdiff_t) replacement_len - (ptrdiff_t) match_len);
|
|
||||||
else
|
|
||||||
new_cursor_offset = match_start_offset + (ptrdiff_t) replacement_len;
|
|
||||||
buf = g_string_sized_new (strlen (text) + 32);
|
buf = g_string_sized_new (strlen (text) + 32);
|
||||||
g_string_append_len (buf, text, match_start - text);
|
g_string_append_len (buf, text, match_start - text);
|
||||||
g_string_append (buf, pop->cmd);
|
g_string_append (buf, pop->cmd);
|
||||||
g_string_append (buf, match_start + match_len);
|
g_string_append (buf, match_start + match_len);
|
||||||
SPELL_ENTRY_SET_TEXT (t, buf->str);
|
SPELL_ENTRY_SET_TEXT (t, buf->str);
|
||||||
SPELL_ENTRY_SET_POS (t, len_to_offset (buf->str, new_cursor_offset));
|
new_cursor_offset = len_to_offset (buf->str, new_cursor_offset);
|
||||||
|
SPELL_ENTRY_SET_POS (t, new_cursor_offset);
|
||||||
|
g_object_set_data (G_OBJECT (t), "zoitechat-replace-pos", GINT_TO_POINTER ((gint) new_cursor_offset));
|
||||||
|
g_idle_add (replace_set_pos_idle, g_object_ref (t));
|
||||||
g_string_free (buf, TRUE);
|
g_string_free (buf, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4206,7 +4206,7 @@ mg_create_menu (session_gui *gui, GtkWidget *table, int away_state)
|
|||||||
gui->menu_item);
|
gui->menu_item);
|
||||||
gtk_widget_set_hexpand (gui->menu, TRUE);
|
gtk_widget_set_hexpand (gui->menu, TRUE);
|
||||||
gtk_widget_set_vexpand (gui->menu, FALSE);
|
gtk_widget_set_vexpand (gui->menu, FALSE);
|
||||||
gtk_widget_set_halign (gui->menu, GTK_ALIGN_FILL);
|
gtk_widget_set_halign (gui->menu, GTK_ALIGN_START);
|
||||||
gtk_widget_set_valign (gui->menu, GTK_ALIGN_FILL);
|
gtk_widget_set_valign (gui->menu, GTK_ALIGN_FILL);
|
||||||
gtk_grid_attach (GTK_GRID (table), gui->menu, 0, 0, 3, 1);
|
gtk_grid_attach (GTK_GRID (table), gui->menu, 0, 0, 3, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1802,6 +1802,44 @@ menu_change_layout (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
menu_update_quit_accel (void)
|
||||||
|
{
|
||||||
|
GSList *list;
|
||||||
|
|
||||||
|
list = sess_list;
|
||||||
|
while (list)
|
||||||
|
{
|
||||||
|
session *sess = list->data;
|
||||||
|
session_gui *gui = sess->gui;
|
||||||
|
GtkWidget *item;
|
||||||
|
GtkAccelGroup *accel_group;
|
||||||
|
int enabled;
|
||||||
|
|
||||||
|
list = list->next;
|
||||||
|
if (!gui)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
item = gui->menu_item[MENU_ID_QUIT];
|
||||||
|
if (!item)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
enabled = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "zc-ctrlq-enabled"));
|
||||||
|
if (enabled == (int)prefs.hex_gui_ctrlq_quit)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
accel_group = g_object_get_data (G_OBJECT (item), "zc-quit-accel-group");
|
||||||
|
if (!accel_group)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (prefs.hex_gui_ctrlq_quit)
|
||||||
|
gtk_widget_add_accelerator (item, "activate", accel_group, GDK_KEY_q, STATE_CTRL, GTK_ACCEL_VISIBLE);
|
||||||
|
else
|
||||||
|
gtk_widget_remove_accelerator (item, accel_group, GDK_KEY_q, STATE_CTRL);
|
||||||
|
g_object_set_data (G_OBJECT (item), "zc-ctrlq-enabled", GINT_TO_POINTER (prefs.hex_gui_ctrlq_quit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
menu_layout_cb (GtkWidget *item, gpointer none)
|
menu_layout_cb (GtkWidget *item, gpointer none)
|
||||||
{
|
{
|
||||||
@@ -1867,8 +1905,18 @@ menu_metres_both (GtkWidget *item, gpointer none)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
about_dialog_close (GtkDialog *dialog, int response, gpointer data)
|
about_dialog_response (GtkDialog *dialog, int response, gpointer data)
|
||||||
{
|
{
|
||||||
|
if (response == GTK_RESPONSE_HELP)
|
||||||
|
{
|
||||||
|
fe_open_url ("http://zoitechat.zoite.net");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (response == GTK_RESPONSE_APPLY)
|
||||||
|
{
|
||||||
|
fe_open_url ("https://www.gnu.org/licenses/old-licenses/gpl-2.0.html");
|
||||||
|
return;
|
||||||
|
}
|
||||||
gtk_widget_destroy (GTK_WIDGET(dialog));
|
gtk_widget_destroy (GTK_WIDGET(dialog));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1879,25 +1927,17 @@ about_dialog_openurl (GtkAboutDialog *dialog, char *uri, gpointer data)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
about_dialog_add_links (GtkAboutDialog *dialog)
|
|
||||||
{
|
|
||||||
GtkWidget *content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
|
|
||||||
GtkWidget *row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
|
|
||||||
GtkWidget *website = gtk_link_button_new_with_label ("http://zoitechat.zoite.net", "Website");
|
|
||||||
GtkWidget *license = gtk_link_button_new_with_label ("https://www.gnu.org/licenses/old-licenses/gpl-2.0.html", "License");
|
|
||||||
gtk_button_set_relief (GTK_BUTTON (website), GTK_RELIEF_NONE);
|
|
||||||
gtk_button_set_relief (GTK_BUTTON (license), GTK_RELIEF_NONE);
|
|
||||||
gtk_box_pack_start (GTK_BOX (row), website, FALSE, FALSE, 0);
|
|
||||||
gtk_box_pack_start (GTK_BOX (row), license, FALSE, FALSE, 0);
|
|
||||||
gtk_box_pack_start (GTK_BOX (content), row, FALSE, FALSE, 0);
|
|
||||||
gtk_widget_show_all (row);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
menu_about (GtkWidget *wid, gpointer sess)
|
menu_about (GtkWidget *wid, gpointer sess)
|
||||||
{
|
{
|
||||||
GtkAboutDialog *dialog = GTK_ABOUT_DIALOG(gtk_about_dialog_new());
|
GtkAboutDialog *dialog = GTK_ABOUT_DIALOG (g_object_new (GTK_TYPE_ABOUT_DIALOG, "use-header-bar", FALSE, NULL));
|
||||||
|
GtkWidget *website;
|
||||||
|
GtkWidget *license;
|
||||||
|
GtkWidget *close;
|
||||||
|
GtkWidget *actions;
|
||||||
|
GList *children;
|
||||||
|
GList *child;
|
||||||
|
static const gchar *empty_people[] = { NULL };
|
||||||
theme_manager_attach_window (GTK_WIDGET (dialog));
|
theme_manager_attach_window (GTK_WIDGET (dialog));
|
||||||
char comment[512];
|
char comment[512];
|
||||||
g_snprintf (comment, sizeof(comment), ""
|
g_snprintf (comment, sizeof(comment), ""
|
||||||
@@ -1914,17 +1954,31 @@ menu_about (GtkWidget *wid, gpointer sess)
|
|||||||
|
|
||||||
gtk_about_dialog_set_program_name (dialog, _(DISPLAY_NAME));
|
gtk_about_dialog_set_program_name (dialog, _(DISPLAY_NAME));
|
||||||
gtk_about_dialog_set_version (dialog, PACKAGE_VERSION);
|
gtk_about_dialog_set_version (dialog, PACKAGE_VERSION);
|
||||||
gtk_about_dialog_set_authors (dialog, NULL);
|
gtk_about_dialog_set_authors (dialog, empty_people);
|
||||||
gtk_about_dialog_set_documenters (dialog, NULL);
|
gtk_about_dialog_set_documenters (dialog, empty_people);
|
||||||
gtk_about_dialog_set_artists (dialog, NULL);
|
gtk_about_dialog_set_artists (dialog, empty_people);
|
||||||
gtk_about_dialog_set_translator_credits (dialog, NULL);
|
gtk_about_dialog_set_translator_credits (dialog, "");
|
||||||
|
gtk_about_dialog_set_website (dialog, NULL);
|
||||||
|
gtk_about_dialog_set_website_label (dialog, NULL);
|
||||||
|
gtk_about_dialog_set_license (dialog, NULL);
|
||||||
|
gtk_about_dialog_set_wrap_license (dialog, FALSE);
|
||||||
gtk_about_dialog_set_logo (dialog, pix_zoitechat);
|
gtk_about_dialog_set_logo (dialog, pix_zoitechat);
|
||||||
gtk_about_dialog_set_copyright (dialog, "\302\251 1998-2010 Peter \305\275elezn\303\275\n\302\251 2009-2014 Berke Viktor\n\302\251 2026 deepend");
|
gtk_about_dialog_set_copyright (dialog, "\302\251 1998-2010 Peter \305\275elezn\303\275\n\302\251 2009-2014 Berke Viktor\n\302\251 2015-2025 Patrick Griffis\n\302\251 2026 deepend");
|
||||||
gtk_about_dialog_set_comments (dialog, comment);
|
gtk_about_dialog_set_comments (dialog, comment);
|
||||||
about_dialog_add_links (dialog);
|
actions = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
|
||||||
|
children = gtk_container_get_children (GTK_CONTAINER (actions));
|
||||||
|
for (child = children; child; child = child->next)
|
||||||
|
gtk_widget_destroy (GTK_WIDGET (child->data));
|
||||||
|
g_list_free (children);
|
||||||
|
website = gtk_dialog_add_button (GTK_DIALOG (dialog), "Website", GTK_RESPONSE_HELP);
|
||||||
|
license = gtk_dialog_add_button (GTK_DIALOG (dialog), "License", GTK_RESPONSE_APPLY);
|
||||||
|
close = gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Close"), GTK_RESPONSE_CLOSE);
|
||||||
|
gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (actions), website, TRUE);
|
||||||
|
gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (actions), license, TRUE);
|
||||||
|
gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (actions), close, FALSE);
|
||||||
|
|
||||||
gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(parent_window));
|
gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(parent_window));
|
||||||
g_signal_connect (G_OBJECT(dialog), "response", G_CALLBACK(about_dialog_close), NULL);
|
g_signal_connect (G_OBJECT(dialog), "response", G_CALLBACK(about_dialog_response), NULL);
|
||||||
g_signal_connect (G_OBJECT(dialog), "activate-link", G_CALLBACK(about_dialog_openurl), NULL);
|
g_signal_connect (G_OBJECT(dialog), "activate-link", G_CALLBACK(about_dialog_openurl), NULL);
|
||||||
|
|
||||||
gtk_widget_show_all (GTK_WIDGET(dialog));
|
gtk_widget_show_all (GTK_WIDGET(dialog));
|
||||||
@@ -1950,7 +2004,7 @@ static struct mymenu mymenu[] = {
|
|||||||
#define CLOSE_OFFSET (13)
|
#define CLOSE_OFFSET (13)
|
||||||
{0, menu_close, 0, M_MENUITEM, 0, 0, 1},
|
{0, menu_close, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{0, 0, 0, M_SEP, 0, 0, 0},
|
{0, 0, 0, M_SEP, 0, 0, 0},
|
||||||
{N_("_Quit"), menu_quit, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_q}, /* 15 */
|
{N_("_Quit"), menu_quit, 0, M_MENUITEM, MENU_ID_QUIT, 0, 1, GDK_KEY_q}, /* 15 */
|
||||||
|
|
||||||
{N_("_View"), 0, 0, M_NEWMENU, 0, 0, 1},
|
{N_("_View"), 0, 0, M_NEWMENU, 0, 0, 1},
|
||||||
#define MENUBAR_OFFSET (17)
|
#define MENUBAR_OFFSET (17)
|
||||||
@@ -2634,7 +2688,7 @@ menu_create_main (void *accel_group, int bar, int away, int toplevel,
|
|||||||
case M_MENUITEM:
|
case M_MENUITEM:
|
||||||
item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text));
|
item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text));
|
||||||
normalitem:
|
normalitem:
|
||||||
if (mymenu[i].key != 0)
|
if (mymenu[i].key != 0 && !(mymenu[i].id == MENU_ID_QUIT && !prefs.hex_gui_ctrlq_quit))
|
||||||
gtk_widget_add_accelerator (item, "activate", accel_group,
|
gtk_widget_add_accelerator (item, "activate", accel_group,
|
||||||
mymenu[i].key,
|
mymenu[i].key,
|
||||||
mymenu[i].key == GDK_KEY_F1 ? 0 :
|
mymenu[i].key == GDK_KEY_F1 ? 0 :
|
||||||
@@ -2644,6 +2698,11 @@ normalitem:
|
|||||||
STATE_SHIFT | STATE_CTRL :
|
STATE_SHIFT | STATE_CTRL :
|
||||||
STATE_CTRL,
|
STATE_CTRL,
|
||||||
GTK_ACCEL_VISIBLE);
|
GTK_ACCEL_VISIBLE);
|
||||||
|
if (mymenu[i].id == MENU_ID_QUIT)
|
||||||
|
{
|
||||||
|
g_object_set_data (G_OBJECT (item), "zc-quit-accel-group", accel_group);
|
||||||
|
g_object_set_data (G_OBJECT (item), "zc-ctrlq-enabled", GINT_TO_POINTER (prefs.hex_gui_ctrlq_quit));
|
||||||
|
}
|
||||||
if (mymenu[i].callback)
|
if (mymenu[i].callback)
|
||||||
g_signal_connect (G_OBJECT (item), "activate",
|
g_signal_connect (G_OBJECT (item), "activate",
|
||||||
G_CALLBACK (mymenu[i].callback), 0);
|
G_CALLBACK (mymenu[i].callback), 0);
|
||||||
@@ -2685,9 +2744,11 @@ togitem:
|
|||||||
goto togitem;
|
goto togitem;
|
||||||
|
|
||||||
case M_SEP:
|
case M_SEP:
|
||||||
item = gtk_menu_item_new ();
|
item = gtk_separator_menu_item_new ();
|
||||||
gtk_widget_set_sensitive (item, FALSE);
|
if (submenu)
|
||||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
|
||||||
|
else
|
||||||
|
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||||
gtk_widget_show (item);
|
gtk_widget_show (item);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ void menu_create (GtkWidget *menu, GSList *list, char *target, int check_path);
|
|||||||
void menu_bar_toggle (void);
|
void menu_bar_toggle (void);
|
||||||
void menu_add_plugin_items (GtkWidget *menu, char *root, char *target);
|
void menu_add_plugin_items (GtkWidget *menu, char *root, char *target);
|
||||||
void menu_change_layout (void);
|
void menu_change_layout (void);
|
||||||
|
void menu_update_quit_accel (void);
|
||||||
|
|
||||||
void menu_set_away (session_gui *gui, int away);
|
void menu_set_away (session_gui *gui, int away);
|
||||||
void menu_set_fullscreen (session_gui *gui, int fullscreen);
|
void menu_set_fullscreen (session_gui *gui, int fullscreen);
|
||||||
@@ -63,8 +64,9 @@ void menu_set_fullscreen (session_gui *gui, int fullscreen);
|
|||||||
#define MENU_ID_USERMENU 12
|
#define MENU_ID_USERMENU 12
|
||||||
#define MENU_ID_FULLSCREEN 13
|
#define MENU_ID_FULLSCREEN 13
|
||||||
#define MENU_ID_ZOITECHAT 14
|
#define MENU_ID_ZOITECHAT 14
|
||||||
|
#define MENU_ID_QUIT 15
|
||||||
|
|
||||||
#if (MENU_ID_NUM < MENU_ID_ZOITECHAT)
|
#if (MENU_ID_NUM < MENU_ID_QUIT)
|
||||||
#error MENU_ID_NUM is set wrong
|
#error MENU_ID_NUM is set wrong
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -964,7 +964,7 @@ tray_find_away_status (void)
|
|||||||
{
|
{
|
||||||
serv = list->data;
|
serv = list->data;
|
||||||
|
|
||||||
if (serv->is_away || serv->reconnect_away)
|
if (serv->is_away || serv->reconnect_away || serv->last_away_reason)
|
||||||
away++;
|
away++;
|
||||||
else
|
else
|
||||||
back++;
|
back++;
|
||||||
@@ -1090,7 +1090,6 @@ tray_menu_populate (GtkWidget *menu)
|
|||||||
{
|
{
|
||||||
GtkWidget *submenu;
|
GtkWidget *submenu;
|
||||||
GtkWidget *item;
|
GtkWidget *item;
|
||||||
int away_status;
|
|
||||||
|
|
||||||
/* ph may have an invalid context now */
|
/* ph may have an invalid context now */
|
||||||
zoitechat_set_context (ph, zoitechat_find_context (ph, NULL, NULL));
|
zoitechat_set_context (ph, zoitechat_find_context (ph, NULL, NULL));
|
||||||
@@ -1113,13 +1112,8 @@ tray_menu_populate (GtkWidget *menu)
|
|||||||
submenu = menu;
|
submenu = menu;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
away_status = tray_find_away_status ();
|
|
||||||
item = tray_make_item (submenu, _("_Away"), tray_foreach_server, "away");
|
item = tray_make_item (submenu, _("_Away"), tray_foreach_server, "away");
|
||||||
if (away_status == 1)
|
|
||||||
gtk_widget_set_sensitive (item, FALSE);
|
|
||||||
item = tray_make_item (submenu, _("_Back"), tray_foreach_server, "back");
|
item = tray_make_item (submenu, _("_Back"), tray_foreach_server, "back");
|
||||||
if (away_status == 2)
|
|
||||||
gtk_widget_set_sensitive (item, FALSE);
|
|
||||||
|
|
||||||
menu_add_plugin_items (menu, "\x5$TRAY", NULL);
|
menu_add_plugin_items (menu, "\x5$TRAY", NULL);
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <gdk/gdkkeysyms.h>
|
#include <gdk/gdkkeysyms.h>
|
||||||
|
|
||||||
@@ -89,6 +90,9 @@ static GtkWidget *edit_label_nick2;
|
|||||||
static GtkWidget *edit_label_real;
|
static GtkWidget *edit_label_real;
|
||||||
static GtkWidget *edit_label_user;
|
static GtkWidget *edit_label_user;
|
||||||
static GtkWidget *edit_trees[N_TREES];
|
static GtkWidget *edit_trees[N_TREES];
|
||||||
|
static GtkWidget *edit_button_cert_generate;
|
||||||
|
static GtkWidget *edit_button_cert_info;
|
||||||
|
static GtkWidget *edit_button_cert_delete;
|
||||||
|
|
||||||
static ircnet *selected_net = NULL;
|
static ircnet *selected_net = NULL;
|
||||||
static ircserver *selected_serv = NULL;
|
static ircserver *selected_serv = NULL;
|
||||||
@@ -99,6 +103,281 @@ static session *servlist_sess;
|
|||||||
static void servlist_network_row_cb (GtkTreeSelection *sel, gpointer user_data);
|
static void servlist_network_row_cb (GtkTreeSelection *sel, gpointer user_data);
|
||||||
static GtkWidget *servlist_open_edit (GtkWidget *parent, ircnet *net);
|
static GtkWidget *servlist_open_edit (GtkWidget *parent, ircnet *net);
|
||||||
|
|
||||||
|
static char *
|
||||||
|
servlist_get_cert_file (ircnet *net)
|
||||||
|
{
|
||||||
|
if (!net || !net->name || !net->name[0])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_strdup_printf ("%s" G_DIR_SEPARATOR_S "certs" G_DIR_SEPARATOR_S "%s.pem",
|
||||||
|
get_xdir (), net->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
servlist_network_cert_exists (ircnet *net)
|
||||||
|
{
|
||||||
|
char *cert_file;
|
||||||
|
gboolean exists;
|
||||||
|
|
||||||
|
cert_file = servlist_get_cert_file (net);
|
||||||
|
if (!cert_file)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
exists = g_file_test (cert_file, G_FILE_TEST_IS_REGULAR);
|
||||||
|
g_free (cert_file);
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
servlist_update_cert_buttons (ircnet *net)
|
||||||
|
{
|
||||||
|
gboolean has_cert = servlist_network_cert_exists (net);
|
||||||
|
|
||||||
|
if (edit_button_cert_generate)
|
||||||
|
gtk_widget_set_visible (edit_button_cert_generate, !has_cert);
|
||||||
|
if (edit_button_cert_info)
|
||||||
|
gtk_widget_set_visible (edit_button_cert_info, has_cert);
|
||||||
|
if (edit_button_cert_delete)
|
||||||
|
gtk_widget_set_visible (edit_button_cert_delete, has_cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
servlist_generate_client_cert_cb (GtkWidget *button, gpointer userdata)
|
||||||
|
{
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
ircnet *net = (ircnet *)userdata;
|
||||||
|
GtkWidget *dialog;
|
||||||
|
char *cert_dir;
|
||||||
|
char *cert_file;
|
||||||
|
char *key_file;
|
||||||
|
char *crt_file;
|
||||||
|
char *subject;
|
||||||
|
char *openssl_conf;
|
||||||
|
const char *conf_data;
|
||||||
|
char *key_data;
|
||||||
|
char *crt_data;
|
||||||
|
char *pem_data;
|
||||||
|
char *stderr_data;
|
||||||
|
char *stdout_data;
|
||||||
|
gsize key_len;
|
||||||
|
gsize crt_len;
|
||||||
|
gboolean spawned;
|
||||||
|
gboolean success;
|
||||||
|
gint status;
|
||||||
|
char *argv[20];
|
||||||
|
|
||||||
|
if (!net || !net->name || !net->name[0])
|
||||||
|
return;
|
||||||
|
|
||||||
|
cert_dir = g_build_filename (get_xdir (), "certs", NULL);
|
||||||
|
cert_file = servlist_get_cert_file (net);
|
||||||
|
key_file = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s.key", cert_dir, net->name);
|
||||||
|
crt_file = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s.crt", cert_dir, net->name);
|
||||||
|
subject = g_strdup_printf ("/CN=%s", net->name);
|
||||||
|
openssl_conf = g_build_filename (cert_dir, "openssl.cnf", NULL);
|
||||||
|
conf_data = "[req]\n"
|
||||||
|
"distinguished_name=req_distinguished_name\n"
|
||||||
|
"[req_distinguished_name]\n";
|
||||||
|
key_data = NULL;
|
||||||
|
crt_data = NULL;
|
||||||
|
pem_data = NULL;
|
||||||
|
stderr_data = NULL;
|
||||||
|
stdout_data = NULL;
|
||||||
|
key_len = 0;
|
||||||
|
crt_len = 0;
|
||||||
|
success = FALSE;
|
||||||
|
status = 0;
|
||||||
|
|
||||||
|
if (g_mkdir_with_parents (cert_dir, 0700) == 0 &&
|
||||||
|
g_file_set_contents (openssl_conf, conf_data, -1, NULL))
|
||||||
|
{
|
||||||
|
argv[0] = "openssl";
|
||||||
|
argv[1] = "req";
|
||||||
|
argv[2] = "-x509";
|
||||||
|
argv[3] = "-newkey";
|
||||||
|
argv[4] = "ec";
|
||||||
|
argv[5] = "-pkeyopt";
|
||||||
|
argv[6] = "ec_paramgen_curve:P-256";
|
||||||
|
argv[7] = "-sha256";
|
||||||
|
argv[8] = "-days";
|
||||||
|
argv[9] = "3650";
|
||||||
|
argv[10] = "-nodes";
|
||||||
|
argv[11] = "-keyout";
|
||||||
|
argv[12] = key_file;
|
||||||
|
argv[13] = "-out";
|
||||||
|
argv[14] = crt_file;
|
||||||
|
argv[15] = "-config";
|
||||||
|
argv[16] = openssl_conf;
|
||||||
|
argv[17] = "-subj";
|
||||||
|
argv[18] = subject;
|
||||||
|
argv[19] = NULL;
|
||||||
|
|
||||||
|
spawned = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
||||||
|
&stdout_data, &stderr_data, &status, NULL);
|
||||||
|
if (spawned && g_spawn_check_exit_status (status, NULL) &&
|
||||||
|
g_file_get_contents (key_file, &key_data, &key_len, NULL) &&
|
||||||
|
g_file_get_contents (crt_file, &crt_data, &crt_len, NULL))
|
||||||
|
{
|
||||||
|
pem_data = g_strconcat (key_data, crt_data, NULL);
|
||||||
|
if (pem_data && g_file_set_contents (cert_file, pem_data, -1, NULL))
|
||||||
|
{
|
||||||
|
chmod (cert_file, 0600);
|
||||||
|
success = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_remove (key_file);
|
||||||
|
g_remove (crt_file);
|
||||||
|
g_remove (openssl_conf);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
servlist_update_cert_buttons (net);
|
||||||
|
dialog = gtk_message_dialog_new (GTK_WINDOW (edit_win),
|
||||||
|
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
||||||
|
GTK_MESSAGE_INFO,
|
||||||
|
GTK_BUTTONS_CLOSE,
|
||||||
|
_("Client certificate generated for \"%s\"."),
|
||||||
|
net->name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dialog = gtk_message_dialog_new (GTK_WINDOW (edit_win),
|
||||||
|
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
||||||
|
GTK_MESSAGE_ERROR,
|
||||||
|
GTK_BUTTONS_CLOSE,
|
||||||
|
_("Failed to generate the client certificate for \"%s\"."),
|
||||||
|
net->name);
|
||||||
|
if (stderr_data && stderr_data[0])
|
||||||
|
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", stderr_data);
|
||||||
|
}
|
||||||
|
theme_manager_attach_window (dialog);
|
||||||
|
g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog);
|
||||||
|
gtk_widget_show (dialog);
|
||||||
|
|
||||||
|
g_free (stdout_data);
|
||||||
|
g_free (stderr_data);
|
||||||
|
g_free (pem_data);
|
||||||
|
g_free (key_data);
|
||||||
|
g_free (crt_data);
|
||||||
|
g_free (subject);
|
||||||
|
g_free (crt_file);
|
||||||
|
g_free (key_file);
|
||||||
|
g_free (openssl_conf);
|
||||||
|
g_free (cert_file);
|
||||||
|
g_free (cert_dir);
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
servlist_cert_info_cb (GtkWidget *button, gpointer userdata)
|
||||||
|
{
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
ircnet *net = (ircnet *)userdata;
|
||||||
|
GtkWidget *dialog;
|
||||||
|
char *cert_file;
|
||||||
|
char *stdout_data;
|
||||||
|
char *stderr_data;
|
||||||
|
gboolean spawned;
|
||||||
|
gint status;
|
||||||
|
char *argv[12];
|
||||||
|
|
||||||
|
cert_file = servlist_get_cert_file (net);
|
||||||
|
if (!cert_file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
stdout_data = NULL;
|
||||||
|
stderr_data = NULL;
|
||||||
|
status = 0;
|
||||||
|
argv[0] = "openssl";
|
||||||
|
argv[1] = "x509";
|
||||||
|
argv[2] = "-in";
|
||||||
|
argv[3] = cert_file;
|
||||||
|
argv[4] = "-noout";
|
||||||
|
argv[5] = "-subject";
|
||||||
|
argv[6] = "-issuer";
|
||||||
|
argv[7] = "-startdate";
|
||||||
|
argv[8] = "-enddate";
|
||||||
|
argv[9] = "-fingerprint";
|
||||||
|
argv[10] = "-sha256";
|
||||||
|
argv[11] = NULL;
|
||||||
|
|
||||||
|
spawned = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
||||||
|
&stdout_data, &stderr_data, &status, NULL);
|
||||||
|
|
||||||
|
if (spawned && g_spawn_check_exit_status (status, NULL) && stdout_data && stdout_data[0])
|
||||||
|
{
|
||||||
|
dialog = gtk_message_dialog_new (GTK_WINDOW (edit_win),
|
||||||
|
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
||||||
|
GTK_MESSAGE_INFO,
|
||||||
|
GTK_BUTTONS_CLOSE,
|
||||||
|
_("Client certificate information for \"%s\"."),
|
||||||
|
net->name);
|
||||||
|
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", stdout_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dialog = gtk_message_dialog_new (GTK_WINDOW (edit_win),
|
||||||
|
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
||||||
|
GTK_MESSAGE_ERROR,
|
||||||
|
GTK_BUTTONS_CLOSE,
|
||||||
|
_("Failed to read client certificate information for \"%s\"."),
|
||||||
|
net->name);
|
||||||
|
if (stderr_data && stderr_data[0])
|
||||||
|
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", stderr_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
theme_manager_attach_window (dialog);
|
||||||
|
g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog);
|
||||||
|
gtk_widget_show (dialog);
|
||||||
|
g_free (stdout_data);
|
||||||
|
g_free (stderr_data);
|
||||||
|
g_free (cert_file);
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
servlist_delete_client_cert_cb (GtkWidget *button, gpointer userdata)
|
||||||
|
{
|
||||||
|
ircnet *net = (ircnet *)userdata;
|
||||||
|
GtkWidget *dialog;
|
||||||
|
char *cert_file;
|
||||||
|
|
||||||
|
cert_file = servlist_get_cert_file (net);
|
||||||
|
if (!cert_file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (g_remove (cert_file) == 0)
|
||||||
|
{
|
||||||
|
servlist_update_cert_buttons (net);
|
||||||
|
dialog = gtk_message_dialog_new (GTK_WINDOW (edit_win),
|
||||||
|
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
||||||
|
GTK_MESSAGE_INFO,
|
||||||
|
GTK_BUTTONS_CLOSE,
|
||||||
|
_("Client certificate removed for \"%s\"."),
|
||||||
|
net->name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dialog = gtk_message_dialog_new (GTK_WINDOW (edit_win),
|
||||||
|
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
||||||
|
GTK_MESSAGE_ERROR,
|
||||||
|
GTK_BUTTONS_CLOSE,
|
||||||
|
_("Failed to remove client certificate for \"%s\"."),
|
||||||
|
net->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
theme_manager_attach_window (dialog);
|
||||||
|
g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog);
|
||||||
|
gtk_widget_show (dialog);
|
||||||
|
g_free (cert_file);
|
||||||
|
}
|
||||||
|
|
||||||
static GtkWidget *
|
static GtkWidget *
|
||||||
servlist_icon_button_new (const char *label, const char *icon_name)
|
servlist_icon_button_new (const char *label, const char *icon_name)
|
||||||
{
|
{
|
||||||
@@ -1783,6 +2062,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
|||||||
GtkWidget *buttonadd;
|
GtkWidget *buttonadd;
|
||||||
GtkWidget *buttonremove;
|
GtkWidget *buttonremove;
|
||||||
GtkWidget *buttonedit;
|
GtkWidget *buttonedit;
|
||||||
|
GtkWidget *hbox_cert_buttons;
|
||||||
GtkWidget *hseparator2;
|
GtkWidget *hseparator2;
|
||||||
GtkWidget *hbuttonbox4;
|
GtkWidget *hbuttonbox4;
|
||||||
GtkWidget *button10;
|
GtkWidget *button10;
|
||||||
@@ -1947,7 +2227,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
|||||||
|
|
||||||
|
|
||||||
/* Checkboxes and entries */
|
/* Checkboxes and entries */
|
||||||
table3 = gtkutil_grid_new (13, 2, FALSE);
|
table3 = gtkutil_grid_new (14, 2, FALSE);
|
||||||
gtk_box_pack_start (GTK_BOX (vbox5), table3, FALSE, FALSE, 0);
|
gtk_box_pack_start (GTK_BOX (vbox5), table3, FALSE, FALSE, 0);
|
||||||
gtk_grid_set_row_spacing (GTK_GRID (table3), 2);
|
gtk_grid_set_row_spacing (GTK_GRID (table3), 2);
|
||||||
gtk_grid_set_column_spacing (GTK_GRID (table3), 8);
|
gtk_grid_set_column_spacing (GTK_GRID (table3), 8);
|
||||||
@@ -2002,6 +2282,27 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
|||||||
SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL,
|
SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL,
|
||||||
4, 2);
|
4, 2);
|
||||||
|
|
||||||
|
hbox_cert_buttons = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 6);
|
||||||
|
edit_button_cert_generate = gtk_button_new_with_mnemonic (_("Generate client SSL cert"));
|
||||||
|
g_signal_connect (G_OBJECT (edit_button_cert_generate), "clicked",
|
||||||
|
G_CALLBACK (servlist_generate_client_cert_cb), net);
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox_cert_buttons), edit_button_cert_generate, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
edit_button_cert_info = gtk_button_new_with_mnemonic (_("Client SSL cert info"));
|
||||||
|
g_signal_connect (G_OBJECT (edit_button_cert_info), "clicked",
|
||||||
|
G_CALLBACK (servlist_cert_info_cb), net);
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox_cert_buttons), edit_button_cert_info, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
edit_button_cert_delete = gtk_button_new_with_mnemonic (_("Delete cert"));
|
||||||
|
g_signal_connect (G_OBJECT (edit_button_cert_delete), "clicked",
|
||||||
|
G_CALLBACK (servlist_delete_client_cert_cb), net);
|
||||||
|
gtk_box_pack_start (GTK_BOX (hbox_cert_buttons), edit_button_cert_delete, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
servlist_table_attach (table3, hbox_cert_buttons, 0, 2, 13, 14,
|
||||||
|
FALSE, FALSE,
|
||||||
|
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
|
||||||
|
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
|
||||||
|
|
||||||
|
|
||||||
/* Rule and Close button */
|
/* Rule and Close button */
|
||||||
hseparator2 = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
|
hseparator2 = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
|
||||||
@@ -2026,6 +2327,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
|||||||
gtk_widget_grab_default (button10);
|
gtk_widget_grab_default (button10);
|
||||||
|
|
||||||
gtk_widget_show_all (editwindow);
|
gtk_widget_show_all (editwindow);
|
||||||
|
servlist_update_cert_buttons (net);
|
||||||
|
|
||||||
/* We can't set the active tab without child elements being shown, so this must be *after* gtk_widget_show()s! */
|
/* We can't set the active tab without child elements being shown, so this must be *after* gtk_widget_show()s! */
|
||||||
gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), netedit_active_tab);
|
gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), netedit_active_tab);
|
||||||
|
|||||||
@@ -536,6 +536,7 @@ static const setting general_settings[] =
|
|||||||
{ST_TOGGLE, N_("WHOIS on notify"), P_OFFINTNL(hex_notify_whois_online), N_("Sends a /WHOIS when a user comes online in your notify list."), 0, 0},
|
{ST_TOGGLE, N_("WHOIS on notify"), P_OFFINTNL(hex_notify_whois_online), N_("Sends a /WHOIS when a user comes online in your notify list."), 0, 0},
|
||||||
{ST_TOGGLE, N_("Hide join and part messages"), P_OFFINTNL(hex_irc_conf_mode), N_("Hide channel join/part messages by default."), 0, 0},
|
{ST_TOGGLE, N_("Hide join and part messages"), P_OFFINTNL(hex_irc_conf_mode), N_("Hide channel join/part messages by default."), 0, 0},
|
||||||
{ST_TOGGLE, N_("Hide nick change messages"), P_OFFINTNL(hex_irc_hide_nickchange), 0, 0, 0},
|
{ST_TOGGLE, N_("Hide nick change messages"), P_OFFINTNL(hex_irc_hide_nickchange), 0, 0, 0},
|
||||||
|
{ST_TOGGLE, N_("Enable Ctrl+Q to quit"), P_OFFINTNL(hex_gui_ctrlq_quit), 0, 0, 0},
|
||||||
|
|
||||||
{ST_END, 0, 0, 0, 0, 0}
|
{ST_END, 0, 0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
@@ -2070,6 +2071,7 @@ setup_apply_real (const ThemeChangedEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mg_apply_setup ();
|
mg_apply_setup ();
|
||||||
|
menu_update_quit_accel ();
|
||||||
tray_apply_setup ();
|
tray_apply_setup ();
|
||||||
zoitechat_reinit_timers ();
|
zoitechat_reinit_timers ();
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ static void sexy_spell_entry_finalize(GObject *obj);
|
|||||||
static void sexy_spell_entry_destroy(GObject *obj);
|
static void sexy_spell_entry_destroy(GObject *obj);
|
||||||
static gboolean sexy_spell_entry_draw(GtkWidget *widget, cairo_t *cr);
|
static gboolean sexy_spell_entry_draw(GtkWidget *widget, cairo_t *cr);
|
||||||
static gint sexy_spell_entry_button_press(GtkWidget *widget, GdkEventButton *event);
|
static gint sexy_spell_entry_button_press(GtkWidget *widget, GdkEventButton *event);
|
||||||
|
static void sexy_spell_entry_style_updated (GtkWidget *widget);
|
||||||
|
|
||||||
/* GtkEditable handlers */
|
/* GtkEditable handlers */
|
||||||
static void sexy_spell_entry_changed(GtkEditable *editable, gpointer data);
|
static void sexy_spell_entry_changed(GtkEditable *editable, gpointer data);
|
||||||
@@ -280,6 +281,7 @@ sexy_spell_entry_class_init(SexySpellEntryClass *klass)
|
|||||||
|
|
||||||
widget_class->draw = sexy_spell_entry_draw;
|
widget_class->draw = sexy_spell_entry_draw;
|
||||||
widget_class->button_press_event = sexy_spell_entry_button_press;
|
widget_class->button_press_event = sexy_spell_entry_button_press;
|
||||||
|
widget_class->style_updated = sexy_spell_entry_style_updated;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SexySpellEntry::word-check:
|
* SexySpellEntry::word-check:
|
||||||
@@ -348,24 +350,54 @@ gtk_entry_find_position (GtkEntry *entry, gint x)
|
|||||||
static void
|
static void
|
||||||
insert_hiddenchar (SexySpellEntry *entry, guint start, guint end)
|
insert_hiddenchar (SexySpellEntry *entry, guint start, guint end)
|
||||||
{
|
{
|
||||||
/* FIXME: Pango does not properly reflect the new widths after a char
|
|
||||||
* is 'hidden' */
|
|
||||||
#if 0
|
|
||||||
PangoAttribute *hattr;
|
PangoAttribute *hattr;
|
||||||
PangoRectangle *rect = g_new (PangoRectangle, 1);
|
PangoRectangle rect = { 0 };
|
||||||
|
|
||||||
rect->x = 0;
|
hattr = pango_attr_shape_new (&rect, &rect);
|
||||||
rect->y = 0;
|
|
||||||
rect->width = 0;
|
|
||||||
rect->height = 0;
|
|
||||||
|
|
||||||
hattr = pango_attr_shape_new (rect, rect);
|
|
||||||
hattr->start_index = start;
|
hattr->start_index = start;
|
||||||
hattr->end_index = end;
|
hattr->end_index = end;
|
||||||
pango_attr_list_insert (entry->priv->attr_list, hattr);
|
pango_attr_list_insert (entry->priv->attr_list, hattr);
|
||||||
|
}
|
||||||
|
|
||||||
g_free (rect);
|
static guint8
|
||||||
#endif
|
sexy_spell_entry_contrasting_caret_component (guint16 red, guint16 green, guint16 blue)
|
||||||
|
{
|
||||||
|
const guint16 luma = (guint16) (((red >> 8) * 299 + (green >> 8) * 587 + (blue >> 8) * 114) / 1000);
|
||||||
|
return luma >= 128 ? 0x00 : 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sexy_spell_entry_apply_caret_style (SexySpellEntry *entry)
|
||||||
|
{
|
||||||
|
ThemeWidgetStyleValues style_values;
|
||||||
|
guint16 bg_red = 0, bg_green = 0, bg_blue = 0;
|
||||||
|
guint8 caret;
|
||||||
|
GtkCssProvider *provider;
|
||||||
|
GtkStyleContext *context;
|
||||||
|
char css[120];
|
||||||
|
|
||||||
|
theme_get_widget_style_values_for_widget (GTK_WIDGET (entry), &style_values);
|
||||||
|
theme_palette_color_get_rgb16 (&style_values.background, &bg_red, &bg_green, &bg_blue);
|
||||||
|
caret = sexy_spell_entry_contrasting_caret_component (bg_red, bg_green, bg_blue);
|
||||||
|
provider = g_object_get_data (G_OBJECT (entry), "sexy-spell-entry-caret-provider");
|
||||||
|
if (!provider)
|
||||||
|
{
|
||||||
|
provider = gtk_css_provider_new ();
|
||||||
|
g_object_set_data_full (G_OBJECT (entry), "sexy-spell-entry-caret-provider", provider, g_object_unref);
|
||||||
|
}
|
||||||
|
g_snprintf (css, sizeof (css), "#zoitechat-inputbox, #zoitechat-inputbox text { caret-color: #%02x%02x%02x; }",
|
||||||
|
caret, caret, caret);
|
||||||
|
gtk_css_provider_load_from_data (provider, css, -1, NULL);
|
||||||
|
context = gtk_widget_get_style_context (GTK_WIDGET (entry));
|
||||||
|
gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sexy_spell_entry_style_updated (GtkWidget *widget)
|
||||||
|
{
|
||||||
|
GTK_WIDGET_CLASS (parent_class)->style_updated (widget);
|
||||||
|
if (SEXY_IS_SPELL_ENTRY (widget))
|
||||||
|
sexy_spell_entry_apply_caret_style (SEXY_SPELL_ENTRY (widget));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -878,6 +910,7 @@ sexy_spell_entry_init(SexySpellEntry *entry)
|
|||||||
g_signal_connect(G_OBJECT(entry), "popup-menu", G_CALLBACK(sexy_spell_entry_popup_menu), entry);
|
g_signal_connect(G_OBJECT(entry), "popup-menu", G_CALLBACK(sexy_spell_entry_popup_menu), entry);
|
||||||
g_signal_connect(G_OBJECT(entry), "populate-popup", G_CALLBACK(sexy_spell_entry_populate_popup), NULL);
|
g_signal_connect(G_OBJECT(entry), "populate-popup", G_CALLBACK(sexy_spell_entry_populate_popup), NULL);
|
||||||
g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(sexy_spell_entry_changed), NULL);
|
g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(sexy_spell_entry_changed), NULL);
|
||||||
|
sexy_spell_entry_apply_caret_style (entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1089,6 +1122,7 @@ check_attributes (SexySpellEntry *entry, const char *text, int len)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ATTR_COLOR:
|
case ATTR_COLOR:
|
||||||
|
insert_hiddenchar (entry, i, i + 1);
|
||||||
parsing_color = 1;
|
parsing_color = 1;
|
||||||
offset = 1;
|
offset = 1;
|
||||||
break;
|
break;
|
||||||
@@ -1102,6 +1136,7 @@ check_color:
|
|||||||
{
|
{
|
||||||
if (text[i] == ',' && parsing_color <= 3)
|
if (text[i] == ',' && parsing_color <= 3)
|
||||||
{
|
{
|
||||||
|
insert_hiddenchar (entry, i, i + 1);
|
||||||
parsing_color = 3;
|
parsing_color = 3;
|
||||||
offset++;
|
offset++;
|
||||||
continue;
|
continue;
|
||||||
@@ -1118,21 +1153,25 @@ check_color:
|
|||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
fg_color[0] = text[i];
|
fg_color[0] = text[i];
|
||||||
|
insert_hiddenchar (entry, i, i + 1);
|
||||||
parsing_color++;
|
parsing_color++;
|
||||||
offset++;
|
offset++;
|
||||||
continue;
|
continue;
|
||||||
case 2:
|
case 2:
|
||||||
fg_color[1] = text[i];
|
fg_color[1] = text[i];
|
||||||
|
insert_hiddenchar (entry, i, i + 1);
|
||||||
parsing_color++;
|
parsing_color++;
|
||||||
offset++;
|
offset++;
|
||||||
continue;
|
continue;
|
||||||
case 3:
|
case 3:
|
||||||
bg_color[0] = text[i];
|
bg_color[0] = text[i];
|
||||||
|
insert_hiddenchar (entry, i, i + 1);
|
||||||
parsing_color++;
|
parsing_color++;
|
||||||
offset++;
|
offset++;
|
||||||
continue;
|
continue;
|
||||||
case 4:
|
case 4:
|
||||||
bg_color[1] = text[i];
|
bg_color[1] = text[i];
|
||||||
|
insert_hiddenchar (entry, i, i + 1);
|
||||||
parsing_color++;
|
parsing_color++;
|
||||||
offset++;
|
offset++;
|
||||||
continue;
|
continue;
|
||||||
@@ -1162,13 +1201,31 @@ check_color:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parsing_color)
|
||||||
|
{
|
||||||
|
if (bg_color[0] != 0)
|
||||||
|
{
|
||||||
|
insert_hiddenchar (entry, len - offset, len);
|
||||||
|
insert_color (entry, len, atoi (fg_color), atoi (bg_color));
|
||||||
|
}
|
||||||
|
else if (fg_color[0] != 0)
|
||||||
|
{
|
||||||
|
insert_hiddenchar (entry, len - offset, len);
|
||||||
|
insert_color (entry, len, atoi (fg_color), -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
insert_hiddenchar (entry, len - offset, len - offset + 1);
|
||||||
|
insert_color (entry, len, -1, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
attr_list_has_attrs (PangoAttrList *attrs)
|
attr_list_has_attrs (PangoAttrList *attrs)
|
||||||
{
|
{
|
||||||
PangoAttrIterator *it;
|
PangoAttrIterator *it;
|
||||||
GSList *list;
|
|
||||||
gboolean has = FALSE;
|
gboolean has = FALSE;
|
||||||
|
|
||||||
if (!attrs)
|
if (!attrs)
|
||||||
@@ -1178,9 +1235,15 @@ attr_list_has_attrs (PangoAttrList *attrs)
|
|||||||
if (!it)
|
if (!it)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
list = pango_attr_iterator_get_attrs (it);
|
do
|
||||||
has = (list != NULL);
|
{
|
||||||
g_slist_free_full (list, (GDestroyNotify) pango_attribute_destroy);
|
GSList *list = pango_attr_iterator_get_attrs (it);
|
||||||
|
has = (list != NULL);
|
||||||
|
g_slist_free_full (list, (GDestroyNotify) pango_attribute_destroy);
|
||||||
|
if (has)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (pango_attr_iterator_next (it));
|
||||||
pango_attr_iterator_destroy (it);
|
pango_attr_iterator_destroy (it);
|
||||||
|
|
||||||
return has;
|
return has;
|
||||||
|
|||||||
@@ -102,6 +102,12 @@ theme_manager_save_preferences (void)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
theme_manager_dispatch_changed (ThemeChangedReason reasons)
|
||||||
|
{
|
||||||
|
(void)reasons;
|
||||||
|
}
|
||||||
|
|
||||||
ThemePaletteBehavior
|
ThemePaletteBehavior
|
||||||
theme_manager_get_userlist_palette_behavior (const PangoFontDescription *font_desc)
|
theme_manager_get_userlist_palette_behavior (const PangoFontDescription *font_desc)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,16 +26,29 @@
|
|||||||
#include "theme-runtime.h"
|
#include "theme-runtime.h"
|
||||||
#include "theme-gtk3.h"
|
#include "theme-gtk3.h"
|
||||||
#include "../maingui.h"
|
#include "../maingui.h"
|
||||||
|
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
extern char *theme_css_build_toplevel_classes (void) __attribute__ ((weak));
|
||||||
|
#else
|
||||||
|
extern char *theme_css_build_toplevel_classes (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char *
|
||||||
|
theme_application_build_toplevel_css (void)
|
||||||
|
{
|
||||||
|
if (theme_css_build_toplevel_classes)
|
||||||
|
return theme_css_build_toplevel_classes ();
|
||||||
|
|
||||||
|
return g_strdup ("");
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
theme_application_apply_windows_theme (gboolean dark)
|
theme_application_apply_toplevel_theme (gboolean dark)
|
||||||
{
|
{
|
||||||
GtkSettings *settings = gtk_settings_get_default ();
|
GtkSettings *settings = gtk_settings_get_default ();
|
||||||
static GtkCssProvider *win_theme_provider = NULL;
|
static GtkCssProvider *theme_provider = NULL;
|
||||||
static gboolean win_theme_provider_installed = FALSE;
|
static gboolean theme_provider_installed = FALSE;
|
||||||
GdkScreen *screen;
|
GdkScreen *screen;
|
||||||
gboolean prefer_dark = dark;
|
gboolean prefer_dark = dark;
|
||||||
char *css;
|
char *css;
|
||||||
@@ -56,33 +69,21 @@ theme_application_apply_windows_theme (gboolean dark)
|
|||||||
if (!screen)
|
if (!screen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (theme_gtk3_is_active ())
|
if (!theme_provider)
|
||||||
{
|
theme_provider = gtk_css_provider_new ();
|
||||||
if (win_theme_provider_installed && win_theme_provider)
|
|
||||||
{
|
|
||||||
gtk_style_context_remove_provider_for_screen (screen,
|
|
||||||
GTK_STYLE_PROVIDER (win_theme_provider));
|
|
||||||
win_theme_provider_installed = FALSE;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!win_theme_provider)
|
css = theme_application_build_toplevel_css ();
|
||||||
win_theme_provider = gtk_css_provider_new ();
|
gtk_css_provider_load_from_data (theme_provider, css, -1, NULL);
|
||||||
|
|
||||||
css = theme_css_build_toplevel_classes ();
|
|
||||||
gtk_css_provider_load_from_data (win_theme_provider, css, -1, NULL);
|
|
||||||
g_free (css);
|
g_free (css);
|
||||||
|
|
||||||
if (!win_theme_provider_installed)
|
if (!theme_provider_installed)
|
||||||
{
|
{
|
||||||
gtk_style_context_add_provider_for_screen (screen,
|
gtk_style_context_add_provider_for_screen (screen,
|
||||||
GTK_STYLE_PROVIDER (win_theme_provider),
|
GTK_STYLE_PROVIDER (theme_provider),
|
||||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 1);
|
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 1);
|
||||||
win_theme_provider_installed = TRUE;
|
theme_provider_installed = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
theme_application_apply_mode (unsigned int mode, gboolean *palette_changed)
|
theme_application_apply_mode (unsigned int mode, gboolean *palette_changed)
|
||||||
@@ -91,10 +92,7 @@ theme_application_apply_mode (unsigned int mode, gboolean *palette_changed)
|
|||||||
|
|
||||||
theme_runtime_load ();
|
theme_runtime_load ();
|
||||||
dark = theme_runtime_apply_mode (mode, palette_changed);
|
dark = theme_runtime_apply_mode (mode, palette_changed);
|
||||||
|
theme_application_apply_toplevel_theme (dark);
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
theme_application_apply_windows_theme (dark);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
theme_application_reload_input_style ();
|
theme_application_reload_input_style ();
|
||||||
|
|
||||||
|
|||||||
@@ -361,20 +361,22 @@ theme_css_build_toplevel_classes (void)
|
|||||||
"color: #f0f0f0;"
|
"color: #f0f0f0;"
|
||||||
"border-color: #202020;"
|
"border-color: #202020;"
|
||||||
"}"
|
"}"
|
||||||
"window.%s menubar, window.%s menubar:backdrop, window.%s menuitem, window.%s menuitem:backdrop {"
|
"window.%s menubar, window.%s menubar:backdrop, window.%s menubar box, window.%s menubar box:backdrop, window.%s menuitem, window.%s menuitem:backdrop {"
|
||||||
"background-color: #202020;"
|
"background-color: @theme_bg_color;"
|
||||||
"color: #f0f0f0;"
|
"background-image: none;"
|
||||||
"border-color: #202020;"
|
"color: @theme_fg_color;"
|
||||||
|
"border-color: @theme_bg_color;"
|
||||||
"}"
|
"}"
|
||||||
"window.%s, window.%s:backdrop, .%s {"
|
"window.%s, window.%s:backdrop, .%s {"
|
||||||
"background-color: #f6f6f6;"
|
"background-color: #f6f6f6;"
|
||||||
"color: #101010;"
|
"color: #101010;"
|
||||||
"border-color: #f6f6f6;"
|
"border-color: #f6f6f6;"
|
||||||
"}"
|
"}"
|
||||||
"window.%s menubar, window.%s menubar:backdrop, window.%s menuitem, window.%s menuitem:backdrop {"
|
"window.%s menubar, window.%s menubar:backdrop, window.%s menubar box, window.%s menubar box:backdrop, window.%s menuitem, window.%s menuitem:backdrop {"
|
||||||
"background-color: #f6f6f6;"
|
"background-color: @theme_bg_color;"
|
||||||
"color: #101010;"
|
"background-image: none;"
|
||||||
"border-color: #f6f6f6;"
|
"color: @theme_fg_color;"
|
||||||
|
"border-color: @theme_bg_color;"
|
||||||
"}",
|
"}",
|
||||||
theme_css_selector_dark_class,
|
theme_css_selector_dark_class,
|
||||||
theme_css_selector_dark_class,
|
theme_css_selector_dark_class,
|
||||||
@@ -383,6 +385,10 @@ theme_css_build_toplevel_classes (void)
|
|||||||
theme_css_selector_dark_class,
|
theme_css_selector_dark_class,
|
||||||
theme_css_selector_dark_class,
|
theme_css_selector_dark_class,
|
||||||
theme_css_selector_dark_class,
|
theme_css_selector_dark_class,
|
||||||
|
theme_css_selector_dark_class,
|
||||||
|
theme_css_selector_dark_class,
|
||||||
|
theme_css_selector_light_class,
|
||||||
|
theme_css_selector_light_class,
|
||||||
theme_css_selector_light_class,
|
theme_css_selector_light_class,
|
||||||
theme_css_selector_light_class,
|
theme_css_selector_light_class,
|
||||||
theme_css_selector_light_class,
|
theme_css_selector_light_class,
|
||||||
|
|||||||
@@ -216,8 +216,6 @@ theme_manager_queue_auto_refresh (GtkSettings *settings, GParamSpec *pspec, gpoi
|
|||||||
void
|
void
|
||||||
theme_manager_init (void)
|
theme_manager_init (void)
|
||||||
{
|
{
|
||||||
GtkSettings *settings;
|
|
||||||
|
|
||||||
if (!theme_manager_listeners)
|
if (!theme_manager_listeners)
|
||||||
theme_manager_listeners = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
|
theme_manager_listeners = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
|
||||||
theme_listener_free);
|
theme_listener_free);
|
||||||
@@ -225,21 +223,10 @@ theme_manager_init (void)
|
|||||||
if (!theme_manager_setup_listener_id)
|
if (!theme_manager_setup_listener_id)
|
||||||
theme_manager_setup_listener_id = theme_listener_register ("setup.apply", theme_manager_setup_apply_listener, NULL);
|
theme_manager_setup_listener_id = theme_listener_register ("setup.apply", theme_manager_setup_apply_listener, NULL);
|
||||||
|
|
||||||
settings = gtk_settings_get_default ();
|
fe_set_auto_dark_mode_state (FALSE);
|
||||||
if (settings)
|
|
||||||
fe_set_auto_dark_mode_state (theme_policy_system_prefers_dark ());
|
|
||||||
|
|
||||||
theme_application_apply_mode (prefs.hex_gui_dark_mode, NULL);
|
theme_application_apply_mode (prefs.hex_gui_dark_mode, NULL);
|
||||||
theme_gtk3_init ();
|
theme_gtk3_init ();
|
||||||
zoitechat_set_theme_post_apply_callback (theme_manager_handle_theme_applied);
|
zoitechat_set_theme_post_apply_callback (theme_manager_handle_theme_applied);
|
||||||
|
|
||||||
if (settings)
|
|
||||||
{
|
|
||||||
g_signal_connect (settings, "notify::gtk-application-prefer-dark-theme",
|
|
||||||
G_CALLBACK (theme_manager_queue_auto_refresh), NULL);
|
|
||||||
g_signal_connect (settings, "notify::gtk-theme-name",
|
|
||||||
G_CALLBACK (theme_manager_queue_auto_refresh), NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
@@ -494,7 +481,6 @@ theme_manager_apply_wayland_kde_csd (GtkWidget *window)
|
|||||||
static void
|
static void
|
||||||
theme_manager_apply_platform_window_theme (GtkWidget *window)
|
theme_manager_apply_platform_window_theme (GtkWidget *window)
|
||||||
{
|
{
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
GtkStyleContext *context;
|
GtkStyleContext *context;
|
||||||
gboolean dark;
|
gboolean dark;
|
||||||
|
|
||||||
@@ -516,6 +502,7 @@ theme_manager_apply_platform_window_theme (GtkWidget *window)
|
|||||||
gtk_style_context_remove_class (context, "zoitechat-light");
|
gtk_style_context_remove_class (context, "zoitechat-light");
|
||||||
gtk_style_context_add_class (context, dark ? "zoitechat-dark" : "zoitechat-light");
|
gtk_style_context_add_class (context, dark ? "zoitechat-dark" : "zoitechat-light");
|
||||||
}
|
}
|
||||||
|
#ifdef G_OS_WIN32
|
||||||
fe_win32_apply_native_titlebar (window, dark);
|
fe_win32_apply_native_titlebar (window, dark);
|
||||||
#else
|
#else
|
||||||
theme_manager_apply_wayland_kde_csd (window);
|
theme_manager_apply_wayland_kde_csd (window);
|
||||||
|
|||||||
@@ -27,38 +27,7 @@
|
|||||||
gboolean
|
gboolean
|
||||||
theme_policy_system_prefers_dark (void)
|
theme_policy_system_prefers_dark (void)
|
||||||
{
|
{
|
||||||
GtkSettings *settings = gtk_settings_get_default ();
|
return FALSE;
|
||||||
gboolean prefer_dark = FALSE;
|
|
||||||
char *theme_name = NULL;
|
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
gboolean have_win_pref = FALSE;
|
|
||||||
|
|
||||||
if (fe_win32_high_contrast_is_enabled ())
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
have_win_pref = fe_win32_try_get_system_dark (&prefer_dark);
|
|
||||||
if (!have_win_pref)
|
|
||||||
#endif
|
|
||||||
if (settings && g_object_class_find_property (G_OBJECT_GET_CLASS (settings),
|
|
||||||
"gtk-application-prefer-dark-theme"))
|
|
||||||
{
|
|
||||||
g_object_get (settings, "gtk-application-prefer-dark-theme", &prefer_dark, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settings && !prefer_dark)
|
|
||||||
{
|
|
||||||
g_object_get (settings, "gtk-theme-name", &theme_name, NULL);
|
|
||||||
if (theme_name)
|
|
||||||
{
|
|
||||||
char *lower = g_ascii_strdown (theme_name, -1);
|
|
||||||
if (g_str_has_suffix (lower, "-dark") || g_strrstr (lower, "dark"))
|
|
||||||
prefer_dark = TRUE;
|
|
||||||
g_free (lower);
|
|
||||||
g_free (theme_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return prefer_dark;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
|
|||||||
@@ -1350,6 +1350,19 @@ theme_preferences_gtk3_sync_remove_state (theme_preferences_ui *ui)
|
|||||||
gtk_widget_set_sensitive (ui->gtk3_remove, source == ZOITECHAT_GTK3_THEME_SOURCE_USER);
|
gtk_widget_set_sensitive (ui->gtk3_remove, source == ZOITECHAT_GTK3_THEME_SOURCE_USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
theme_preferences_gtk3_apply_and_refresh (GError **error)
|
||||||
|
{
|
||||||
|
if (!theme_gtk3_apply_current (error))
|
||||||
|
return FALSE;
|
||||||
|
theme_manager_dispatch_changed (THEME_CHANGED_REASON_THEME_PACK |
|
||||||
|
THEME_CHANGED_REASON_PALETTE |
|
||||||
|
THEME_CHANGED_REASON_WIDGET_STYLE |
|
||||||
|
THEME_CHANGED_REASON_USERLIST |
|
||||||
|
THEME_CHANGED_REASON_MODE);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
theme_preferences_gtk3_changed_cb (GtkComboBox *combo, gpointer user_data)
|
theme_preferences_gtk3_changed_cb (GtkComboBox *combo, gpointer user_data)
|
||||||
{
|
{
|
||||||
@@ -1380,7 +1393,7 @@ theme_preferences_gtk3_changed_cb (GtkComboBox *combo, gpointer user_data)
|
|||||||
ui->setup_prefs->hex_gui_gtk3_variant = prefs.hex_gui_gtk3_variant;
|
ui->setup_prefs->hex_gui_gtk3_variant = prefs.hex_gui_gtk3_variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selection_changed && !theme_gtk3_apply_current (&error))
|
if (selection_changed && !theme_preferences_gtk3_apply_and_refresh (&error))
|
||||||
{
|
{
|
||||||
theme_preferences_show_message (ui, GTK_MESSAGE_ERROR,
|
theme_preferences_show_message (ui, GTK_MESSAGE_ERROR,
|
||||||
error ? error->message : _("Failed to apply GTK3 theme."));
|
error ? error->message : _("Failed to apply GTK3 theme."));
|
||||||
@@ -1393,55 +1406,20 @@ theme_preferences_gtk3_changed_cb (GtkComboBox *combo, gpointer user_data)
|
|||||||
static GdkPixbuf *
|
static GdkPixbuf *
|
||||||
theme_preferences_load_thumbnail (const char *path)
|
theme_preferences_load_thumbnail (const char *path)
|
||||||
{
|
{
|
||||||
char *data = NULL;
|
|
||||||
gsize length = 0;
|
|
||||||
GdkPixbufLoader *loader;
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GdkPixbuf *pixbuf;
|
GdkPixbuf *pixbuf;
|
||||||
GdkPixbuf *scaled;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
|
|
||||||
if (!path || !g_file_get_contents (path, &data, &length, &error))
|
if (!path)
|
||||||
{
|
|
||||||
g_clear_error (&error);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
loader = gdk_pixbuf_loader_new ();
|
pixbuf = gdk_pixbuf_new_from_file_at_scale (path, 48, 48, TRUE, &error);
|
||||||
if (!gdk_pixbuf_loader_write (loader, (const guchar *) data, length, &error))
|
|
||||||
{
|
|
||||||
g_clear_error (&error);
|
|
||||||
g_object_unref (loader);
|
|
||||||
g_free (data);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (data);
|
|
||||||
|
|
||||||
if (!gdk_pixbuf_loader_close (loader, &error))
|
|
||||||
{
|
|
||||||
g_clear_error (&error);
|
|
||||||
g_object_unref (loader);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
|
|
||||||
if (!pixbuf)
|
if (!pixbuf)
|
||||||
{
|
{
|
||||||
g_object_unref (loader);
|
g_clear_error (&error);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
width = gdk_pixbuf_get_width (pixbuf);
|
return pixbuf;
|
||||||
height = gdk_pixbuf_get_height (pixbuf);
|
|
||||||
if (width > 48 || height > 48)
|
|
||||||
scaled = gdk_pixbuf_scale_simple (pixbuf, 48, 48, GDK_INTERP_BILINEAR);
|
|
||||||
else
|
|
||||||
scaled = gdk_pixbuf_copy (pixbuf);
|
|
||||||
|
|
||||||
g_object_unref (loader);
|
|
||||||
return scaled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -1557,7 +1535,7 @@ theme_preferences_populate_gtk3 (theme_preferences_ui *ui)
|
|||||||
g_free (final_id);
|
g_free (final_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (should_apply && !theme_gtk3_apply_current (&error))
|
if (should_apply && !theme_preferences_gtk3_apply_and_refresh (&error))
|
||||||
{
|
{
|
||||||
theme_preferences_show_message (ui, GTK_MESSAGE_ERROR,
|
theme_preferences_show_message (ui, GTK_MESSAGE_ERROR,
|
||||||
error ? error->message : _("Failed to apply GTK3 theme."));
|
error ? error->message : _("Failed to apply GTK3 theme."));
|
||||||
|
|||||||
@@ -44,14 +44,29 @@
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
COL_PIX=0, /* GdkPixbuf * */
|
COL_PIX=0, /* GdkPixbuf * */
|
||||||
COL_NICK=1, /* char * */
|
COL_PREFIX=1, /* char * */
|
||||||
COL_HOST=2, /* char * */
|
COL_NICK=2, /* char * */
|
||||||
COL_USER=3, /* struct User * */
|
COL_HOST=3, /* char * */
|
||||||
COL_GDKCOLOR=4 /* GdkRGBA */
|
COL_USER=4, /* struct User * */
|
||||||
|
COL_GDKCOLOR=5 /* GdkRGBA */
|
||||||
};
|
};
|
||||||
|
|
||||||
static void userlist_store_color (GtkListStore *store, GtkTreeIter *iter, ThemeSemanticToken token, gboolean has_token);
|
static void userlist_store_color (GtkListStore *store, GtkTreeIter *iter, ThemeSemanticToken token, gboolean has_token);
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
userlist_prefix_color (char prefix)
|
||||||
|
{
|
||||||
|
switch (prefix)
|
||||||
|
{
|
||||||
|
case '~': return "#d46a6a";
|
||||||
|
case '@': return "#5ea36a";
|
||||||
|
case '%': return "#d39a5f";
|
||||||
|
case '&': return "#79aecd";
|
||||||
|
case '+': return "#d2bf6a";
|
||||||
|
default: return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
userlist_column_width_notify_cb (GtkTreeViewColumn *column, GParamSpec *pspec, gpointer userdata)
|
userlist_column_width_notify_cb (GtkTreeViewColumn *column, GParamSpec *pspec, gpointer userdata)
|
||||||
{
|
{
|
||||||
@@ -500,6 +515,11 @@ fe_userlist_insert (session *sess, struct User *newuser, gboolean sel)
|
|||||||
GdkPixbuf *pix = get_user_icon (sess->server, newuser);
|
GdkPixbuf *pix = get_user_icon (sess->server, newuser);
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
char *nick;
|
char *nick;
|
||||||
|
char *nick_escaped;
|
||||||
|
char *prefix = NULL;
|
||||||
|
char *prefix_escaped;
|
||||||
|
char prefix_text[2];
|
||||||
|
const char *prefix_color;
|
||||||
ThemeSemanticToken nick_token = THEME_TOKEN_TEXT_FOREGROUND;
|
ThemeSemanticToken nick_token = THEME_TOKEN_TEXT_FOREGROUND;
|
||||||
gboolean have_nick_token = FALSE;
|
gboolean have_nick_token = FALSE;
|
||||||
|
|
||||||
@@ -519,30 +539,36 @@ fe_userlist_insert (session *sess, struct User *newuser, gboolean sel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nick = newuser->nick;
|
nick_escaped = g_markup_escape_text (newuser->nick, -1);
|
||||||
|
nick = nick_escaped;
|
||||||
if (!prefs.hex_gui_ulist_icons)
|
if (!prefs.hex_gui_ulist_icons)
|
||||||
{
|
{
|
||||||
nick = g_malloc (strlen (newuser->nick) + 2);
|
if (newuser->prefix[0] != '\0' && newuser->prefix[0] != ' ')
|
||||||
nick[0] = newuser->prefix[0];
|
{
|
||||||
if (nick[0] == '\0' || nick[0] == ' ')
|
prefix_text[0] = newuser->prefix[0];
|
||||||
strcpy (nick, newuser->nick);
|
prefix_text[1] = '\0';
|
||||||
else
|
prefix_escaped = g_markup_escape_text (prefix_text, -1);
|
||||||
strcpy (nick + 1, newuser->nick);
|
prefix_color = userlist_prefix_color (newuser->prefix[0]);
|
||||||
|
if (prefix_color)
|
||||||
|
prefix = g_strdup_printf ("<b><span foreground=\"%s\">%s</span></b>", prefix_color, prefix_escaped);
|
||||||
|
else
|
||||||
|
prefix = g_strdup_printf ("<b>%s</b>", prefix_escaped);
|
||||||
|
g_free (prefix_escaped);
|
||||||
|
}
|
||||||
pix = NULL;
|
pix = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, 0,
|
gtk_list_store_insert_with_values (GTK_LIST_STORE (model), &iter, 0,
|
||||||
COL_PIX, pix,
|
COL_PIX, pix,
|
||||||
|
COL_PREFIX, prefix,
|
||||||
COL_NICK, nick,
|
COL_NICK, nick,
|
||||||
COL_HOST, newuser->hostname,
|
COL_HOST, newuser->hostname,
|
||||||
COL_USER, newuser,
|
COL_USER, newuser,
|
||||||
-1);
|
-1);
|
||||||
userlist_store_color (GTK_LIST_STORE (model), &iter, nick_token, have_nick_token);
|
userlist_store_color (GTK_LIST_STORE (model), &iter, nick_token, have_nick_token);
|
||||||
|
|
||||||
if (!prefs.hex_gui_ulist_icons)
|
g_free (prefix);
|
||||||
{
|
g_free (nick_escaped);
|
||||||
g_free (nick);
|
|
||||||
}
|
|
||||||
|
|
||||||
userlist_row_map_set (sess, model, newuser, &iter);
|
userlist_row_map_set (sess, model, newuser, &iter);
|
||||||
|
|
||||||
@@ -671,8 +697,8 @@ userlist_create_model (session *sess)
|
|||||||
GtkTreeIterCompareFunc cmp_func;
|
GtkTreeIterCompareFunc cmp_func;
|
||||||
GtkSortType sort_type;
|
GtkSortType sort_type;
|
||||||
|
|
||||||
store = gtk_list_store_new (5, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
|
store = gtk_list_store_new (6, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
|
||||||
G_TYPE_POINTER, THEME_GTK_COLOR_TYPE);
|
G_TYPE_STRING, G_TYPE_POINTER, THEME_GTK_COLOR_TYPE);
|
||||||
|
|
||||||
switch (prefs.hex_gui_ulist_sort)
|
switch (prefs.hex_gui_ulist_sort)
|
||||||
{
|
{
|
||||||
@@ -717,19 +743,29 @@ userlist_add_columns (GtkTreeView * treeview)
|
|||||||
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
||||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
||||||
-1, NULL, renderer,
|
-1, NULL, renderer,
|
||||||
"pixbuf", 0, NULL);
|
"pixbuf", COL_PIX, NULL);
|
||||||
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 0);
|
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 0);
|
||||||
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
|
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
|
||||||
|
|
||||||
/* nick column */
|
/* nick column */
|
||||||
|
column = gtk_tree_view_column_new ();
|
||||||
|
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
|
||||||
|
|
||||||
|
renderer = gtk_cell_renderer_text_new ();
|
||||||
|
if (prefs.hex_gui_compact)
|
||||||
|
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 (column, renderer, FALSE);
|
||||||
|
gtk_tree_view_column_add_attribute (column, renderer, "markup", COL_PREFIX);
|
||||||
|
|
||||||
renderer = gtk_cell_renderer_text_new ();
|
renderer = gtk_cell_renderer_text_new ();
|
||||||
if (prefs.hex_gui_compact)
|
if (prefs.hex_gui_compact)
|
||||||
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
||||||
g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
||||||
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
||||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
gtk_tree_view_column_pack_start (column, renderer, TRUE);
|
||||||
-1, NULL, renderer,
|
gtk_tree_view_column_add_attribute (column, renderer, "markup", COL_NICK);
|
||||||
"text", 1, THEME_GTK_FOREGROUND_PROPERTY, 4, NULL);
|
gtk_tree_view_column_add_attribute (column, renderer, THEME_GTK_FOREGROUND_PROPERTY, COL_GDKCOLOR);
|
||||||
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 1);
|
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 1);
|
||||||
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
|
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
|
||||||
gtk_tree_view_column_set_expand (column, TRUE);
|
gtk_tree_view_column_set_expand (column, TRUE);
|
||||||
@@ -750,7 +786,7 @@ userlist_add_columns (GtkTreeView * treeview)
|
|||||||
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
||||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
||||||
-1, NULL, renderer,
|
-1, NULL, renderer,
|
||||||
"text", 2, NULL);
|
"text", COL_HOST, NULL);
|
||||||
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 2);
|
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 2);
|
||||||
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
|
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
|
||||||
gtk_tree_view_column_set_expand (column, TRUE);
|
gtk_tree_view_column_set_expand (column, TRUE);
|
||||||
|
|||||||
@@ -2640,6 +2640,11 @@ gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event)
|
|||||||
xtext->select_start_x = x;
|
xtext->select_start_x = x;
|
||||||
xtext->select_start_y = y;
|
xtext->select_start_y = y;
|
||||||
xtext->select_start_adj = xtext_adj_get_value (xtext->adj);
|
xtext->select_start_adj = xtext_adj_get_value (xtext->adj);
|
||||||
|
if (xtext->buffer->last_ent_start)
|
||||||
|
{
|
||||||
|
gtk_xtext_unselect (xtext);
|
||||||
|
xtext->mark_stamp = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#include <glib/gwin32.h>
|
||||||
#define STDIN_FILENO 0
|
#define STDIN_FILENO 0
|
||||||
#define STDOUT_FILENO 1
|
#define STDOUT_FILENO 1
|
||||||
#else
|
#else
|
||||||
@@ -478,9 +479,28 @@ fe_args (int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GOptionContext *context;
|
GOptionContext *context;
|
||||||
|
#ifdef WIN32
|
||||||
|
char *base_path = NULL;
|
||||||
|
char *locale_path = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_NLS
|
#ifdef ENABLE_NLS
|
||||||
|
#ifdef WIN32
|
||||||
|
base_path = g_win32_get_package_installation_directory_of_module (NULL);
|
||||||
|
if (base_path)
|
||||||
|
{
|
||||||
|
locale_path = g_build_filename (base_path, "share", "locale", NULL);
|
||||||
|
bindtextdomain (GETTEXT_PACKAGE, locale_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||||
|
}
|
||||||
|
g_free (locale_path);
|
||||||
|
g_free (base_path);
|
||||||
|
#else
|
||||||
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||||
|
#endif
|
||||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||||
textdomain (GETTEXT_PACKAGE);
|
textdomain (GETTEXT_PACKAGE);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ Root: HKCR; Subkey: "ZoiteChat.Theme\shell\open\command"; ValueType: string; Val
|
|||||||
[Run]
|
[Run]
|
||||||
Filename: "{app}\zoitechat.exe"; Description: "Run ZoiteChat after closing the Wizard"; Flags: nowait postinstall skipifsilent
|
Filename: "{app}\zoitechat.exe"; Description: "Run ZoiteChat after closing the Wizard"; Flags: nowait postinstall skipifsilent
|
||||||
Filename: "http://docs.zoitechat.org/en/latest/changelog.html"; Description: "See what's changed"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked
|
Filename: "http://docs.zoitechat.org/en/latest/changelog.html"; Description: "See what's changed"; Flags: shellexec runasoriginaluser postinstall skipifsilent unchecked
|
||||||
Filename: "{tmp}\vcredist.exe"; Parameters: "/install /quiet /norestart"; StatusMsg: "Installing Visual C++ Redistributable"; Components: deps\vcredist2015; Flags: skipifdoesntexist; Tasks: not portable
|
Filename: "{tmp}\vcredist.exe"; Parameters: "/install /quiet /norestart"; StatusMsg: "Installing Visual C++ Redistributable"; Components: deps\vcredist2015; Tasks: not portable
|
||||||
Filename: "{tmp}\perl.msi"; StatusMsg: "Installing Perl"; Components: langs\perl; Flags: shellexec skipifdoesntexist; Tasks: not portable
|
Filename: "{tmp}\perl.msi"; StatusMsg: "Installing Perl"; Components: langs\perl; 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.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
|
||||||
@@ -339,7 +339,7 @@ begin
|
|||||||
if not IsTaskSelected('portable') then
|
if not IsTaskSelected('portable') then
|
||||||
begin
|
begin
|
||||||
|
|
||||||
REDIST := 'https://github.com/ZoiteChat/gvsbuild/releases/download/zoitechat-2.18.0-pre4/vc_redist.x64.exe';
|
REDIST := 'https://aka.ms/vs/17/release/vc_redist.x64.exe';
|
||||||
PERL := 'https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_54201_64bit/strawberry-perl-5.42.0.1-64bit.msi';
|
PERL := 'https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_54201_64bit/strawberry-perl-5.42.0.1-64bit.msi';
|
||||||
PY3 := 'https://www.python.org/ftp/python/3.14.3/python-3.14.3-amd64.exe';
|
PY3 := 'https://www.python.org/ftp/python/3.14.3/python-3.14.3-amd64.exe';
|
||||||
SPELL := 'https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.16.2/ZoiteChat.Spelling.Dictionaries.r2.exe';
|
SPELL := 'https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.16.2/ZoiteChat.Spelling.Dictionaries.r2.exe';
|
||||||
@@ -387,6 +387,14 @@ begin
|
|||||||
WizardForm.TasksList.Checked[1] := False
|
WizardForm.TasksList.Checked[1] := False
|
||||||
MsgBox('Portable mode is only intended for use on portable drives and has been disabled.', mbInformation, MB_OK)
|
MsgBox('Portable mode is only intended for use on portable drives and has been disabled.', mbInformation, MB_OK)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if CurPageID = wpReady then
|
||||||
|
if IsComponentSelected('deps\vcredist2015') and not CheckVCInstall() and not FileExists(ExpandConstant('{tmp}\vcredist.exe')) then
|
||||||
|
begin
|
||||||
|
MsgBox('Visual C++ Redistributable could not be downloaded. Please retry setup or install it manually and rerun setup.', mbError, MB_OK);
|
||||||
|
Result := False;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.18.0~pre4
|
2.18.0~pre5
|
||||||
|
|||||||
Reference in New Issue
Block a user