28 Commits

Author SHA1 Message Date
0f3fffc728 Broaden GTK3 palette/state selector coveragez even more. 2026-04-10 15:40:58 -06:00
7261d8637d Expand palette CSS + selection state coverage 2026-04-10 14:12:14 -06:00
deepend-tildeclub
8a1e82986a Merge pull request #197 from ZoiteChat/pevents_import_from_hct
Import pevents from .hct too, show clearer result dialog
2026-04-09 13:23:17 -06:00
deepend-tildeclub
e8d421b3df Merge pull request #196 from ZoiteChat/topic_bar_height
Auto-size topic bar to wrapped text
2026-04-09 13:23:03 -06:00
cb2c09b2ba Import pevents from .hct too, show clearer result dialog 2026-04-09 12:30:23 -06:00
a14026f0d1 Add vertical padding to topic text view 2026-04-09 10:56:39 -06:00
e237df31f4 Auto-size topic bar to wrapped text 2026-04-09 10:03:59 -06:00
deepend-tildeclub
a9421c63a9 Merge pull request #195 from ZoiteChat/hct_import_support
Add .hct support to colors.conf import
2026-04-09 08:55:48 -06:00
4f2938d957 Add .hct support to colors.conf import 2026-04-08 17:47:51 -06:00
deepend-tildeclub
8fa9d3678b Merge pull request #194 from ZoiteChat/add-python-perl-lua-versions-to-installer
Label installer runtimes with exact versions
2026-04-07 09:16:41 -06:00
4bbc23c185 Label installer runtimes with exact versions 2026-04-07 08:42:23 -06:00
deepend-tildeclub
73733e4176 Merge pull request #193 from ZoiteChat/pasted_path_fix
Refine cmd-char parsing for pasted path text
2026-04-06 15:17:37 -06:00
9f8faf0a6e Refine cmd-char parsing for pasted path text mentioned at https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=897426 2026-04-06 14:26:47 -06:00
deepend-tildeclub
5ff704459c Merge pull request #192 from sney/use-appstream
Improve appstream metainfo validation
2026-04-06 14:00:52 -06:00
Jesse Rhodes
0ccc730d85 test: Validate plugin metainfo. 2026-04-05 10:35:54 -04:00
Jesse Rhodes
093ffe791e test: Switch to appstreamcli for metainfo validation. 2026-04-05 10:31:19 -04:00
b9ff051043 Drop forced bold from userlist prefixes 2026-04-03 08:15:38 -06:00
10b6d5927b Tighten tab layout, right-align close button 2026-04-03 07:54:01 -06:00
0052b6589e updated svg. removed unused svg files 2026-04-01 22:52:27 -06:00
51e9ac15df fix zoitechat.svg 2026-04-01 00:21:44 -06:00
deepend-tildeclub
4df579e0d3 Merge pull request #185 from ZoiteChat/improve-appimage-URI-folder-opening
Sanitize Linux open env for AppImage, add safer fallbacks
2026-04-01 00:15:53 -06:00
2cf69d2e67 Sanitize Linux open env for AppImage, add safer fallbacks 2026-03-31 23:26:40 -06:00
deepend-tildeclub
64bffd0dc8 Merge pull request #184 from ZoiteChat/add-gtk3-themes-windows-installer
Theme: Adding themes users can select at install time.
2026-03-31 19:38:40 -06:00
deepend-tildeclub
b451240dfd Merge pull request #181 from ZoiteChat/prefs-option-disable-tab-close-button
Add pref for tab close buttons
2026-03-31 19:30:26 -06:00
41cc1f617f Theme: Adding themes users can select at install time. 2026-03-31 19:28:45 -06:00
ed671eac25 Add pref for tab close buttons 2026-03-31 18:10:28 -06:00
9f2529adb6 Update all links to new domain. 2026-03-30 18:25:26 -06:00
deepend-tildeclub
3903d7b9e5 Change official documentation link in README
Updated the link for the official documentation from zoitechat.zoite.net to zoitechat.org.
2026-03-30 17:16:01 -06:00
24 changed files with 498 additions and 185 deletions

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
version="1.1"
width="0.213333in" height="0.213333in"
viewBox="0 0 64 64">
<defs>
</defs>
<image id="raster0"
x="0"
y="0"
width="64"
height="64"
opacity="1.000000"
href="data:image/png;base64,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" />
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
version="1.1"
width="0.213333in" height="0.213333in"
viewBox="0 0 64 64">
<defs>
</defs>
<image id="raster0"
x="0"
y="0"
width="64"
height="64"
opacity="1.000000"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IB2cksfwAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAADJpJREFUeNrdm310lNWdxz/3eZnMJJMJeSeBIO9CbCtlQUWksuvaetSuLVrkWLqIbttj7fGsaGu71V2ptbYe+3KsdNetdd2tdUUqKos9aHcLHiwKCSu0yItSggSESSIJyWTen/vbP2aSzJCZyUwSAuzvnOfceZ7nzr33972/t/u791GcLbrngK0wvCIC4gT4yezY2RiGOqONP9jqRrgcLfMQuQiR2Wi5AJEatIAIkiyT9360HEFkPyJ70NKM1tt48hPh8wYA9b3jNYjcjMj1aPlLROw+ZlMYJQsAZKgbQ8sWRDYispan5vjPSQDUI/6rEbkTkc+ixRiCqUIASC01IhvRsoZn5r5+TgCgHm2/AZEHEZlDFmZ8CmrdCq8NHlthGWCboBBEAC3EHU0sqolENcGwQ0fAoS3sZAMCRHahZTW/mvfy2QHg6+9+TFWWrqHE86lMMzbZragpUfg8Bm5bDcyqkPI7CUDGdxCPaXoCMT46FeNgZ4y4k1FKtiJyJ7++5E9jAoB6tM2SA8f+Ecv4tppeb6UO2gvM8CmqSw1clsrKmCR/qyEASAXKiQudXVFa/BH8Ied0NYmj5RFEf5fnF8TPHAB37mmgJ/wCjr5MzagDrwe0UKyExjKTGp+BoZIDdoRgSNMbcgiENcGIpiOiCcZ12iwaCHW2wmOB16XwFhkUewxsU6UBQFJVEKGrK8r7x8MJINLVYjsiX2DtgtbRB+Cruy+nJ7weoZZxxajp9SBCY4liUoWJZUA8rjnZ7dAWcDjc64zICI53KSaUmZSXWrhdagAABDSIaNraI+w+FiLqpP3fj8gS1l2+bfQAuLX5M4RiL6GUB6VQsydQ6ivmk1UGPo8iGNIc64zzXsBJMFSAZc/HC0wuNmiotCnzWv0AJHWJSNhhf0svrYF46n+CiCzhNwtfGzkAtzZfQzD6CuDCMMBbxKS5k2msMYnHhcMdcf7cm9Naj5obrC9STB9fhK/E6gcAEcQRPjgaZE9bJPU/UURuYP0Vm4YPwK3NCwlEfgd4MBQYBjM+Xsv0WVUc74yzu8sZym+PdhwAIsz0mUypd2P3G9qEepzwh2huDaXWDSFyNS8t+kPhAKzcOYmecBMiNSgFhmJGhYuGRdPY2wn+iM57wKMNAFooNmBug5txPivNPrS3h9l+OJhatw2R+bzyqSOZ2DQyMv/ICYtA+AUcXdP3aKrPomq8lzc7wB8TzjYFHeHNliBHj4cSrjRJ1ZVu5tYXpVatAV7gb7ZY+QPwzp/vJ+Zc2t+o28DrMXkrYHAO8J5Gu05EOfhBbyK2SFJ9XTGzKu3UapeC+k5+KrB8+2wCkV2AC6VQhmLyOBctPXHU7IlQXppFLDU48cJEOV8VyNmGAhQzfSYzJpegJOEhdFyzc+8p/MG+oElH0VzMxsX7U9kdLBa9kcfQ4sJIYOMxFS2nYmAo8BRlmQfhyN+VM7HKNaaz//6hD1n0D7vxmxW81yW4jgaZPKE4IdqGonFKCf53u/vm2gXyGHB9dhW4edtCYvra03Wtn4rsjAN5cLo15sy3Hj3B8vvW48cDKjFZe9qjtHcMpA5KSmwuqkkdl1zHdZsXZgcgGv92To9pZjYZX5hfPKbMt3V0svJb69ihZoJdkqbJTa0hQqGB5cDEOg9WuqJ/KzMAy9+eTMy5LmuvRmaPeUedYnaDe8yY7+4OcM/qdfxPZDq4yweZMS1w4HCw3zPYtkljbVG6FFz7+8mDAeiJ3IoUHjKtvHTsZr83GObeh57n2RP1UFwNKrNEHg06dJwcUIWaqqJ0ToQVgwHQclPO3vVgdD7vgzlTx2b2Y7E4P3j8JX7RUg0l47My30f7joXRSfvldls0eM1UKbgxfV5v3jaR7nArhqIv6kv7nSzVwsY0tyTxGHS0QE97ynMGL2PT7vtcWOL5Py0o5zt3XIVtW1mZiTsOP17zEve9ocB3AWDmFS1eeoGH6ooiEKGtLciOlt7U/iey6apjiV5D0UV5TUM0BikDVaYFVVOhcsoQ4a9OZ1wLiOarDRbf/MokbNvM2e0zz73OfVscGDcNlJVRGjPR4RPhBABAqXeQB1sEPG8kxfuSvAEYZBuMxGVkKZUBykxchtn/7kt1Nj+8rYHiotzMr3vlDb788ikonwaGXZDa+MOaYDAxZo/HwlRphmzegA0QZuUXgI9Oev6vfYof3VafXNZmp9c2N7P03z+E8hlgDi/OONUd61f2iaVpdmDWAABaj8+nMekOjZj5S9zw9O3jqSrLzdCO/93HNY/vg8rhMw/QdmpAakvcadJWPwCAaUzIq7XO3hExP8UUfn17LRNrcnuOP+09xKKH3oaqWWCNzMu0Bpz+hZKdHhFVDwDg6Mq8Wotr6AkOayAGwovLK5k2wZPbcB05zrKHthCtagTbM3J9E4hEnGQslwZAbaoNyL+9k93DGsXWZeXMmVGas9ax4+3c8sBv2ettBJd31DauolGdNbTrU4FT+StVDzi6oAFsuLaUBRf5cmtXVzdf+96rvOWaDW5f/wJnNMhJBkRa0ma6LVUFjuTdmhboyB+v5670cP1l5Tnr9ASCrHr4RTZEpoGn/IxtWsfj2QAwVHtBAn28MxHcDKF7T8xzsXRxbvMSjkS5/7H1PNMxEUqqzuiOfW/YSdWA46k2YH9hUGrE35mzysONFl+5pirbIjIR38fjPPYvG3n8cBWUTRgyvh+pMTwaSAWAAwMAKJoKbtB/CsLRjK++McXkns9VY5nZuXe05omnN/HALg+Mm5SIFEXS8v2JLSCdvRSdlwV3uQxC4Tjx9BC6aSAlZhpbieuCEZXWDtTU9BjqthrFA0sqE5ujuQxT3GHZDQtZ9nlXch5kUPtZbtJWiDc9sIOmiC+n6tgug67OyOmPtw4A8F+LW7j294eAqQWBEIoi/k5UbcLILS1X/GhZBV6Pmces2NTVlo9Iqnfs3EfTyQCUlGWtU2orXLaJ/2SatO5n01Wt6fkAxdphjeKjAHT1coUbfrq0PLl/Nzb0y7U7wF2R02VO8FlEIg4fdKcZwHWDEyKm+exwB3JxdxfPLvMxvsIeM+b37m/hX99VYOWOFsvLbNo6wukaoviPwQBsuHIvii2FDqTKhOdWTWFS7djlBQFe2NAEJXU5PYcCiost9vpT9V+9zm//6mDmrLBSDxdqCTfdfQGzp5aNKfNHj7WxenM3FOUOrS+stGlrDxNLt+/fz53q/OyWrSh1RaaUWCLJMfBsfilcMzMM8a701gwT5XKlGHAZKEmmyJKlpN6n1hOyPBPeaw2w9kQVFJUPpNwyZKTmN7hpOhxMTZ/9NxsXX03OnSFD3YWwM5+QrKkXmt5xJfYfT88n2haqrDixl5AjbycynK2xWuhb20tmF9ngNWltTxF9EQe4e+jN0VeufAfFT8j3hI2ywLTTL8MFYiLdUYiSSGiYLrCylENdxumlndPyKyDiCCdCOlW9H2Xj4j357Q5bxv3A3tEIPyUYQXqCEHPGzEYI0NbHfLENM2t3gawu7IDEkq0XIjRjKG82G5A9jW5kfmcaKMtM/JaRHZAYso7XlYhSa8pPEQzPlbsrDxV+RObGNz8NvIpS1qgA0F8aKEONPgAuE2p9qJpyKPOCIko4+hn5etmW4R+SuukPK1D8G0qp0QNAofraUgpIAuFoiDuJMh8A3DYUu1BeN/hKEucW+/oBh0Doi7Kqcu3Ij8kt3bYCeArDsEYdgExtKZXMN6jkqi85UtMEywTLAJc9oJan/1cRpTf0t7Kqau3oHZS8+a1Po9SLKOU94wCkqErufjIAINJN3Pmc3DVuc37J2nxp7YLXUcwH9nGukqP/SCjyF/kyXxgAAP952X5MNQ944pxiXESIx3/Mhx2XyT1VBxmT4/JfaroCpX6OUh8/qyoA7xCL3yHfqN7OmH8wsXLnhWj2nxUA4CAi35V7q341EhZGlr3QcssZ/u4qU59b0M4/y7H2dfzsYyM+tTh8AL62p4hA+Mtjwr/IDpANROU5ub+uZTSbtkaQZL8dqMujZhD4BYrpwBTgwsQRj8wJd+AAwiHgj2jdhKPflNUNH3FOfTa3orkCLe+jVMUQcUAvhrqOJxrfSOv03vfdKFWNUhWJqE0+EqGdH06LcF58OLm86TfAjUMEQq0YaglrLmrmHKbCt2K+uGMVMnDKKgus6zHUJ8915guXgFu2r0R4OrvrMvZiqm/y5Cde5Tyh/I3gsrfvQstPB2ViFIJSr6HUkzx18cucZ2TlwXgJWq9B6xWJwIQg8C6G2o1SmzHN3/HLOe2cpzS0Cvz9eybhcBVKCWXF7fxgmvD/iP4Ps1PbE8ZtV64AAAAASUVORK5CYIIA" />
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -13,10 +13,10 @@ if get_option('gtk-frontend')
install_dir: metainfodir install_dir: metainfodir
) )
appstream_util = find_program('appstream-util', required: false) appstreamcli = find_program('appstreamcli', required: false)
if appstream_util.found() if appstreamcli.found()
test('Validate net.zoite.Zoitechat.appdata.xml', appstream_util, test('Validate net.zoite.Zoitechat.appdata.xml', appstreamcli,
args: ['validate-relax', zoitechat_appdata] args: ['validate', zoitechat_appdata]
) )
endif endif
endif endif
@@ -97,11 +97,18 @@ if get_option('plugin')
conf.set('SUMMARY', metainfo[1]) conf.set('SUMMARY', metainfo[1])
conf.set('LICENSE', metainfo[2]) conf.set('LICENSE', metainfo[2])
configure_file( plugin_appdata = configure_file(
input: 'net.zoite.Zoitechat.Plugin.metainfo.xml.in', input: 'net.zoite.Zoitechat.Plugin.metainfo.xml.in',
output: 'net.zoite.Zoitechat.Plugin.@0@.metainfo.xml'.format(name), output: 'net.zoite.Zoitechat.Plugin.@0@.metainfo.xml'.format(name),
configuration: conf, configuration: conf,
install_dir: get_option('install-plugin-metainfo') ? metainfodir : '', install_dir: get_option('install-plugin-metainfo') ? metainfodir : '',
) )
if appstreamcli.found()
test('Validate net.zoite.Zoitechat.Plugin.@0@.metainfo.xml'.format(name), appstreamcli,
args: ['validate', plugin_appdata]
)
endif
endforeach endforeach
endif endif

View File

@@ -4,7 +4,7 @@
<extends>net.zoite.Zoitechat</extends> <extends>net.zoite.Zoitechat</extends>
<name>@NAME@ Plugin</name> <name>@NAME@ Plugin</name>
<summary>@SUMMARY@</summary> <summary>@SUMMARY@</summary>
<url type="homepage">https://zoitechat.zoite.net/</url> <url type="homepage">https://zoitechat.org/</url>
<project_license>@LICENSE@</project_license> <project_license>@LICENSE@</project_license>
<metadata_license>CC0-1.0</metadata_license> <metadata_license>CC0-1.0</metadata_license>
<update_contact>deepend_AT_zoite.net</update_contact> <update_contact>deepend_AT_zoite.net</update_contact>

View File

@@ -16,12 +16,12 @@
<p>ZoiteChat is an easy to use yet extensible IRC Client based on Hexchat. It allows you to securely join multiple networks and talk to users privately or in channels using a customizable interface. You can even transfer files.</p> <p>ZoiteChat is an easy to use yet extensible IRC Client based on Hexchat. It allows you to securely join multiple networks and talk to users privately or in channels using a customizable interface. You can even transfer files.</p>
<p>ZoiteChat supports features such as: DCC, SASL, proxies, spellcheck, alerts, logging, custom themes, and Python/Perl scripts.</p> <p>ZoiteChat supports features such as: DCC, SASL, proxies, spellcheck, alerts, logging, custom themes, and Python/Perl scripts.</p>
</description> </description>
<url type="homepage">https://zoitechat.zoite.net</url> <url type="homepage">https://zoitechat.org</url>
<url type="bugtracker">https://github.com/zoitechat/zoitechat</url> <url type="bugtracker">https://github.com/zoitechat/zoitechat</url>
<url type="help">https://docs.zoitechat.zoite.net/en/latest/</url> <url type="help">https://docs.zoitechat.org/en/latest/</url>
<screenshots> <screenshots>
<screenshot type="default"> <screenshot type="default">
<image>https://zoitechat.zoite.net/assets/ZoiteChat.png</image> <image>https://zoitechat.org/assets/ZoiteChat.png</image>
<caption>Main Chat Window</caption> <caption>Main Chat Window</caption>
</screenshot> </screenshot>
</screenshots> </screenshots>
@@ -100,14 +100,6 @@
</ul> </ul>
</description> </description>
</release> </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>

View File

@@ -1457,14 +1457,14 @@ perl_load_file (char *filename)
"You must have a Visual C++ build of Perl " "You must have a Visual C++ build of Perl "
PERL_REQUIRED_VERSION " installed in order to\n" PERL_REQUIRED_VERSION " installed in order to\n"
"run Perl scripts. A reboot may be required.\n\n" "run Perl scripts. A reboot may be required.\n\n"
"http://zoitechat.zoite.net/downloads.html\n\n" "http://zoitechat.org/downloads.html\n\n"
"I have found Perl 5.6, but that is too old."); "I have found Perl 5.6, but that is too old.");
} else { } else {
thread_mbox ("Cannot open " PERL_DLL "!\n\n" thread_mbox ("Cannot open " PERL_DLL "!\n\n"
"You must have a Visual C++ build of Perl " "You must have a Visual C++ build of Perl "
PERL_REQUIRED_VERSION " installed in order to\n" PERL_REQUIRED_VERSION " installed in order to\n"
"run Perl scripts. A reboot may be required.\n\n" "run Perl scripts. A reboot may be required.\n\n"
"http://zoitechat.zoite.net/downloads.html\n\n" "http://zoitechat.org/downloads.html\n\n"
"Make sure Perl's bin directory is in your PATH."); "Make sure Perl's bin directory is in your PATH.");
} }
} }

View File

@@ -24,7 +24,7 @@
#include "zoitechat-plugin.h" #include "zoitechat-plugin.h"
#define APPCAST_URL "https://zoitechat.zoite.net/appcast.xml" #define APPCAST_URL "https://zoitechat.org/appcast.xml"
static zoitechat_plugin *ph; static zoitechat_plugin *ph;
static char name[] = "Update Checker"; static char name[] = "Update Checker";

View File

@@ -8,7 +8,7 @@
[![Version][github-version-img]][github-version-uri] [![Downloads][github-downloads-img]][github-downloads-uri] [![Size][github-size-img]][github-size-img] [![Last Commit][github-commit-img]][github-commit-img] [![Contributors][contribs-all-img]](#contributors-) [![Version][github-version-img]][github-version-uri] [![Downloads][github-downloads-img]][github-downloads-uri] [![Size][github-size-img]][github-size-img] [![Last Commit][github-commit-img]][github-commit-img] [![Contributors][contribs-all-img]](#contributors-)
[![View Official Documentation](https://img.shields.io/badge/View_Official_Documentation-526CFE?style=for-the-badge&logo=MaterialForMkDocs&logoColor=white)](https://docs.zoitechat.zoite.net) [![View Official Documentation](https://img.shields.io/badge/View_Official_Documentation-526CFE?style=for-the-badge&logo=MaterialForMkDocs&logoColor=white)](https://docs.zoitechat.org)
</div> </div>
@@ -33,8 +33,8 @@
ZoiteChat is an HexChat based IRC client for Windows and UNIX-like operating systems. ZoiteChat is an HexChat based IRC client for Windows and UNIX-like operating systems.
See [IRCHelp.org](http://irchelp.org) for information about IRC in general. See [IRCHelp.org](http://irchelp.org) for information about IRC in general.
For more information on ZoiteChat please read our [documentation](https://docs.zoitechat.zoite.net/): For more information on ZoiteChat please read our [documentation](https://docs.zoitechat.org/):
- [Downloads](https://zoitechat.zoite.net/download) - [Downloads](https://zoitechat.org/download)
- [Troubleshooting](troubleshooting.md) - [Troubleshooting](troubleshooting.md)

View File

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

View File

@@ -1221,6 +1221,94 @@ extract_archive (const char *source, GError **error)
#endif #endif
} }
static char *
path_find_first_file_recursive (const char *root, const char *name, int depth)
{
GDir *dir;
const char *entry;
if (!root || !name || depth < 0 || !g_file_test (root, G_FILE_TEST_IS_DIR))
return NULL;
{
char *candidate = g_build_filename (root, name, NULL);
if (g_file_test (candidate, G_FILE_TEST_IS_REGULAR))
return candidate;
g_free (candidate);
}
if (depth == 0)
return NULL;
dir = g_dir_open (root, 0, NULL);
if (!dir)
return NULL;
while ((entry = g_dir_read_name (dir)) != NULL)
{
char *child = g_build_filename (root, entry, NULL);
char *found = NULL;
if (g_file_test (child, G_FILE_TEST_IS_DIR))
found = path_find_first_file_recursive (child, name, depth - 1);
g_free (child);
if (found)
{
g_dir_close (dir);
return found;
}
}
g_dir_close (dir);
return NULL;
}
gboolean
zoitechat_gtk3_theme_service_read_archive_text_file (const char *archive_path, const char *name, char **contents, GError **error)
{
char *root;
char *path;
gboolean ok;
GError *local_error = NULL;
if (contents)
*contents = NULL;
if (!archive_path || !*archive_path)
return g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "No archive path provided."), FALSE;
if (!name || !*name)
return g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "No file name provided."), FALSE;
if (!contents)
return g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "No output buffer provided."), FALSE;
root = extract_archive (archive_path, error);
if (!root)
return FALSE;
path = path_find_first_file_recursive (root, name, 8);
if (!path)
{
remove_tree (root);
g_free (root);
return g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, "Requested file was not found in archive."), FALSE;
}
ok = g_file_get_contents (path, contents, NULL, &local_error);
g_free (path);
remove_tree (root);
g_free (root);
if (!ok)
{
if (error)
*error = local_error;
else
g_clear_error (&local_error);
return FALSE;
}
return TRUE;
}
gboolean gboolean
zoitechat_gtk3_theme_service_import (const char *source_path, char **imported_id, GError **error) zoitechat_gtk3_theme_service_import (const char *source_path, char **imported_id, GError **error)
{ {

View File

@@ -48,5 +48,6 @@ gboolean zoitechat_gtk3_theme_service_remove_user_theme (const char *theme_id, G
char *zoitechat_gtk3_theme_pick_css_dir_for_minor (const char *theme_root, int preferred_minor); char *zoitechat_gtk3_theme_pick_css_dir_for_minor (const char *theme_root, int preferred_minor);
char *zoitechat_gtk3_theme_pick_css_dir (const char *theme_root); char *zoitechat_gtk3_theme_pick_css_dir (const char *theme_root);
GPtrArray *zoitechat_gtk3_theme_build_inheritance_chain (const char *theme_root); GPtrArray *zoitechat_gtk3_theme_build_inheritance_chain (const char *theme_root);
gboolean zoitechat_gtk3_theme_service_read_archive_text_file (const char *archive_path, const char *name, char **contents, GError **error);
#endif #endif

View File

@@ -4070,7 +4070,7 @@ const struct commands xc_cmds[] = {
{"ME", cmd_me, 0, 0, 1, {"ME", cmd_me, 0, 0, 1,
N_("ME <action>, sends the action to the current channel (actions are written in the 3rd person, like /me jumps)")}, N_("ME <action>, sends the action to the current channel (actions are written in the 3rd person, like /me jumps)")},
{"MENU", cmd_menu, 0, 0, 1, "MENU [-eX] [-i<ICONFILE>] [-k<mod>,<key>] [-m] [-pX] [-r<X,group>] [-tX] {ADD|DEL} <path> [command] [unselect command]\n" {"MENU", cmd_menu, 0, 0, 1, "MENU [-eX] [-i<ICONFILE>] [-k<mod>,<key>] [-m] [-pX] [-r<X,group>] [-tX] {ADD|DEL} <path> [command] [unselect command]\n"
" See https://docs.zoitechat.zoite.net/en/latest/en/latest/plugins.html#controlling-the-gui for more details."}, " See https://docs.zoitechat.org/en/latest/en/latest/plugins.html#controlling-the-gui for more details."},
{"MHOP", cmd_mhop, 1, 1, 1, {"MHOP", cmd_mhop, 1, 1, 1,
N_("MHOP, Mass hop's all users in the current channel (needs chanop)")}, N_("MHOP, Mass hop's all users in the current channel (needs chanop)")},
{"MKICK", cmd_mkick, 1, 1, 1, {"MKICK", cmd_mkick, 1, 1, 1,
@@ -4883,6 +4883,9 @@ xit:
static int static int
handle_user_input (session *sess, char *text, int history, int nocommand) handle_user_input (session *sess, char *text, int history, int nocommand)
{ {
char cmd_char = prefs.hex_input_command_char[0];
unsigned int i;
if (*text == '\0') if (*text == '\0')
return 1; return 1;
@@ -4890,50 +4893,22 @@ handle_user_input (session *sess, char *text, int history, int nocommand)
history_add (&sess->history, text); history_add (&sess->history, text);
/* is it NOT a command, just text? */ /* is it NOT a command, just text? */
if (nocommand || text[0] != prefs.hex_input_command_char[0]) if (nocommand || text[0] != cmd_char)
{ {
handle_say (sess, text, TRUE); handle_say (sess, text, TRUE);
return 1; return 1;
} }
/* check for // */ for (i = 1; text[i]; i++)
if (text[0] == prefs.hex_input_command_char[0] && text[1] == prefs.hex_input_command_char[0])
{ {
handle_say (sess, text + 1, TRUE); if (text[i] == cmd_char)
return 1;
}
#if 0 /* Who would remember all this? */
if (prefs.hex_input_command_char[0] == '/')
{
int i;
const char *unix_dirs [] = {
"/bin/",
"/boot/",
"/dev/",
"/etc/",
"/home/",
"/lib/",
"/lost+found/",
"/mnt/",
"/opt/",
"/proc/",
"/root/",
"/sbin/",
"/tmp/",
"/usr/",
"/var/",
"/gnome/",
NULL
};
for (i = 0; unix_dirs[i] != NULL; i++)
if (strncmp (text, unix_dirs[i], strlen (unix_dirs[i]))==0)
{ {
handle_say (sess, text, TRUE); handle_say (sess, text, TRUE);
return 1; return 1;
} }
if (text[i] == ' ')
break;
} }
#endif
return handle_command (sess, text + 1, TRUE); return handle_command (sess, text + 1, TRUE);
} }

View File

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

View File

@@ -653,7 +653,7 @@ tab_click_cb (GtkWidget *wid, GdkEventButton *event, chan *ch)
if (event->button == 1 && event->type == GDK_BUTTON_PRESS) if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
{ {
close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button"); close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button");
if (close_button && if (prefs.hex_gui_tab_closebuttons && close_button &&
gtk_widget_translate_coordinates (close_button, wid, 0, 0, &close_x, &close_y)) gtk_widget_translate_coordinates (close_button, wid, 0, 0, &close_x, &close_y))
{ {
gtk_widget_get_allocation (close_button, &close_alloc); gtk_widget_get_allocation (close_button, &close_alloc);
@@ -679,7 +679,7 @@ tab_close_motion_cb (GtkWidget *wid, GdkEventMotion *event, chan *ch)
gboolean hover = FALSE; gboolean hover = FALSE;
close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button"); close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button");
if (close_button && if (prefs.hex_gui_tab_closebuttons && close_button &&
gtk_widget_translate_coordinates (close_button, wid, 0, 0, &close_x, &close_y)) gtk_widget_translate_coordinates (close_button, wid, 0, 0, &close_x, &close_y))
{ {
gtk_widget_get_allocation (close_button, &close_alloc); gtk_widget_get_allocation (close_button, &close_alloc);
@@ -714,7 +714,7 @@ tab_close_leave_cb (GtkWidget *wid, GdkEventCrossing *event, chan *ch)
GtkWidget *close_button; GtkWidget *close_button;
close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button"); close_button = g_object_get_data (G_OBJECT (wid), "tab-close-button");
if (close_button) if (prefs.hex_gui_tab_closebuttons && close_button)
gtk_widget_unset_state_flags (close_button, GTK_STATE_FLAG_PRELIGHT); gtk_widget_unset_state_flags (close_button, GTK_STATE_FLAG_PRELIGHT);
if (gtk_widget_get_window (wid)) if (gtk_widget_get_window (wid))
gdk_window_set_cursor (gtk_widget_get_window (wid), NULL); gdk_window_set_cursor (gtk_widget_get_window (wid), NULL);
@@ -744,9 +744,9 @@ cv_tabs_add (chanview *cv, chan *ch, char *name, GtkTreeIter *parent)
but = gtk_toggle_button_new (); but = gtk_toggle_button_new ();
gtk_widget_set_name (but, "zoitechat-tab"); gtk_widget_set_name (but, "zoitechat-tab");
gtk_widget_set_size_request (but, -1, 18); gtk_widget_set_size_request (but, -1, 14);
gtk_widget_add_events (but, GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK); gtk_widget_add_events (but, GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
label = gtk_label_new (name); label = gtk_label_new (name);
close_button = gtk_button_new (); close_button = gtk_button_new ();
gtk_style_context_add_class (gtk_widget_get_style_context (close_button), "flat"); gtk_style_context_add_class (gtk_widget_get_style_context (close_button), "flat");
@@ -755,8 +755,8 @@ cv_tabs_add (chanview *cv, chan *ch, char *name, GtkTreeIter *parent)
gtk_button_set_always_show_image (GTK_BUTTON (close_button), TRUE); gtk_button_set_always_show_image (GTK_BUTTON (close_button), TRUE);
gtk_widget_set_can_focus (close_button, FALSE); gtk_widget_set_can_focus (close_button, FALSE);
gtk_container_add (GTK_CONTAINER (close_button), close_icon); gtk_container_add (GTK_CONTAINER (close_button), close_icon);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), close_button, FALSE, FALSE, 0); gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
gtk_container_add (GTK_CONTAINER (but), hbox); gtk_container_add (GTK_CONTAINER (but), hbox);
g_object_set_data (G_OBJECT (but), "tab-label", label); g_object_set_data (G_OBJECT (but), "tab-label", label);
g_object_set_data (G_OBJECT (but), "tab-close-button", close_button); g_object_set_data (G_OBJECT (but), "tab-close-button", close_button);
@@ -780,6 +780,8 @@ cv_tabs_add (chanview *cv, chan *ch, char *name, GtkTreeIter *parent)
G_CALLBACK (tab_toggled_cb), ch); G_CALLBACK (tab_toggled_cb), ch);
g_object_set_data (G_OBJECT (but), "u", ch->userdata); g_object_set_data (G_OBJECT (but), "u", ch->userdata);
gtk_widget_show_all (hbox); gtk_widget_show_all (hbox);
if (!prefs.hex_gui_tab_closebuttons)
gtk_widget_hide (close_button);
tab_add_real (cv, but, ch); tab_add_real (cv, but, ch);

View File

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

View File

@@ -862,12 +862,34 @@ fe_set_title (session *sess)
gtk_window_set_title (GTK_WINDOW (sess->gui->window), tbuf); gtk_window_set_title (GTK_WINDOW (sess->gui->window), tbuf);
} }
static void
mg_topicbar_update_height (GtkWidget *topic);
static session *
mg_session_from_window (GtkWidget *wid)
{
GSList *list;
session *sess;
list = sess_list;
while (list)
{
sess = list->data;
if (sess && sess->gui && sess->gui->window == wid)
return sess;
list = list->next;
}
return current_sess;
}
static gboolean static gboolean
mg_windowstate_cb (GtkWindow *wid, GdkEventWindowState *event, gpointer userdata) mg_windowstate_cb (GtkWindow *wid, GdkEventWindowState *event, gpointer userdata)
{ {
guint win_state; guint win_state;
guint win_fullscreen; guint win_fullscreen;
gboolean changed = FALSE; gboolean changed = FALSE;
session *sess;
if ((event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && if ((event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) &&
(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) && (event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) &&
@@ -903,6 +925,20 @@ mg_windowstate_cb (GtkWindow *wid, GdkEventWindowState *event, gpointer userdata
mg_schedule_config_save (); mg_schedule_config_save ();
} }
sess = mg_session_from_window (GTK_WIDGET (wid));
if (sess && sess->gui && GTK_IS_WIDGET (sess->gui->topic_entry))
{
mg_topicbar_update_height (sess->gui->topic_entry);
gtk_widget_queue_draw (sess->gui->topic_entry);
}
if (sess && sess->gui && GTK_IS_XTEXT (sess->gui->xtext))
{
gtk_xtext_refresh (GTK_XTEXT (sess->gui->xtext));
gtk_widget_queue_draw (sess->gui->xtext);
}
if (sess && sess->gui && GTK_IS_WIDGET (sess->gui->window))
gtk_widget_queue_draw (sess->gui->window);
menu_set_fullscreen (current_sess->gui, prefs.hex_gui_win_fullscreen); menu_set_fullscreen (current_sess->gui, prefs.hex_gui_win_fullscreen);
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
@@ -916,6 +952,7 @@ static gboolean
mg_configure_cb (GtkWidget *wid, GdkEventConfigure *event, session *sess) mg_configure_cb (GtkWidget *wid, GdkEventConfigure *event, session *sess)
{ {
gboolean changed = FALSE; gboolean changed = FALSE;
session *target_sess;
if (sess == NULL) if (sess == NULL)
{ {
@@ -998,6 +1035,23 @@ mg_configure_cb (GtkWidget *wid, GdkEventConfigure *event, session *sess)
mg_schedule_config_save (); mg_schedule_config_save ();
} }
target_sess = mg_session_from_window (wid);
if (target_sess && target_sess->gui)
{
if (GTK_IS_WIDGET (target_sess->gui->topic_entry))
{
mg_topicbar_update_height (target_sess->gui->topic_entry);
gtk_widget_queue_draw (target_sess->gui->topic_entry);
}
if (GTK_IS_XTEXT (target_sess->gui->xtext))
{
gtk_xtext_refresh (GTK_XTEXT (target_sess->gui->xtext));
gtk_widget_queue_draw (target_sess->gui->xtext);
}
if (GTK_IS_WIDGET (target_sess->gui->window))
gtk_widget_queue_draw (target_sess->gui->window);
}
return FALSE; return FALSE;
} }
@@ -2969,13 +3023,36 @@ mg_create_dialogbuttons (GtkWidget *box)
} }
static void static void
mg_configure_topic_scroller (GtkWidget *scroller, GtkWidget *topic) mg_topicbar_update_height (GtkWidget *topic)
{ {
GtkWidget *scroller;
GtkTextBuffer *buffer;
GtkTextIter start;
GtkTextIter end;
PangoLayout *layout;
char *text;
int width;
int line_height;
int line_count;
int target_height;
PangoContext *context; PangoContext *context;
PangoFontMetrics *metrics; PangoFontMetrics *metrics;
int line_height;
int min_height; if (!topic || !GTK_IS_TEXT_VIEW (topic))
int max_height; return;
scroller = gtk_widget_get_parent (topic);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (topic));
gtk_text_buffer_get_bounds (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
layout = gtk_widget_create_pango_layout (topic, text && text[0] ? text : " ");
g_free (text);
width = gtk_widget_get_allocated_width (topic) - 8;
if (width > 0)
pango_layout_set_width (layout, width * PANGO_SCALE);
pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
context = gtk_widget_get_pango_context (topic); context = gtk_widget_get_pango_context (topic);
metrics = pango_context_get_metrics (context, metrics = pango_context_get_metrics (context,
@@ -2984,26 +3061,52 @@ mg_configure_topic_scroller (GtkWidget *scroller, GtkWidget *topic)
line_height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + line_height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
pango_font_metrics_get_descent (metrics)); pango_font_metrics_get_descent (metrics));
pango_font_metrics_unref (metrics); pango_font_metrics_unref (metrics);
if (line_height <= 0) if (line_height <= 0)
line_height = 16; line_height = 16;
line_count = pango_layout_get_line_count (layout);
if (line_count <= 0)
line_count = 1;
target_height = line_height * line_count;
if (target_height < line_height)
target_height = line_height;
min_height = line_height + 8; gtk_widget_set_size_request (topic, -1, target_height);
max_height = line_height * 4 + 8; if (scroller && GTK_IS_SCROLLED_WINDOW (scroller))
{
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (scroller), -1);
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (scroller), -1);
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (scroller), target_height);
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (scroller), target_height);
gtk_widget_set_size_request (scroller, -1, target_height);
gtk_widget_queue_resize (scroller);
}
else
{
gtk_widget_queue_resize (topic);
}
gtk_widget_queue_draw (topic);
g_object_unref (layout);
}
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller), static void
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); mg_topicbar_buffer_changed_cb (GtkTextBuffer *buffer, gpointer userdata)
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller), GTK_SHADOW_NONE); {
gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (scroller), TRUE); (void) buffer;
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (scroller), min_height); mg_topicbar_update_height (GTK_WIDGET (userdata));
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (scroller), max_height); }
static void
mg_topicbar_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation, gpointer userdata)
{
(void) allocation;
(void) userdata;
mg_topicbar_update_height (widget);
} }
void void
mg_apply_session_font_prefs (session_gui *gui) mg_apply_session_font_prefs (session_gui *gui)
{ {
const PangoFontDescription *font = NULL; const PangoFontDescription *font = NULL;
GtkWidget *topic_scroller;
if (!gui) if (!gui)
return; return;
@@ -3014,9 +3117,7 @@ mg_apply_session_font_prefs (session_gui *gui)
if (gui->topic_entry) if (gui->topic_entry)
{ {
theme_manager_apply_entry_palette (gui->topic_entry, font); theme_manager_apply_entry_palette (gui->topic_entry, font);
topic_scroller = gtk_widget_get_parent (gui->topic_entry); mg_topicbar_update_height (gui->topic_entry);
if (topic_scroller && GTK_IS_SCROLLED_WINDOW (topic_scroller))
mg_configure_topic_scroller (topic_scroller, gui->topic_entry);
} }
if (gui->input_box && prefs.hex_gui_input_style) if (gui->input_box && prefs.hex_gui_input_style)
@@ -3034,7 +3135,7 @@ mg_apply_session_font_prefs (session_gui *gui)
static void static void
mg_create_topicbar (session *sess, GtkWidget *box) mg_create_topicbar (session *sess, GtkWidget *box)
{ {
GtkWidget *vbox, *hbox, *mode_hbox, *topic, *bbox, *topic_scroller; GtkWidget *vbox, *hbox, *mode_hbox, *topic, *bbox;
session_gui *gui = sess->gui; session_gui *gui = sess->gui;
gui->topic_bar = vbox = mg_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); gui->topic_bar = vbox = mg_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
@@ -3048,14 +3149,21 @@ mg_create_topicbar (session *sess, GtkWidget *box)
gui->topic_entry = topic = gtk_text_view_new (); gui->topic_entry = topic = gtk_text_view_new ();
gtk_widget_set_name (topic, "zoitechat-topicbox"); gtk_widget_set_name (topic, "zoitechat-topicbox");
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (topic), GTK_WRAP_WORD); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (topic), GTK_WRAP_WORD_CHAR);
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (topic), 4); gtk_text_view_set_left_margin (GTK_TEXT_VIEW (topic), 4);
gtk_text_view_set_right_margin (GTK_TEXT_VIEW (topic), 4); gtk_text_view_set_right_margin (GTK_TEXT_VIEW (topic), 4);
topic_scroller = gtk_scrolled_window_new (NULL, NULL); gtk_text_view_set_top_margin (GTK_TEXT_VIEW (topic), 4);
gtk_container_add (GTK_CONTAINER (topic_scroller), topic); gtk_text_view_set_bottom_margin (GTK_TEXT_VIEW (topic), 4);
gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (topic), 0);
gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (topic), 0);
gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (topic), 0);
theme_manager_apply_entry_palette (topic, input_style ? input_style->font_desc : NULL); theme_manager_apply_entry_palette (topic, input_style ? input_style->font_desc : NULL);
mg_configure_topic_scroller (topic_scroller, topic); g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (topic)), "changed",
gtk_box_pack_start (GTK_BOX (hbox), topic_scroller, TRUE, TRUE, 0); G_CALLBACK (mg_topicbar_buffer_changed_cb), topic);
g_signal_connect (G_OBJECT (topic), "size-allocate",
G_CALLBACK (mg_topicbar_size_allocate_cb), NULL);
mg_topicbar_update_height (topic);
gtk_box_pack_start (GTK_BOX (hbox), topic, TRUE, TRUE, 0);
gtk_widget_add_events (topic, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | gtk_widget_add_events (topic, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK); GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
g_signal_connect (G_OBJECT (topic), "key-press-event", g_signal_connect (G_OBJECT (topic), "key-press-event",

View File

@@ -1717,7 +1717,7 @@ menu_ctcpguiopen (void)
static void static void
menu_docs (GtkWidget *wid, gpointer none) menu_docs (GtkWidget *wid, gpointer none)
{ {
fe_open_url ("https://docs.zoitechat.zoite.net/en/latest/"); fe_open_url ("https://docs.zoitechat.org/en/latest/");
} }
/*static void /*static void
@@ -1862,7 +1862,7 @@ about_dialog_response (GtkDialog *dialog, int response, gpointer data)
{ {
if (response == GTK_RESPONSE_HELP) if (response == GTK_RESPONSE_HELP)
{ {
fe_open_url ("http://zoitechat.zoite.net"); fe_open_url ("http://zoitechat.org");
return; return;
} }
if (response == GTK_RESPONSE_APPLY) if (response == GTK_RESPONSE_APPLY)

View File

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

View File

@@ -188,6 +188,16 @@ zoitechat_gtk3_theme_service_import (const char *source_path, char **imported_id
return FALSE; return FALSE;
} }
gboolean
zoitechat_gtk3_theme_service_read_archive_text_file (const char *archive_path, const char *name, char **contents, GError **error)
{
(void)archive_path;
(void)name;
(void)contents;
(void)error;
return FALSE;
}
gboolean gboolean
zoitechat_gtk3_theme_service_remove_user_theme (const char *theme_id, GError **error) zoitechat_gtk3_theme_service_remove_user_theme (const char *theme_id, GError **error)
{ {

View File

@@ -33,6 +33,10 @@ static const char *theme_css_selector_dark_class = "zoitechat-dark";
static const char *theme_css_selector_light_class = "zoitechat-light"; static const char *theme_css_selector_light_class = "zoitechat-light";
static const char *theme_css_palette_provider_key = "zoitechat-palette-provider"; static const char *theme_css_palette_provider_key = "zoitechat-palette-provider";
static const guint theme_css_provider_priority = GTK_STYLE_PROVIDER_PRIORITY_USER; static const guint theme_css_provider_priority = GTK_STYLE_PROVIDER_PRIORITY_USER;
static const char *theme_css_palette_scope_selectors =
".zoitechat-palette, .zoitechat-palette *, .zoitechat-palette box, .zoitechat-palette grid, .zoitechat-palette stack, .zoitechat-palette frame, .zoitechat-palette paned, .zoitechat-palette paned > separator, .zoitechat-palette separator, .zoitechat-palette viewport, .zoitechat-palette overlay, .zoitechat-palette revealer, .zoitechat-palette notebook, .zoitechat-palette notebook > header, .zoitechat-palette notebook > header > tabs, .zoitechat-palette notebook > header > tabs > tab, .zoitechat-palette scrolledwindow, .zoitechat-palette scrollbar, .zoitechat-palette scrollbar slider, .zoitechat-palette scrollbar trough, .zoitechat-palette treeview, .zoitechat-palette treeview.view, .zoitechat-palette treeview.view text, .zoitechat-palette treeview.view cell, .zoitechat-palette treeview.view row, .zoitechat-palette treeview header, .zoitechat-palette treeview header button, .zoitechat-palette list, .zoitechat-palette list row, .zoitechat-palette row, .zoitechat-palette textview, .zoitechat-palette textview text, .zoitechat-palette text, .zoitechat-palette entry, .zoitechat-palette entry text, .zoitechat-palette button, .zoitechat-palette button label, .zoitechat-palette check, .zoitechat-palette radio, .zoitechat-palette switch, .zoitechat-palette slider, .zoitechat-palette scale, .zoitechat-palette scale trough, .zoitechat-palette scale highlight, .zoitechat-palette spinbutton, .zoitechat-palette combobox, .zoitechat-palette combobox box, .zoitechat-palette progressbar, .zoitechat-palette progressbar trough, .zoitechat-palette levelbar, .zoitechat-palette levelbar trough, .zoitechat-palette menubar, .zoitechat-palette menu, .zoitechat-palette menuitem, .zoitechat-palette menuitem label, .zoitechat-palette toolbar, .zoitechat-palette headerbar, .zoitechat-palette label, .zoitechat-palette link, .zoitechat-palette infobar, .zoitechat-palette statusbar, .zoitechat-palette statusbar frame, .zoitechat-palette tooltip, .zoitechat-palette tooltip label";
static const char *theme_css_palette_selection_selectors =
".zoitechat-palette *:selected, .zoitechat-palette *:selected:focus, .zoitechat-palette *:selected:hover, .zoitechat-palette treeview.view:selected, .zoitechat-palette treeview.view:selected:focus, .zoitechat-palette treeview.view:selected:hover, .zoitechat-palette row:selected, .zoitechat-palette row:selected:focus, .zoitechat-palette row:selected:hover, .zoitechat-palette selection, .zoitechat-palette text selection, .zoitechat-palette entry selection, .zoitechat-palette entry text selection, .zoitechat-palette button:selected, .zoitechat-palette button:checked, .zoitechat-palette check:checked, .zoitechat-palette radio:checked, .zoitechat-palette switch:checked, .zoitechat-palette slider:active, .zoitechat-palette menuitem:selected, .zoitechat-palette menuitem:hover, .zoitechat-palette notebook > header > tabs > tab:checked, .zoitechat-palette notebook > header > tabs > tab:hover, .zoitechat-palette treeview header button:hover, .zoitechat-palette treeview header button:active, .zoitechat-palette progressbar progress, .zoitechat-palette levelbar block.filled, .zoitechat-palette:focus selection, .zoitechat-palette:focus text selection";
typedef struct typedef struct
{ {
@@ -323,13 +327,16 @@ theme_css_apply_palette_widget (GtkWidget *widget, const GdkRGBA *bg, const GdkR
} }
gtkutil_append_font_css (css, font_desc); gtkutil_append_font_css (css, font_desc);
g_string_append (css, " }"); g_string_append (css, " }");
g_string_append_printf (css, ".%s, .%s *, .%s treeview, .%s treeview.view, .%s treeview.view text, .%s treeview.view cell, .%s treeview.view row, .%s list, .%s list row, .%s text {", theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class); g_string_append_printf (css, "%s {", theme_css_palette_scope_selectors);
if (bg) if (bg)
g_string_append_printf (css, " background-color: %s;", bg_color); g_string_append_printf (css, " background-color: %s;", bg_color);
if (fg) if (fg)
{
g_string_append_printf (css, " color: %s;", fg_color); g_string_append_printf (css, " color: %s;", fg_color);
g_string_append_printf (css, " caret-color: %s;", fg_color);
}
g_string_append (css, " }"); g_string_append (css, " }");
g_string_append_printf (css, ".%s *:selected, .%s *:selected:focus, .%s *:selected:hover, .%s treeview.view:selected, .%s treeview.view:selected:focus, .%s treeview.view:selected:hover, .%s row:selected, .%s row:selected:focus, .%s row:selected:hover, .%s selection, .%s text selection, .%s entry selection, .%s entry text selection, .%s:focus selection, .%s:focus text selection {", theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class); g_string_append_printf (css, "%s {", theme_css_palette_selection_selectors);
if (sel_bg_color) if (sel_bg_color)
g_string_append_printf (css, " background-color: %s;", sel_bg_color); g_string_append_printf (css, " background-color: %s;", sel_bg_color);
else if (bg) else if (bg)

View File

@@ -29,12 +29,15 @@
#include "../gtkutil.h" #include "../gtkutil.h"
#include "../../common/fe.h" #include "../../common/fe.h"
#include "../../common/cfgfiles.h"
#include "../../common/util.h" #include "../../common/util.h"
#include "../../common/gtk3-theme-service.h" #include "../../common/gtk3-theme-service.h"
#include "theme-gtk3.h" #include "theme-gtk3.h"
#include "theme-manager.h" #include "theme-manager.h"
#include "theme-preferences.h" #include "theme-preferences.h"
extern void load_text_events (void);
typedef struct typedef struct
{ {
GtkWindow *parent; GtkWindow *parent;
@@ -932,6 +935,21 @@ theme_preferences_show_import_error (GtkWidget *button, const char *message)
gtk_widget_destroy (dialog); gtk_widget_destroy (dialog);
} }
static void
theme_preferences_show_import_info (GtkWidget *button, const char *message)
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (button)),
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_CLOSE,
"%s",
message);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
}
static gboolean static gboolean
theme_preferences_parse_cfg_color (const char *cfg, theme_preferences_parse_cfg_color (const char *cfg,
const char *key, const char *key,
@@ -1038,40 +1056,77 @@ static void
theme_preferences_import_colors_conf_cb (GtkWidget *button, gpointer user_data) theme_preferences_import_colors_conf_cb (GtkWidget *button, gpointer user_data)
{ {
gboolean *color_change_flag = user_data; gboolean *color_change_flag = user_data;
GtkWidget *dialog; GtkFileChooserNative *dialog;
char *path; char *path;
char *lower_path;
char *cfg; char *cfg;
char *pevents_cfg = NULL;
GError *error = NULL; GError *error = NULL;
gboolean any_imported = FALSE; gboolean any_imported = FALSE;
gboolean imported_from_hct = FALSE;
gboolean imported_pevents = FALSE;
ThemeSemanticToken token; ThemeSemanticToken token;
GtkFileFilter *filter;
dialog = gtk_file_chooser_dialog_new (_("Import colors.conf colors"), dialog = gtk_file_chooser_native_new (_("Import colors.conf colors"),
GTK_WINDOW (gtk_widget_get_toplevel (button)), GTK_WINDOW (gtk_widget_get_toplevel (button)),
GTK_FILE_CHOOSER_ACTION_OPEN, GTK_FILE_CHOOSER_ACTION_OPEN,
_("_Cancel"), GTK_RESPONSE_CANCEL, _("_Import"),
_("_Import"), GTK_RESPONSE_ACCEPT, _("_Cancel"));
NULL);
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), TRUE);
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), FALSE); gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), FALSE);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Theme colors (*.conf, *.hct)"));
gtk_file_filter_add_pattern (filter, "*.conf");
gtk_file_filter_add_pattern (filter, "*.hct");
gtk_file_filter_add_pattern (filter, "*.HCT");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT) if (gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT)
{ {
gtk_widget_destroy (dialog); g_object_unref (dialog);
return; return;
} }
path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
gtk_widget_destroy (dialog); g_object_unref (dialog);
if (!path) if (!path)
return; return;
if (!g_file_get_contents (path, &cfg, NULL, &error)) lower_path = g_ascii_strdown (path, -1);
if (g_str_has_suffix (lower_path, ".hct"))
{ {
theme_preferences_show_import_error (button, _("Failed to read colors.conf file.")); imported_from_hct = TRUE;
if (!zoitechat_gtk3_theme_service_read_archive_text_file (path, "colors.conf", &cfg, &error))
{
theme_preferences_show_import_error (button, _("Failed to read colors.conf from .hct file."));
g_clear_error (&error); g_clear_error (&error);
g_free (lower_path);
g_free (path); g_free (path);
return; return;
} }
if (zoitechat_gtk3_theme_service_read_archive_text_file (path, "pevents.conf", &pevents_cfg, &error))
{
char *pevents_path = g_build_filename (get_xdir (), "pevents.conf", NULL);
if (g_file_set_contents (pevents_path, pevents_cfg, -1, &error))
{
load_text_events ();
imported_pevents = TRUE;
}
g_free (pevents_path);
g_clear_error (&error);
}
else
g_clear_error (&error);
}
else if (!g_file_get_contents (path, &cfg, NULL, &error))
{
theme_preferences_show_import_error (button, _("Failed to read colors.conf file."));
g_clear_error (&error);
g_free (lower_path);
g_free (path);
return;
}
g_free (lower_path);
for (token = THEME_TOKEN_MIRC_0; token < THEME_TOKEN_COUNT; token++) for (token = THEME_TOKEN_MIRC_0; token < THEME_TOKEN_COUNT; token++)
{ {
@@ -1086,9 +1141,22 @@ theme_preferences_import_colors_conf_cb (GtkWidget *button, gpointer user_data)
if (!any_imported) if (!any_imported)
theme_preferences_show_import_error (button, _("No importable colors were found in that colors.conf file.")); theme_preferences_show_import_error (button, _("No importable colors were found in that colors.conf file."));
else if (imported_from_hct)
{
char *message = g_strdup_printf (imported_pevents ?
_("Imported colors.conf and pevents.conf from %s.") :
_("Imported colors.conf from %s."),
path);
theme_preferences_show_import_info (button, message);
g_free (message);
}
else if (color_change_flag) else if (color_change_flag)
*color_change_flag = theme_preferences_stage.active ? theme_preferences_stage.changed : *color_change_flag; *color_change_flag = theme_preferences_stage.active ? theme_preferences_stage.changed : *color_change_flag;
if (any_imported && color_change_flag)
*color_change_flag = theme_preferences_stage.active ? theme_preferences_stage.changed : *color_change_flag;
g_free (pevents_cfg);
g_free (cfg); g_free (cfg);
g_free (path); g_free (path);
} }

View File

@@ -550,9 +550,9 @@ fe_userlist_insert (session *sess, struct User *newuser, gboolean sel)
prefix_escaped = g_markup_escape_text (prefix_text, -1); prefix_escaped = g_markup_escape_text (prefix_text, -1);
prefix_color = userlist_prefix_color (newuser->prefix[0]); prefix_color = userlist_prefix_color (newuser->prefix[0]);
if (prefix_color) if (prefix_color)
prefix = g_strdup_printf ("<b><span foreground=\"%s\">%s</span></b>", prefix_color, prefix_escaped); prefix = g_strdup_printf ("<span foreground=\"%s\">%s</span>", prefix_color, prefix_escaped);
else else
prefix = g_strdup_printf ("<b>%s</b>", prefix_escaped); prefix = g_strdup (prefix_escaped);
g_free (prefix_escaped); g_free (prefix_escaped);
} }
pix = NULL; pix = NULL;

View File

@@ -9,10 +9,10 @@ AppName=ZoiteChat
AppVersion={#APPVER} AppVersion={#APPVER}
AppVerName=ZoiteChat {#APPVER} AppVerName=ZoiteChat {#APPVER}
AppPublisher=ZoiteChat AppPublisher=ZoiteChat
AppPublisherURL=http://zoitechat.zoite.net AppPublisherURL=http://zoitechat.org
AppCopyright=Copyright (C) 1998-2010 Peter Zelezny AppCopyright=Copyright (C) 1998-2010 Peter Zelezny
AppSupportURL=https://github.com/zoitechat/zoitechat/issues AppSupportURL=https://github.com/zoitechat/zoitechat/issues
AppUpdatesURL=http://zoitechat.zoite.net/downloads.html AppUpdatesURL=http://zoitechat.org/downloads.html
LicenseFile=share\doc\zoitechat\COPYING LicenseFile=share\doc\zoitechat\COPYING
UninstallDisplayIcon={app}\zoitechat.exe UninstallDisplayIcon={app}\zoitechat.exe
UninstallDisplayName=ZoiteChat UninstallDisplayName=ZoiteChat
@@ -58,9 +58,12 @@ Name: "plugins\sysinfo"; Description: "SysInfo"; Types: custom; Flags: disableno
Name: "plugins\upd"; Description: "Update Checker"; Types: normal custom; Flags: disablenouninstallwarning Name: "plugins\upd"; Description: "Update Checker"; Types: normal custom; Flags: disablenouninstallwarning
Name: "plugins\winamp"; Description: "Winamp"; Types: custom; Flags: disablenouninstallwarning Name: "plugins\winamp"; Description: "Winamp"; Types: custom; Flags: disablenouninstallwarning
Name: "langs"; Description: "Language Interfaces"; Types: custom; Flags: disablenouninstallwarning Name: "langs"; Description: "Language Interfaces"; Types: custom; Flags: disablenouninstallwarning
Name: "langs\lua"; Description: "Lua"; Types: normal custom; Flags: disablenouninstallwarning Name: "langs\lua"; Description: "Lua (LuaJIT 2.1)"; Types: normal custom; Flags: disablenouninstallwarning
Name: "langs\perl"; Description: "Perl (requires Perl 5.42)"; Types: custom; Flags: disablenouninstallwarning Name: "langs\perl"; Description: "Perl (Strawberry Perl 5.42.0.1)"; Types: custom; Flags: disablenouninstallwarning
Name: "langs\python"; Description: "Python (requires Python 3.14.3)"; Types: custom; Flags: disablenouninstallwarning Name: "langs\python"; Description: "Python (Python 3.14.3)"; Types: custom; Flags: disablenouninstallwarning
Name: "themes"; Description: "GTK3 Themes"; Types: normal minimal custom; Flags: disablenouninstallwarning
Name: "themes\windows10"; Description: "Windows 10"; Types: normal minimal custom; Flags: disablenouninstallwarning
Name: "themes\windows10dark"; Description: "Windows 10 Dark"; Types: normal minimal custom; Flags: disablenouninstallwarning
Name: "deps"; Description: "Dependencies"; Types: custom; Flags: disablenouninstallwarning Name: "deps"; Description: "Dependencies"; Types: custom; Flags: disablenouninstallwarning
Name: "deps\vcredist2015"; Description: "Visual C++ Redistributable 2015"; Types: normal minimal custom; Flags: disablenouninstallwarning Name: "deps\vcredist2015"; Description: "Visual C++ Redistributable 2015"; Types: normal minimal custom; Flags: disablenouninstallwarning
@@ -88,6 +91,11 @@ Filename: "{tmp}\perl.msi"; StatusMsg: "Installing Perl"; Components: langs\perl
Filename: "{tmp}\python.msi"; StatusMsg: "Installing Python"; Components: langs\python; Flags: shellexec skipifdoesntexist; Tasks: not portable Filename: "{tmp}\python.msi"; StatusMsg: "Installing Python"; Components: langs\python; Flags: shellexec skipifdoesntexist; Tasks: not portable
Filename: "{tmp}\python.exe"; Parameters: "InstallAllUsers=1 PrependPath=1"; StatusMsg: "Installing Python"; Components: langs\python; Flags: shellexec skipifdoesntexist; Tasks: not portable Filename: "{tmp}\python.exe"; Parameters: "InstallAllUsers=1 PrependPath=1"; StatusMsg: "Installing Python"; Components: langs\python; Flags: shellexec skipifdoesntexist; Tasks: not portable
Filename: "{tmp}\spelling-dicts.exe"; Parameters: "/verysilent"; StatusMsg: "Installing Spelling Dictionaries"; Components: spell; Flags: skipifdoesntexist; Tasks: not portable Filename: "{tmp}\spelling-dicts.exe"; Parameters: "/verysilent"; StatusMsg: "Installing Spelling Dictionaries"; Components: spell; Flags: skipifdoesntexist; Tasks: not portable
Filename: "{sys}\WindowsPowerShell\v1.0\powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -Command ""Expand-Archive -LiteralPath '{tmp}\Windows-10-3.2.1.zip' -DestinationPath '{userappdata}\ZoiteChat\gtk3-themes' -Force"""; StatusMsg: "Installing GTK3 Theme: Windows 10"; Components: themes\windows10; Flags: runhidden waituntilterminated skipifdoesntexist
Filename: "{sys}\WindowsPowerShell\v1.0\powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -Command ""Expand-Archive -LiteralPath '{tmp}\Windows-10-Dark-3.2.1-dark.zip' -DestinationPath '{userappdata}\ZoiteChat\gtk3-themes' -Force"""; StatusMsg: "Installing GTK3 Theme: Windows 10 Dark"; Components: themes\windows10dark; Flags: runhidden waituntilterminated skipifdoesntexist
[Dirs]
Name: "{userappdata}\ZoiteChat\gtk3-themes"; Components: themes
[Files] [Files]
Source: "portable-mode"; DestDir: "{app}"; Tasks: portable Source: "portable-mode"; DestDir: "{app}"; Tasks: portable
@@ -196,6 +204,10 @@ Name: "{commonappdata}\Microsoft\Internet Explorer\Quick Launch\ZoiteChat"; File
[Messages] [Messages]
BeveledLabel= {#APPNAM} BeveledLabel= {#APPNAM}
[UninstallDelete]
Type: filesandordirs; Name: "{userappdata}\ZoiteChat\gtk3-themes\Windows-10-3.2.1"; Components: themes\windows10
Type: filesandordirs; Name: "{userappdata}\ZoiteChat\gtk3-themes\Windows-10-Dark-3.2.1-dark"; Components: themes\windows10dark
[Code] [Code]
#ifndef USE_INNO_DOWNLOAD_PLUGIN #ifndef USE_INNO_DOWNLOAD_PLUGIN
var var
@@ -336,6 +348,12 @@ begin
begin begin
idpClearFiles; idpClearFiles;
if IsComponentSelected('themes\windows10') then
idpAddFile('https://dl.zoitechat.zoite.net/themes/GTK3Themes/Windows-10-3.2.1.zip', ExpandConstant('{tmp}\Windows-10-3.2.1.zip'));
if IsComponentSelected('themes\windows10dark') then
idpAddFile('https://dl.zoitechat.zoite.net/themes/GTK3Themes/Windows-10-Dark-3.2.1-dark.zip', ExpandConstant('{tmp}\Windows-10-Dark-3.2.1-dark.zip'));
if not IsTaskSelected('portable') then if not IsTaskSelected('portable') then
begin begin
@@ -389,12 +407,28 @@ begin
end; end;
if CurPageID = wpReady then if CurPageID = wpReady then
begin
if IsComponentSelected('themes\windows10') and not FileExists(ExpandConstant('{tmp}\Windows-10-3.2.1.zip')) then
begin
MsgBox('Windows 10 GTK3 theme could not be downloaded. Please retry setup and rerun setup.', mbError, MB_OK);
Result := False;
Exit;
end;
if IsComponentSelected('themes\windows10dark') and not FileExists(ExpandConstant('{tmp}\Windows-10-Dark-3.2.1-dark.zip')) then
begin
MsgBox('Windows 10 Dark GTK3 theme could not be downloaded. Please retry setup and rerun setup.', mbError, MB_OK);
Result := False;
Exit;
end;
if IsComponentSelected('deps\vcredist2015') and not CheckVCInstall() and not FileExists(ExpandConstant('{tmp}\vcredist.exe')) then if IsComponentSelected('deps\vcredist2015') and not CheckVCInstall() and not FileExists(ExpandConstant('{tmp}\vcredist.exe')) then
begin begin
MsgBox('Visual C++ Redistributable could not be downloaded. Please retry setup or install it manually and rerun setup.', mbError, MB_OK); MsgBox('Visual C++ Redistributable could not be downloaded. Please retry setup or install it manually and rerun setup.', mbError, MB_OK);
Result := False; Result := False;
Exit; Exit;
end; end;
end;
end; end;
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////