mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-06-11 01:10:18 +00:00
Compare commits
70 Commits
d167b53b17
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb08b19c0d | ||
|
|
7497919e8f | ||
|
|
41cbe7b31c | ||
| 425e951341 | |||
| 2e4a0b92fc | |||
| 9f839579e2 | |||
| 900066b9d4 | |||
| 97534b0670 | |||
|
|
62672ade04 | ||
| b22e1c1ccc | |||
|
|
1b8e60c26d | ||
| 035dfdd332 | |||
|
|
c9bed097ba | ||
| 5acb90025f | |||
|
|
2d12da79b0 | ||
|
|
bede379021 | ||
| 38acde1b20 | |||
| d0c4a5addd | |||
|
|
b8a7ccf005 | ||
| 68fc53585e | |||
| 26afc125c7 | |||
|
|
090b39f78b | ||
| 3722de6b13 | |||
|
|
d93c9aa780 | ||
| ea56504aee | |||
| 46b91edfdf | |||
|
|
d2dfde519d | ||
| 1eac56f22c | |||
|
|
fb491a6bb2 | ||
| 3da7c89b66 | |||
|
|
e842cf3a57 | ||
| 85b0e8f1a6 | |||
|
|
b8e03ff6c1 | ||
| 54b1703d67 | |||
| 15d647a0ec | |||
|
|
353558ddb3 | ||
|
|
9f58d30050 | ||
|
|
4f0632cdf1 | ||
|
|
ff8ba71948 | ||
|
|
a367591327 | ||
|
|
c91925fbc2 | ||
| 479f1649ef | |||
|
|
06f69184b6 | ||
|
|
3471d9a57c | ||
| 28d4035477 | |||
|
|
3e1d151efd | ||
| 556cfc3036 | |||
| c49b757be6 | |||
| cec7e2caf3 | |||
| 9a0c07a461 | |||
| c7064c18b9 | |||
|
|
fb897310c8 | ||
| 5944849326 | |||
| 1255f1e6c7 | |||
| d7bc09d859 | |||
| f84a448351 | |||
| 7e34690e0c | |||
|
|
6f6d378600 | ||
|
|
216b463b8f | ||
| 4ad84cb5e5 | |||
| 19e0946717 | |||
| 0de1ad06cd | |||
|
|
72427006dd | ||
|
|
0e5f702651 | ||
| 4f1b0fc838 | |||
|
|
23d0963c2d | ||
|
|
dcb35fb80f | ||
| b1768854c3 | |||
| 4ed4eaf8e8 | |||
| 18eff80a30 |
34
.github/workflows/appimage-build.yml
vendored
34
.github/workflows/appimage-build.yml
vendored
@@ -86,11 +86,21 @@ jobs:
|
|||||||
cp -a /usr/lib/x86_64-linux-gnu/python3/dist-packages AppDir/usr/lib/x86_64-linux-gnu/python3/
|
cp -a /usr/lib/x86_64-linux-gnu/python3/dist-packages AppDir/usr/lib/x86_64-linux-gnu/python3/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -d "/usr/lib/x86_64-linux-gnu/perl-base" ]; then
|
||||||
|
install -d AppDir/usr/lib/x86_64-linux-gnu
|
||||||
|
cp -a /usr/lib/x86_64-linux-gnu/perl-base AppDir/usr/lib/x86_64-linux-gnu/
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -d "/usr/lib/x86_64-linux-gnu/perl" ]; then
|
if [ -d "/usr/lib/x86_64-linux-gnu/perl" ]; then
|
||||||
install -d AppDir/usr/lib/x86_64-linux-gnu
|
install -d AppDir/usr/lib/x86_64-linux-gnu
|
||||||
cp -a /usr/lib/x86_64-linux-gnu/perl AppDir/usr/lib/x86_64-linux-gnu/
|
cp -a /usr/lib/x86_64-linux-gnu/perl AppDir/usr/lib/x86_64-linux-gnu/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -d "/usr/lib/x86_64-linux-gnu/perl5" ]; then
|
||||||
|
install -d AppDir/usr/lib/x86_64-linux-gnu
|
||||||
|
cp -a /usr/lib/x86_64-linux-gnu/perl5 AppDir/usr/lib/x86_64-linux-gnu/
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -d "/usr/share/perl" ]; then
|
if [ -d "/usr/share/perl" ]; then
|
||||||
install -d AppDir/usr/share
|
install -d AppDir/usr/share
|
||||||
cp -a /usr/share/perl AppDir/usr/share/
|
cp -a /usr/share/perl AppDir/usr/share/
|
||||||
@@ -100,6 +110,10 @@ jobs:
|
|||||||
install -d AppDir/usr/share
|
install -d AppDir/usr/share
|
||||||
cp -a /usr/share/perl5 AppDir/usr/share/
|
cp -a /usr/share/perl5 AppDir/usr/share/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
perl -MFile::Spec -e 'print "Build host File::Spec: $INC{\"File/Spec.pm\"}\n"'
|
||||||
|
find AppDir/usr -path '*/File/Spec.pm' -print -quit | grep -q .
|
||||||
|
|
||||||
if compgen -G '/usr/lib/x86_64-linux-gnu/libpython3*.so*' > /dev/null; then
|
if compgen -G '/usr/lib/x86_64-linux-gnu/libpython3*.so*' > /dev/null; then
|
||||||
install -d AppDir/usr/lib/x86_64-linux-gnu
|
install -d AppDir/usr/lib/x86_64-linux-gnu
|
||||||
cp -a /usr/lib/x86_64-linux-gnu/libpython3*.so* AppDir/usr/lib/x86_64-linux-gnu/
|
cp -a /usr/lib/x86_64-linux-gnu/libpython3*.so* AppDir/usr/lib/x86_64-linux-gnu/
|
||||||
@@ -162,7 +176,7 @@ jobs:
|
|||||||
|
|
||||||
APPDIR="${APPDIR:-$(dirname "$(readlink -f "$0")")}"
|
APPDIR="${APPDIR:-$(dirname "$(readlink -f "$0")")}"
|
||||||
|
|
||||||
export PATH="${PATH:-/usr/bin:/bin}:$APPDIR/usr/bin"
|
export PATH="$APPDIR/usr/bin:${PATH:-/usr/bin:/bin}"
|
||||||
export LD_LIBRARY_PATH="$APPDIR/usr/lib:$APPDIR/usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH:-}"
|
export LD_LIBRARY_PATH="$APPDIR/usr/lib:$APPDIR/usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH:-}"
|
||||||
export XDG_DATA_DIRS="$APPDIR/usr/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
|
export XDG_DATA_DIRS="$APPDIR/usr/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
|
||||||
export GTK_EXE_PREFIX="$APPDIR/usr"
|
export GTK_EXE_PREFIX="$APPDIR/usr"
|
||||||
@@ -211,6 +225,23 @@ jobs:
|
|||||||
|
|
||||||
unset GTK_MODULES
|
unset GTK_MODULES
|
||||||
|
|
||||||
|
perl5lib_entries=""
|
||||||
|
for dir in \
|
||||||
|
"$APPDIR/usr/lib/x86_64-linux-gnu/perl-base" \
|
||||||
|
"$APPDIR/usr/lib/x86_64-linux-gnu/perl"/* \
|
||||||
|
"$APPDIR/usr/lib/x86_64-linux-gnu/perl5"/* \
|
||||||
|
"$APPDIR/usr/share/perl"/* \
|
||||||
|
"$APPDIR/usr/share/perl5"
|
||||||
|
do
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
perl5lib_entries="${perl5lib_entries:+$perl5lib_entries:}$dir"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$perl5lib_entries" ]; then
|
||||||
|
export PERL5LIB="$perl5lib_entries${PERL5LIB:+:$PERL5LIB}"
|
||||||
|
fi
|
||||||
|
|
||||||
export PYTHONHOME="$APPDIR/usr"
|
export PYTHONHOME="$APPDIR/usr"
|
||||||
python_stdlib_dir="$(find "$APPDIR/usr/lib" -maxdepth 1 -type d -name 'python3.*' | head -n 1 || true)"
|
python_stdlib_dir="$(find "$APPDIR/usr/lib" -maxdepth 1 -type d -name 'python3.*' | head -n 1 || true)"
|
||||||
pythonpath_entries=""
|
pythonpath_entries=""
|
||||||
@@ -256,7 +287,6 @@ jobs:
|
|||||||
EOF
|
EOF
|
||||||
chmod +x AppRun
|
chmod +x AppRun
|
||||||
|
|
||||||
|
|
||||||
VERSION="$(git describe --tags --always)"
|
VERSION="$(git describe --tags --always)"
|
||||||
|
|
||||||
./linuxdeploy-x86_64.AppImage \
|
./linuxdeploy-x86_64.AppImage \
|
||||||
|
|||||||
4
.github/workflows/windows-build.yml
vendored
4
.github/workflows/windows-build.yml
vendored
@@ -65,8 +65,8 @@ jobs:
|
|||||||
Download-WithRetry -Url https://github.com/jrsoftware/issrc/releases/download/is-6_7_1/innosetup-6.7.1.exe -OutFile deps\innosetup-unicode.exe
|
Download-WithRetry -Url https://github.com/jrsoftware/issrc/releases/download/is-6_7_1/innosetup-6.7.1.exe -OutFile deps\innosetup-unicode.exe
|
||||||
& deps\innosetup-unicode.exe /VERYSILENT | Out-Null
|
& deps\innosetup-unicode.exe /VERYSILENT | Out-Null
|
||||||
|
|
||||||
Download-WithRetry -Url https://github.com/ZoiteChat/gvsbuild/releases/download/zoitechat-2.18.0-pre1/GTK3_Gvsbuild_zoitechat-2.18.0-pre1_${{ matrix.platform }}.7z -OutFile deps\gtk-${{ matrix.arch }}.7z
|
Download-WithRetry -Url https://github.com/ZoiteChat/gvsbuild/releases/download/zoitechat-2.18.1/GTK3_Gvsbuild_zoitechat-2.18.1_x64.zip -OutFile deps\gtk-${{ matrix.arch }}.zip
|
||||||
& 7z.exe x deps\gtk-${{ matrix.arch }}.7z -oC:\gtk-build\gtk\x64\release
|
Expand-Archive -LiteralPath deps\gtk-${{ matrix.arch }}.zip -DestinationPath C:\gtk-build\gtk\x64\release -Force
|
||||||
|
|
||||||
Download-WithRetry -Url https://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-hicolor-icon-theme-0.18-1-any.pkg.tar.zst -OutFile deps\hicolor-icon-theme.pkg.tar.zst
|
Download-WithRetry -Url https://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-hicolor-icon-theme-0.18-1-any.pkg.tar.zst -OutFile deps\hicolor-icon-theme.pkg.tar.zst
|
||||||
python -c "import tarfile,zstandard,pathlib;archive=pathlib.Path(r'deps\\hicolor-icon-theme.pkg.tar.zst');target=pathlib.Path(r'C:\\gtk-build\\gtk\\x64\\release');dctx=zstandard.ZstdDecompressor();f=archive.open('rb');reader=dctx.stream_reader(f);tf=tarfile.open(fileobj=reader,mode='r|');[tf.extract(m,path=target) for m in tf if m.name.startswith('mingw64/share/icons/hicolor/')];tf.close();reader.close();f.close()"
|
python -c "import tarfile,zstandard,pathlib;archive=pathlib.Path(r'deps\\hicolor-icon-theme.pkg.tar.zst');target=pathlib.Path(r'C:\\gtk-build\\gtk\\x64\\release');dctx=zstandard.ZstdDecompressor();f=archive.open('rb');reader=dctx.stream_reader(f);tf=tarfile.open(fileobj=reader,mode='r|');[tf.extract(m,path=target) for m in tf if m.name.startswith('mingw64/share/icons/hicolor/')];tf.close();reader.close();f.close()"
|
||||||
|
|||||||
@@ -1,7 +1,28 @@
|
|||||||
ZoiteChat ChangeLog
|
ZoiteChat ChangeLog
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
2.18.1 (2026-05-21)
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- Migrated D-Bus handling to GDBus.
|
||||||
|
- Enabled mouse wheel channel switching by default and consumed handled tab wheel events.
|
||||||
|
- Switched main panes to native GTK scrollbars.
|
||||||
|
- Tightened userlist button and meter layout.
|
||||||
|
- Made the native Windows file chooser modal.
|
||||||
|
- Set the Windows AppUserModelID before GTK startup.
|
||||||
|
- Updated Windows CI to use the new GTK3 bundle zip.
|
||||||
|
- Updated Windows installer architecture checks to use x64-compatible detection.
|
||||||
|
- Bumped the Flatpak Perl runtime to 5.42.2.
|
||||||
|
- Fixed palette color reads to preserve base GTK state.
|
||||||
|
- Fixed auto-replace whole-word matching.
|
||||||
|
- Fixed checksum file stream cleanup.
|
||||||
|
- Fixed byte handling in the Python console.
|
||||||
|
- Guarded GTK drag-and-drop handlers against null windows.
|
||||||
|
- Fixed size_t and integer handling issues.
|
||||||
|
- Removed the Winamp plugin.
|
||||||
|
|
||||||
2.18.0 (2026-04-20)
|
2.18.0 (2026-04-20)
|
||||||
|
-------------------
|
||||||
|
|
||||||
- Added optional close buttons on tabs.
|
- Added optional close buttons on tabs.
|
||||||
- Added Ctrl+W to close tabs and Ctrl+Shift+T to reopen recently closed tabs.
|
- Added Ctrl+W to close tabs and Ctrl+Shift+T to reopen recently closed tabs.
|
||||||
@@ -19,6 +40,7 @@ ZoiteChat ChangeLog
|
|||||||
- Improved AppStream metainfo validation.
|
- Improved AppStream metainfo validation.
|
||||||
|
|
||||||
2.18.0~pre6 (2026-03-30)
|
2.18.0~pre6 (2026-03-30)
|
||||||
|
------------------------
|
||||||
|
|
||||||
- Applied app theme CSS to the menubar consistently across the app.
|
- Applied app theme CSS to the menubar consistently across the app.
|
||||||
- Restored horizontal separator lines in menus.
|
- Restored horizontal separator lines in menus.
|
||||||
|
|||||||
@@ -29,6 +29,28 @@
|
|||||||
<id>zoitechat.desktop</id>
|
<id>zoitechat.desktop</id>
|
||||||
</provides>
|
</provides>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release date="2026-05-21" version="2.18.1">
|
||||||
|
<description>
|
||||||
|
<ul>
|
||||||
|
<li>Migrated D-Bus handling to GDBus.</li>
|
||||||
|
<li>Enabled mouse wheel channel switching by default and consumed handled tab wheel events.</li>
|
||||||
|
<li>Switched main panes to native GTK scrollbars.</li>
|
||||||
|
<li>Tightened userlist button and meter layout.</li>
|
||||||
|
<li>Made the native Windows file chooser modal.</li>
|
||||||
|
<li>Set the Windows AppUserModelID before GTK startup.</li>
|
||||||
|
<li>Updated Windows CI to use the new GTK3 bundle zip.</li>
|
||||||
|
<li>Updated Windows installer architecture checks to use x64-compatible detection.</li>
|
||||||
|
<li>Bumped the Flatpak Perl runtime to 5.42.2.</li>
|
||||||
|
<li>Fixed palette color reads to preserve base GTK state.</li>
|
||||||
|
<li>Fixed auto-replace whole-word matching.</li>
|
||||||
|
<li>Fixed checksum file stream cleanup.</li>
|
||||||
|
<li>Fixed byte handling in the Python console.</li>
|
||||||
|
<li>Guarded GTK drag-and-drop handlers against null windows.</li>
|
||||||
|
<li>Fixed size_t and integer handling issues.</li>
|
||||||
|
<li>Removed the Winamp plugin.</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release date="2026-04-20" version="2.18.0">
|
<release date="2026-04-20" version="2.18.0">
|
||||||
<description>
|
<description>
|
||||||
<p>Tabs and navigation:</p>
|
<p>Tabs and navigation:</p>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
project('zoitechat', 'c',
|
project('zoitechat', 'c',
|
||||||
version: '2.18.0',
|
version: '2.18.1',
|
||||||
meson_version: '>= 0.55.0',
|
meson_version: '>= 0.55.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c17',
|
'c_std=c17',
|
||||||
@@ -19,6 +19,7 @@ libgmodule_dep = dependency('gmodule-2.0')
|
|||||||
libcanberra_dep = dependency('libcanberra', version: '>= 0.22',
|
libcanberra_dep = dependency('libcanberra', version: '>= 0.22',
|
||||||
required: get_option('libcanberra'))
|
required: get_option('libcanberra'))
|
||||||
dbus_dep = dependency('gio-2.0', required: get_option('dbus'))
|
dbus_dep = dependency('gio-2.0', required: get_option('dbus'))
|
||||||
|
libsecret_dep = dependency('libsecret-1', required: false)
|
||||||
|
|
||||||
global_deps = []
|
global_deps = []
|
||||||
if cc.get_id() == 'msvc'
|
if cc.get_id() == 'msvc'
|
||||||
@@ -40,6 +41,7 @@ config_h.set10('ENABLE_NLS', true)
|
|||||||
config_h.set('USE_OPENSSL', libssl_dep.found())
|
config_h.set('USE_OPENSSL', libssl_dep.found())
|
||||||
config_h.set('USE_LIBCANBERRA', libcanberra_dep.found())
|
config_h.set('USE_LIBCANBERRA', libcanberra_dep.found())
|
||||||
config_h.set('USE_DBUS', dbus_dep.found())
|
config_h.set('USE_DBUS', dbus_dep.found())
|
||||||
|
config_h.set('HAVE_LIBSECRET', libsecret_dep.found())
|
||||||
config_h.set('USE_PLUGIN', get_option('plugin'))
|
config_h.set('USE_PLUGIN', get_option('plugin'))
|
||||||
config_h.set('USE_GTK_FRONTEND', get_option('gtk-frontend'))
|
config_h.set('USE_GTK_FRONTEND', get_option('gtk-frontend'))
|
||||||
|
|
||||||
|
|||||||
@@ -91,27 +91,13 @@ static const signed char fish_unbase64[256] = {
|
|||||||
#include <openssl/provider.h>
|
#include <openssl/provider.h>
|
||||||
static OSSL_PROVIDER *legacy_provider;
|
static OSSL_PROVIDER *legacy_provider;
|
||||||
static OSSL_PROVIDER *default_provider;
|
static OSSL_PROVIDER *default_provider;
|
||||||
static OSSL_LIB_CTX *ossl_ctx;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int fish_init(void)
|
int fish_init(void)
|
||||||
{
|
{
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||||
ossl_ctx = OSSL_LIB_CTX_new();
|
legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
|
||||||
if (!ossl_ctx)
|
default_provider = OSSL_PROVIDER_load(NULL, "default");
|
||||||
return 0;
|
|
||||||
|
|
||||||
legacy_provider = OSSL_PROVIDER_load(ossl_ctx, "legacy");
|
|
||||||
if (!legacy_provider) {
|
|
||||||
fish_deinit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
default_provider = OSSL_PROVIDER_load(ossl_ctx, "default");
|
|
||||||
if (!default_provider) {
|
|
||||||
fish_deinit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -129,10 +115,6 @@ void fish_deinit(void)
|
|||||||
default_provider = NULL;
|
default_provider = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ossl_ctx) {
|
|
||||||
OSSL_LIB_CTX_free(ossl_ctx);
|
|
||||||
ossl_ctx = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +260,9 @@ char *fish_cipher(const char *plaintext, size_t plaintext_len, const char *key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||||
cipher = EVP_CIPHER_fetch(ossl_ctx, "BF-CBC", NULL);
|
cipher = EVP_CIPHER_fetch(NULL, "BF-CBC", NULL);
|
||||||
|
if (!cipher)
|
||||||
|
cipher = (EVP_CIPHER *) EVP_bf_cbc();
|
||||||
#else
|
#else
|
||||||
cipher = (EVP_CIPHER *) EVP_bf_cbc();
|
cipher = (EVP_CIPHER *) EVP_bf_cbc();
|
||||||
#endif
|
#endif
|
||||||
@@ -286,7 +270,9 @@ char *fish_cipher(const char *plaintext, size_t plaintext_len, const char *key,
|
|||||||
} else if (mode == EVP_CIPH_ECB_MODE) {
|
} else if (mode == EVP_CIPH_ECB_MODE) {
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||||
cipher = EVP_CIPHER_fetch(ossl_ctx, "BF-ECB", NULL);
|
cipher = EVP_CIPHER_fetch(NULL, "BF-ECB", NULL);
|
||||||
|
if (!cipher)
|
||||||
|
cipher = (EVP_CIPHER *) EVP_bf_ecb();
|
||||||
#else
|
#else
|
||||||
cipher = (EVP_CIPHER *) EVP_bf_ecb();
|
cipher = (EVP_CIPHER *) EVP_bf_ecb();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ static int handle_keyx_notice(char *word[], char *word_eol[], void *userdata) {
|
|||||||
zoitechat_commandf(ph, "quote NOTICE %s :DH1080_FINISH %s%s", sender, pub_key, (mode == FISH_CBC_MODE) ? " CBC" : "");
|
zoitechat_commandf(ph, "quote NOTICE %s :DH1080_FINISH %s%s", sender, pub_key, (mode == FISH_CBC_MODE) ? " CBC" : "");
|
||||||
g_free(pub_key);
|
g_free(pub_key);
|
||||||
} else {
|
} else {
|
||||||
zoitechat_print(ph, "Failed to generate keys");
|
zoitechat_printf(ph, "Failed to generate keys");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
} else if (!strcmp (dh_message, "DH1080_FINISH")) {
|
} else if (!strcmp (dh_message, "DH1080_FINISH")) {
|
||||||
@@ -446,7 +446,7 @@ static int handle_keyx_notice(char *word[], char *word_eol[], void *userdata) {
|
|||||||
zoitechat_printf(ph, "Stored new key for %s (%s)", sender, fish_modes[mode]);
|
zoitechat_printf(ph, "Stored new key for %s (%s)", sender, fish_modes[mode]);
|
||||||
g_free(secret_key);
|
g_free(secret_key);
|
||||||
} else {
|
} else {
|
||||||
zoitechat_print(ph, "Failed to create secret key!");
|
zoitechat_printf(ph, "Failed to create secret key!");
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@@ -548,7 +548,7 @@ static int handle_keyx(char *word[], char *word_eol[], void *userdata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((query_ctx && ctx_type != 3) || (!query_ctx && !irc_is_query(target))) {
|
if ((query_ctx && ctx_type != 3) || (!query_ctx && !irc_is_query(target))) {
|
||||||
zoitechat_print(ph, "You can only exchange keys with individuals");
|
zoitechat_printf(ph, "You can only exchange keys with individuals");
|
||||||
return ZOITECHAT_EAT_ALL;
|
return ZOITECHAT_EAT_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,7 +560,7 @@ static int handle_keyx(char *word[], char *word_eol[], void *userdata) {
|
|||||||
|
|
||||||
g_free(pub_key);
|
g_free(pub_key);
|
||||||
} else {
|
} else {
|
||||||
zoitechat_print(ph, "Failed to generate keys");
|
zoitechat_printf(ph, "Failed to generate keys");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ZOITECHAT_EAT_ALL;
|
return ZOITECHAT_EAT_ALL;
|
||||||
@@ -577,7 +577,7 @@ static int handle_crypt_topic(char *word[], char *word_eol[], void *userdata) {
|
|||||||
GSList *encrypted_list;
|
GSList *encrypted_list;
|
||||||
|
|
||||||
if (!*topic) {
|
if (!*topic) {
|
||||||
zoitechat_print(ph, usage_topic);
|
zoitechat_printf(ph, "%s", usage_topic);
|
||||||
return ZOITECHAT_EAT_ALL;
|
return ZOITECHAT_EAT_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,7 +624,7 @@ static int handle_crypt_notice(char *word[], char *word_eol[], void *userdata) {
|
|||||||
GSList *encrypted_list, *encrypted_item;
|
GSList *encrypted_list, *encrypted_item;
|
||||||
|
|
||||||
if (!*target || !*notice) {
|
if (!*target || !*notice) {
|
||||||
zoitechat_print(ph, usage_notice);
|
zoitechat_printf(ph, "%s", usage_notice);
|
||||||
return ZOITECHAT_EAT_ALL;
|
return ZOITECHAT_EAT_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,7 +676,7 @@ static int handle_crypt_msg(char *word[], char *word_eol[], void *userdata) {
|
|||||||
GSList *encrypted_list, *encrypted_item;
|
GSList *encrypted_list, *encrypted_item;
|
||||||
|
|
||||||
if (!*target || !*message) {
|
if (!*target || !*message) {
|
||||||
zoitechat_print(ph, usage_msg);
|
zoitechat_printf(ph, "%s", usage_msg);
|
||||||
return ZOITECHAT_EAT_ALL;
|
return ZOITECHAT_EAT_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -805,11 +805,15 @@ int zoitechat_plugin_init(zoitechat_plugin *plugin_handle,
|
|||||||
zoitechat_hook_server_attrs(ph, "TOPIC", ZOITECHAT_PRI_NORM, handle_incoming, NULL);
|
zoitechat_hook_server_attrs(ph, "TOPIC", ZOITECHAT_PRI_NORM, handle_incoming, NULL);
|
||||||
zoitechat_hook_server_attrs(ph, "332", ZOITECHAT_PRI_NORM, handle_incoming, NULL);
|
zoitechat_hook_server_attrs(ph, "332", ZOITECHAT_PRI_NORM, handle_incoming, NULL);
|
||||||
|
|
||||||
if (!fish_init())
|
if (!fish_init()) {
|
||||||
|
zoitechat_printf(ph, "FiSHLiM failed to initialize crypto backend");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dh1080_init())
|
if (!dh1080_init()) {
|
||||||
|
zoitechat_printf(ph, "FiSHLiM failed to initialize DH1080");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
pending_exchanges = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
pending_exchanges = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
||||||
|
|
||||||
|
|||||||
@@ -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'
|
VERSION = b'2.18.1'
|
||||||
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)
|
||||||
@@ -320,9 +320,9 @@ def _on_say_command(word, word_eol, userdata):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
python = _cstr(word_eol[1])
|
python = __decode(_cstr(word_eol[1]))
|
||||||
except Exception:
|
except Exception:
|
||||||
python = b''
|
python = ''
|
||||||
|
|
||||||
if not python:
|
if not python:
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
17
readme.md
17
readme.md
@@ -31,12 +31,19 @@
|
|||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
|
||||||
ZoiteChat is an HexChat based IRC client for Windows and UNIX-like operating systems.
|
ZoiteChat is a GTK3 IRC client based on HexChat, available for Windows and UNIX-like operating systems.
|
||||||
See [IRCHelp.org](http://irchelp.org) for information about IRC in general.
|
|
||||||
For more information on ZoiteChat please read our [documentation](https://docs.zoitechat.org/):
|
|
||||||
- [Downloads](https://zoitechat.org/download)
|
|
||||||
|
|
||||||
- [Troubleshooting](troubleshooting.md)
|
Features include HexChat-compatible Python, Perl and Lua scripting support, a plugin API,
|
||||||
|
multiple server/channel windows, spell checking, multiple authentication methods including SASL,
|
||||||
|
and customizable notifications.
|
||||||
|
|
||||||
|
See [IRCHelp.org](http://irchelp.org) for information about IRC in general.
|
||||||
|
|
||||||
|
For more information on ZoiteChat:
|
||||||
|
|
||||||
|
- [Main Documentation](https://docs.zoitechat.org/) and [FAQ](https://docs.zoitechat.org/en/latest/faq.html)
|
||||||
|
|
||||||
|
- [Downloads](https://zoitechat.org/download.php)
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -447,6 +447,7 @@ const struct prefs vars[] =
|
|||||||
{"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_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_mouse_scroll_speed", P_OFFINT (hex_gui_mouse_scroll_speed), TYPE_INT},
|
||||||
{"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},
|
||||||
{"gui_tab_scrollchans", P_OFFINT (hex_gui_tab_scrollchans), TYPE_BOOL},
|
{"gui_tab_scrollchans", P_OFFINT (hex_gui_tab_scrollchans), TYPE_BOOL},
|
||||||
@@ -517,6 +518,7 @@ const struct prefs vars[] =
|
|||||||
{"irc_conf_mode", P_OFFINT (hex_irc_conf_mode), TYPE_BOOL},
|
{"irc_conf_mode", P_OFFINT (hex_irc_conf_mode), TYPE_BOOL},
|
||||||
{"irc_extra_hilight", P_OFFSET (hex_irc_extra_hilight), TYPE_STR},
|
{"irc_extra_hilight", P_OFFSET (hex_irc_extra_hilight), TYPE_STR},
|
||||||
{"irc_hide_nickchange", P_OFFINT (hex_irc_hide_nickchange), TYPE_BOOL},
|
{"irc_hide_nickchange", P_OFFINT (hex_irc_hide_nickchange), TYPE_BOOL},
|
||||||
|
{"irc_hide_join_part_hostmask", P_OFFINT (hex_irc_hide_join_part_hostmask), TYPE_BOOL},
|
||||||
{"irc_hide_version", P_OFFINT (hex_irc_hide_version), TYPE_BOOL},
|
{"irc_hide_version", P_OFFINT (hex_irc_hide_version), TYPE_BOOL},
|
||||||
{"irc_hidehost", P_OFFINT (hex_irc_hidehost), TYPE_BOOL},
|
{"irc_hidehost", P_OFFINT (hex_irc_hidehost), TYPE_BOOL},
|
||||||
{"irc_id_ntext", P_OFFSET (hex_irc_id_ntext), TYPE_STR},
|
{"irc_id_ntext", P_OFFSET (hex_irc_id_ntext), TYPE_STR},
|
||||||
@@ -548,6 +550,10 @@ const struct prefs vars[] =
|
|||||||
#endif
|
#endif
|
||||||
{"net_bind_host", P_OFFSET (hex_net_bind_host), TYPE_STR},
|
{"net_bind_host", P_OFFSET (hex_net_bind_host), TYPE_STR},
|
||||||
{"net_ping_timeout", P_OFFINT (hex_net_ping_timeout), TYPE_INT, zoitechat_reinit_timers},
|
{"net_ping_timeout", P_OFFINT (hex_net_ping_timeout), TYPE_INT, zoitechat_reinit_timers},
|
||||||
|
{"net_lag_check", P_OFFINT (hex_net_lag_check), TYPE_INT, zoitechat_reinit_timers},
|
||||||
|
{"net_keepalive_idle", P_OFFINT (hex_net_keepalive_idle), TYPE_INT},
|
||||||
|
{"net_keepalive_interval", P_OFFINT (hex_net_keepalive_interval), TYPE_INT},
|
||||||
|
{"net_keepalive_count", P_OFFINT (hex_net_keepalive_count), TYPE_INT},
|
||||||
{"net_proxy_auth", P_OFFINT (hex_net_proxy_auth), TYPE_BOOL},
|
{"net_proxy_auth", P_OFFINT (hex_net_proxy_auth), TYPE_BOOL},
|
||||||
{"net_proxy_host", P_OFFSET (hex_net_proxy_host), TYPE_STR},
|
{"net_proxy_host", P_OFFSET (hex_net_proxy_host), TYPE_STR},
|
||||||
{"net_proxy_pass", P_OFFSET (hex_net_proxy_pass), TYPE_STR},
|
{"net_proxy_pass", P_OFFSET (hex_net_proxy_pass), TYPE_STR},
|
||||||
@@ -783,6 +789,7 @@ load_default_config(void)
|
|||||||
prefs.hex_gui_tab_server = 1;
|
prefs.hex_gui_tab_server = 1;
|
||||||
prefs.hex_gui_tab_sort = 1;
|
prefs.hex_gui_tab_sort = 1;
|
||||||
prefs.hex_gui_tab_scrollchans = 1;
|
prefs.hex_gui_tab_scrollchans = 1;
|
||||||
|
prefs.hex_gui_mouse_scroll_speed = 10;
|
||||||
prefs.hex_gui_topicbar = 1;
|
prefs.hex_gui_topicbar = 1;
|
||||||
prefs.hex_gui_transparency = 255;
|
prefs.hex_gui_transparency = 255;
|
||||||
prefs.hex_gui_tray = 1;
|
prefs.hex_gui_tray = 1;
|
||||||
@@ -858,6 +865,10 @@ load_default_config(void)
|
|||||||
prefs.hex_irc_ban_type = 1;
|
prefs.hex_irc_ban_type = 1;
|
||||||
prefs.hex_irc_join_delay = 5;
|
prefs.hex_irc_join_delay = 5;
|
||||||
prefs.hex_net_ping_timeout = 60;
|
prefs.hex_net_ping_timeout = 60;
|
||||||
|
prefs.hex_net_lag_check = 60;
|
||||||
|
prefs.hex_net_keepalive_idle = 60;
|
||||||
|
prefs.hex_net_keepalive_interval = 20;
|
||||||
|
prefs.hex_net_keepalive_count = 3;
|
||||||
prefs.hex_net_reconnect_delay = 10;
|
prefs.hex_net_reconnect_delay = 10;
|
||||||
prefs.hex_notify_timeout = 15;
|
prefs.hex_notify_timeout = 15;
|
||||||
prefs.hex_text_max_indent = 256;
|
prefs.hex_text_max_indent = 256;
|
||||||
@@ -1168,7 +1179,10 @@ set_showval (session *sess, const struct prefs *var, char *tbuf)
|
|||||||
switch (var->type)
|
switch (var->type)
|
||||||
{
|
{
|
||||||
case TYPE_STR:
|
case TYPE_STR:
|
||||||
sprintf (tbuf + len, "\0033:\017 %s\n", (char *) &prefs + var->offset);
|
{
|
||||||
|
const char *value = (char *) &prefs + var->offset;
|
||||||
|
sprintf (tbuf + len, "\0033:\017 %s\n", value ? value : "");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
sprintf (tbuf + len, "\0033:\017 %d\n", *((int *) &prefs + var->offset));
|
sprintf (tbuf + len, "\0033:\017 %d\n", *((int *) &prefs + var->offset));
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
<ClInclude Include="public_suffix_data.h" />
|
<ClInclude Include="public_suffix_data.h" />
|
||||||
<ClInclude Include="server.h" />
|
<ClInclude Include="server.h" />
|
||||||
<ClInclude Include="servlist.h" />
|
<ClInclude Include="servlist.h" />
|
||||||
|
<ClInclude Include="secretstore.h" />
|
||||||
<ClInclude Include="ssl.h" />
|
<ClInclude Include="ssl.h" />
|
||||||
<ClInclude Include="scram.h" />
|
<ClInclude Include="scram.h" />
|
||||||
<ClInclude Include="sysinfo\sysinfo.h" />
|
<ClInclude Include="sysinfo\sysinfo.h" />
|
||||||
@@ -68,6 +69,7 @@
|
|||||||
<ClCompile Include="proto-irc.c" />
|
<ClCompile Include="proto-irc.c" />
|
||||||
<ClCompile Include="server.c" />
|
<ClCompile Include="server.c" />
|
||||||
<ClCompile Include="servlist.c" />
|
<ClCompile Include="servlist.c" />
|
||||||
|
<ClCompile Include="secretstore.c" />
|
||||||
<ClCompile Include="ssl.c" />
|
<ClCompile Include="ssl.c" />
|
||||||
<ClCompile Include="scram.c" />
|
<ClCompile Include="scram.c" />
|
||||||
<ClCompile Include="sts.c" />
|
<ClCompile Include="sts.c" />
|
||||||
|
|||||||
@@ -74,6 +74,9 @@
|
|||||||
<ClInclude Include="servlist.h">
|
<ClInclude Include="servlist.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="secretstore.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="ssl.h">
|
<ClInclude Include="ssl.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -178,6 +181,9 @@
|
|||||||
<ClCompile Include="servlist.c">
|
<ClCompile Include="servlist.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="secretstore.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="ssl.c">
|
<ClCompile Include="ssl.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@@ -304,29 +304,24 @@ dcc_check_timeouts (void)
|
|||||||
static int
|
static int
|
||||||
dcc_lookup_proxy (char *host, struct sockaddr_in *addr)
|
dcc_lookup_proxy (char *host, struct sockaddr_in *addr)
|
||||||
{
|
{
|
||||||
struct hostent *h;
|
|
||||||
static char *cache_host = NULL;
|
static char *cache_host = NULL;
|
||||||
static guint32 cache_addr;
|
static guint32 cache_addr;
|
||||||
|
|
||||||
/* too lazy to thread this, so we cache results */
|
|
||||||
if (cache_host)
|
if (cache_host)
|
||||||
{
|
{
|
||||||
if (strcmp (host, cache_host) == 0)
|
if (strcmp (host, cache_host) == 0)
|
||||||
{
|
{
|
||||||
memcpy (&addr->sin_addr, &cache_addr, 4);
|
addr->sin_addr.s_addr = cache_addr;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
g_free (cache_host);
|
g_free (cache_host);
|
||||||
cache_host = NULL;
|
cache_host = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
h = gethostbyname (host);
|
if (net_lookup_ipv4 (host, &addr->sin_addr.s_addr))
|
||||||
if (h != NULL && h->h_length == 4 && h->h_addr_list[0] != NULL)
|
|
||||||
{
|
{
|
||||||
memcpy (&addr->sin_addr, h->h_addr_list[0], 4);
|
cache_addr = addr->sin_addr.s_addr;
|
||||||
memcpy (&cache_addr, h->h_addr_list[0], 4);
|
|
||||||
cache_host = g_strdup (host);
|
cache_host = g_strdup (host);
|
||||||
/* cppcheck-suppress memleak */
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1614,25 +1609,14 @@ dcc_accept (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
guint32
|
guint32
|
||||||
dcc_get_my_address (session *sess) /* the address we'll tell the other person */
|
dcc_get_my_address (session *sess)
|
||||||
{
|
{
|
||||||
struct hostent *dns_query;
|
|
||||||
guint32 addr = 0;
|
guint32 addr = 0;
|
||||||
|
|
||||||
if (prefs.hex_dcc_ip_from_server && sess->server->dcc_ip)
|
if (prefs.hex_dcc_ip_from_server && sess->server->dcc_ip)
|
||||||
addr = sess->server->dcc_ip;
|
addr = sess->server->dcc_ip;
|
||||||
else if (prefs.hex_dcc_ip[0])
|
else if (prefs.hex_dcc_ip[0])
|
||||||
{
|
net_lookup_ipv4 ((const char *) prefs.hex_dcc_ip, &addr);
|
||||||
dns_query = gethostbyname ((const char *) prefs.hex_dcc_ip);
|
|
||||||
|
|
||||||
if (dns_query != NULL &&
|
|
||||||
dns_query->h_length == 4 &&
|
|
||||||
dns_query->h_addr_list[0] != NULL)
|
|
||||||
{
|
|
||||||
/*we're offered at least one IPv4 address: we take the first*/
|
|
||||||
addr = *((guint32*) dns_query->h_addr_list[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "ignore.h"
|
#include "ignore.h"
|
||||||
#include "fe.h"
|
#include "fe.h"
|
||||||
#include "modes.h"
|
#include "modes.h"
|
||||||
|
#include "network.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "outbound.h"
|
#include "outbound.h"
|
||||||
#include "inbound.h"
|
#include "inbound.h"
|
||||||
@@ -1476,14 +1477,13 @@ inbound_uback (server *serv, const message_tags_data *tags_data)
|
|||||||
void
|
void
|
||||||
inbound_foundip (session *sess, char *ip, const message_tags_data *tags_data)
|
inbound_foundip (session *sess, char *ip, const message_tags_data *tags_data)
|
||||||
{
|
{
|
||||||
struct hostent *HostAddr;
|
struct in_addr addr;
|
||||||
|
|
||||||
HostAddr = gethostbyname (ip);
|
if (net_lookup_ipv4 (ip, &addr.s_addr))
|
||||||
if (HostAddr)
|
|
||||||
{
|
{
|
||||||
sess->server->dcc_ip = ((struct in_addr *) HostAddr->h_addr_list[0])->s_addr;
|
sess->server->dcc_ip = addr.s_addr;
|
||||||
EMIT_SIGNAL_TIMESTAMP (XP_TE_FOUNDIP, sess->server->server_session,
|
EMIT_SIGNAL_TIMESTAMP (XP_TE_FOUNDIP, sess->server->server_session,
|
||||||
inet_ntoa (*((struct in_addr *) HostAddr->h_addr_list[0])),
|
inet_ntoa (addr),
|
||||||
NULL, NULL, NULL, 0, tags_data->timestamp);
|
NULL, NULL, NULL, 0, tags_data->timestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ common_sources = [
|
|||||||
'util.c'
|
'util.c'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
secretstore_sources = files('secretstore.c')
|
||||||
|
|
||||||
common_sysinfo_deps = []
|
common_sysinfo_deps = []
|
||||||
libarchive_dep = dependency('libarchive', required: host_machine.system() != 'windows')
|
libarchive_dep = dependency('libarchive', required: host_machine.system() != 'windows')
|
||||||
|
|
||||||
@@ -38,6 +40,9 @@ common_deps = [
|
|||||||
if libarchive_dep.found()
|
if libarchive_dep.found()
|
||||||
common_deps += libarchive_dep
|
common_deps += libarchive_dep
|
||||||
endif
|
endif
|
||||||
|
if libsecret_dep.found()
|
||||||
|
common_deps += libsecret_dep
|
||||||
|
endif
|
||||||
|
|
||||||
common_includes = [
|
common_includes = [
|
||||||
config_h_include,
|
config_h_include,
|
||||||
@@ -127,7 +132,7 @@ if get_option('plugin')
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
zoitechat_common = static_library('zoitechatcommon',
|
zoitechat_common = static_library('zoitechatcommon',
|
||||||
sources: [textevents, public_suffix_data] + marshal + common_sources,
|
sources: [textevents, public_suffix_data] + marshal + common_sources + secretstore_sources,
|
||||||
include_directories: config_h_include,
|
include_directories: config_h_include,
|
||||||
dependencies: common_deps + common_sysinfo_deps,
|
dependencies: common_deps + common_sysinfo_deps,
|
||||||
c_args: common_cflags,
|
c_args: common_cflags,
|
||||||
|
|||||||
@@ -34,6 +34,9 @@
|
|||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#ifdef HAVE_NETINET_TCP_H
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WANTSOCKET
|
#define WANTSOCKET
|
||||||
@@ -43,6 +46,9 @@
|
|||||||
|
|
||||||
#define NETWORK_PRIVATE
|
#define NETWORK_PRIVATE
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
#include "zoitechat.h"
|
||||||
|
|
||||||
|
extern struct zoitechatprefs prefs;
|
||||||
|
|
||||||
#define RAND_INT(n) ((int)(rand() / (RAND_MAX + 1.0) * (n)))
|
#define RAND_INT(n) ((int)(rand() / (RAND_MAX + 1.0) * (n)))
|
||||||
|
|
||||||
@@ -58,6 +64,27 @@ net_set_socket_options (int sok)
|
|||||||
setsockopt (sok, SOL_SOCKET, SO_REUSEADDR, (char *) &sw, sizeof (sw));
|
setsockopt (sok, SOL_SOCKET, SO_REUSEADDR, (char *) &sw, sizeof (sw));
|
||||||
sw = 1;
|
sw = 1;
|
||||||
setsockopt (sok, SOL_SOCKET, SO_KEEPALIVE, (char *) &sw, sizeof (sw));
|
setsockopt (sok, SOL_SOCKET, SO_KEEPALIVE, (char *) &sw, sizeof (sw));
|
||||||
|
#ifdef TCP_KEEPIDLE
|
||||||
|
{
|
||||||
|
int keepidle = prefs.hex_net_keepalive_idle;
|
||||||
|
if (keepidle > 0)
|
||||||
|
setsockopt (sok, IPPROTO_TCP, TCP_KEEPIDLE, (char *) &keepidle, sizeof (keepidle));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef TCP_KEEPINTVL
|
||||||
|
{
|
||||||
|
int keepintvl = prefs.hex_net_keepalive_interval;
|
||||||
|
if (keepintvl > 0)
|
||||||
|
setsockopt (sok, IPPROTO_TCP, TCP_KEEPINTVL, (char *) &keepintvl, sizeof (keepintvl));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef TCP_KEEPCNT
|
||||||
|
{
|
||||||
|
int keepcnt = prefs.hex_net_keepalive_count;
|
||||||
|
if (keepcnt > 0)
|
||||||
|
setsockopt (sok, IPPROTO_TCP, TCP_KEEPCNT, (char *) &keepcnt, sizeof (keepcnt));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
@@ -69,6 +96,30 @@ net_ip (uint32_t addr)
|
|||||||
return inet_ntoa (ia);
|
return inet_ntoa (ia);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
net_lookup_ipv4 (const char *hostname, uint32_t *addr)
|
||||||
|
{
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo *res;
|
||||||
|
struct sockaddr_in *sin;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset (&hints, 0, sizeof (hints));
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_flags = AI_ADDRCONFIG;
|
||||||
|
|
||||||
|
ret = getaddrinfo (hostname, NULL, &hints, &res);
|
||||||
|
if (ret != 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
sin = (struct sockaddr_in *) res->ai_addr;
|
||||||
|
*addr = sin->sin_addr.s_addr;
|
||||||
|
freeaddrinfo (res);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
net_store_destroy (netstore * ns)
|
net_store_destroy (netstore * ns)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ int net_connect (netstore *ns, int sok4, int sok6, int *sok_return);
|
|||||||
char *net_resolve (netstore *ns, char *hostname, int port, char **real_host);
|
char *net_resolve (netstore *ns, char *hostname, int port, char **real_host);
|
||||||
void net_bind (netstore *tobindto, int sok4, int sok6);
|
void net_bind (netstore *tobindto, int sok4, int sok6);
|
||||||
char *net_ip (uint32_t addr);
|
char *net_ip (uint32_t addr);
|
||||||
|
int net_lookup_ipv4 (const char *hostname, uint32_t *addr);
|
||||||
void net_sockets (int *sok4, int *sok6);
|
void net_sockets (int *sok4, int *sok6);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3462,28 +3462,45 @@ cmd_server (struct session *sess, char *tbuf, char *word[], char *word_eol[])
|
|||||||
int use_ssl = FALSE;
|
int use_ssl = FALSE;
|
||||||
#endif
|
#endif
|
||||||
int is_url = TRUE;
|
int is_url = TRUE;
|
||||||
|
int no_proxy = FALSE;
|
||||||
server *serv = sess->server;
|
server *serv = sess->server;
|
||||||
ircnet *net = NULL;
|
ircnet *net = NULL;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
/* BitchX uses -ssl, mIRC uses -e, let's support both */
|
if (g_strcmp0 (word[2 + offset], "-ssl") == 0 || g_strcmp0 (word[2 + offset], "-e") == 0)
|
||||||
if (g_strcmp0 (word[2], "-ssl") == 0 || g_strcmp0 (word[2], "-e") == 0)
|
|
||||||
{
|
{
|
||||||
use_ssl = TRUE;
|
use_ssl = TRUE;
|
||||||
offset++; /* args move up by 1 word */
|
use_ssl_noverify = FALSE;
|
||||||
|
offset++;
|
||||||
}
|
}
|
||||||
else if (g_strcmp0 (word[2], "-ssl-noverify") == 0)
|
else if (g_strcmp0 (word[2 + offset], "-ssl-noverify") == 0)
|
||||||
{
|
{
|
||||||
use_ssl = TRUE;
|
use_ssl = TRUE;
|
||||||
use_ssl_noverify = TRUE;
|
use_ssl_noverify = TRUE;
|
||||||
offset++; /* args move up by 1 word */
|
offset++;
|
||||||
}
|
}
|
||||||
else if (g_strcmp0 (word[2], "-insecure") == 0)
|
else if (g_strcmp0 (word[2 + offset], "-insecure") == 0)
|
||||||
{
|
{
|
||||||
use_ssl = FALSE;
|
use_ssl = FALSE;
|
||||||
offset++; /* args move up by 1 word */
|
use_ssl_noverify = FALSE;
|
||||||
|
offset++;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
|
if (g_strcmp0 (word[2 + offset], "-noproxy") == 0)
|
||||||
|
{
|
||||||
|
no_proxy = TRUE;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
serv->dont_use_proxy = no_proxy;
|
||||||
|
|
||||||
if (!parse_irc_url (word[2 + offset], &server_name, &port, &channel, &key, &use_ssl))
|
if (!parse_irc_url (word[2 + offset], &server_name, &port, &channel, &key, &use_ssl))
|
||||||
{
|
{
|
||||||
@@ -3584,10 +3601,18 @@ cmd_servchan (struct session *sess, char *tbuf, char *word[],
|
|||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
if (g_strcmp0 (word[2], "-ssl") == 0 || g_strcmp0 (word[2], "-ssl-noverify") == 0 || g_strcmp0 (word[2], "-insecure") == 0)
|
if (g_strcmp0 (word[2 + offset], "-ssl") == 0 || g_strcmp0 (word[2 + offset], "-ssl-noverify") == 0 || g_strcmp0 (word[2 + offset], "-insecure") == 0)
|
||||||
offset++;
|
offset++;
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
|
if (g_strcmp0 (word[2 + offset], "-noproxy") == 0)
|
||||||
|
offset++;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (*word[4 + offset])
|
if (*word[4 + offset])
|
||||||
{
|
{
|
||||||
@@ -4119,17 +4144,17 @@ const struct commands xc_cmds[] = {
|
|||||||
{"SEND", cmd_send, 0, 0, 1, N_("SEND <nick> [<file>]")},
|
{"SEND", cmd_send, 0, 0, 1, N_("SEND <nick> [<file>]")},
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
{"SERVCHAN", cmd_servchan, 0, 0, 1,
|
{"SERVCHAN", cmd_servchan, 0, 0, 1,
|
||||||
N_("SERVCHAN [-insecure|-ssl|-ssl-noverify] <host> <port> <channel>, connects and joins a channel using ssl unless otherwise specified")},
|
N_("SERVCHAN [-noproxy] [-insecure|-ssl|-ssl-noverify] <host> <port> <channel>, connects and joins a channel using ssl unless otherwise specified")},
|
||||||
#else
|
#else
|
||||||
{"SERVCHAN", cmd_servchan, 0, 0, 1,
|
{"SERVCHAN", cmd_servchan, 0, 0, 1,
|
||||||
N_("SERVCHAN <host> <port> <channel>, connects and joins a channel")},
|
N_("SERVCHAN [-noproxy] <host> <port> <channel>, connects and joins a channel")},
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
{"SERVER", cmd_server, 0, 0, 1,
|
{"SERVER", cmd_server, 0, 0, 1,
|
||||||
N_("SERVER [-insecure|-ssl|-ssl-noverify] <host> [<port>] [<password>], connects to a server using ssl unless otherwise specified, the default port is 6697 for ssl connections and 6667 for insecure connections")},
|
N_("SERVER [-noproxy] [-insecure|-ssl|-ssl-noverify] <host> [<port>] [<password>], connects to a server using ssl unless otherwise specified, the default port is 6697 for ssl connections and 6667 for insecure connections")},
|
||||||
#else
|
#else
|
||||||
{"SERVER", cmd_server, 0, 0, 1,
|
{"SERVER", cmd_server, 0, 0, 1,
|
||||||
N_("SERVER <host> [<port>] [<password>], connects to a server, the default port is 6667")},
|
N_("SERVER [-noproxy] <host> [<port>] [<password>], connects to a server, the default port is 6667")},
|
||||||
#endif
|
#endif
|
||||||
{"SET", cmd_set, 0, 0, 1, N_("SET [-e] [-off|-on] [-quiet] <variable> [<value>]")},
|
{"SET", cmd_set, 0, 0, 1, N_("SET [-e] [-off|-on] [-quiet] <variable> [<value>]")},
|
||||||
{"SETCURSOR", cmd_setcursor, 0, 0, 1, N_("SETCURSOR [-|+]<position>, reposition the cursor in the inputbox")},
|
{"SETCURSOR", cmd_setcursor, 0, 0, 1, N_("SETCURSOR [-|+]<position>, reposition the cursor in the inputbox")},
|
||||||
@@ -4166,10 +4191,10 @@ const struct commands xc_cmds[] = {
|
|||||||
static int
|
static int
|
||||||
command_compare (const void *a, const void *b)
|
command_compare (const void *a, const void *b)
|
||||||
{
|
{
|
||||||
return g_ascii_strcasecmp (a, ((struct commands *)b)->name);
|
return g_ascii_strcasecmp (a, ((const struct commands *)b)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct commands *
|
static const struct commands *
|
||||||
find_internal_command (char *name)
|
find_internal_command (char *name)
|
||||||
{
|
{
|
||||||
/* the "-1" is to skip the NULL terminator */
|
/* the "-1" is to skip the NULL terminator */
|
||||||
@@ -4205,7 +4230,7 @@ usercommand_show_help (session *sess, char *name)
|
|||||||
static void
|
static void
|
||||||
help (session *sess, char *tbuf, char *helpcmd, int quiet)
|
help (session *sess, char *tbuf, char *helpcmd, int quiet)
|
||||||
{
|
{
|
||||||
struct commands *cmd;
|
const struct commands *cmd;
|
||||||
|
|
||||||
if (plugin_show_help (sess, helpcmd))
|
if (plugin_show_help (sess, helpcmd))
|
||||||
return;
|
return;
|
||||||
@@ -4397,7 +4422,7 @@ void
|
|||||||
check_special_chars (char *cmd, int do_ascii) /* check for %X */
|
check_special_chars (char *cmd, int do_ascii) /* check for %X */
|
||||||
{
|
{
|
||||||
int occur = 0;
|
int occur = 0;
|
||||||
int len = strlen (cmd);
|
size_t len = strlen (cmd);
|
||||||
char *buf, *utf;
|
char *buf, *utf;
|
||||||
char tbuf[4];
|
char tbuf[4];
|
||||||
int i = 0, j = 0;
|
int i = 0, j = 0;
|
||||||
@@ -4763,7 +4788,7 @@ handle_command (session *sess, char *cmd, int check_spch)
|
|||||||
char *word[PDIWORDS+1];
|
char *word[PDIWORDS+1];
|
||||||
char *word_eol[PDIWORDS+1];
|
char *word_eol[PDIWORDS+1];
|
||||||
static int command_level = 0;
|
static int command_level = 0;
|
||||||
struct commands *int_cmd;
|
const struct commands *int_cmd;
|
||||||
char *pdibuf;
|
char *pdibuf;
|
||||||
char *tbuf;
|
char *tbuf;
|
||||||
int len;
|
int len;
|
||||||
|
|||||||
@@ -1213,8 +1213,6 @@ zoitechat_get_info (zoitechat_plugin *ph, const char *id)
|
|||||||
|
|
||||||
case 0x4889ba9b: /* password */
|
case 0x4889ba9b: /* password */
|
||||||
case 0x438fdf9: /* nickserv */
|
case 0x438fdf9: /* nickserv */
|
||||||
if (sess->server->network)
|
|
||||||
return ((ircnet *)sess->server->network)->pass;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
case 0xca022f43: /* server */
|
case 0xca022f43: /* server */
|
||||||
|
|||||||
@@ -1017,7 +1017,7 @@ process_named_msg (session *sess, char *type, char *word[], char *word_eol[],
|
|||||||
char *account;
|
char *account;
|
||||||
char ip[128], nick[NICKLEN];
|
char ip[128], nick[NICKLEN];
|
||||||
char *text, *ex;
|
char *text, *ex;
|
||||||
int len = strlen (type);
|
size_t len = strlen (type);
|
||||||
|
|
||||||
/* fill in the "ip" and "nick" buffers */
|
/* fill in the "ip" and "nick" buffers */
|
||||||
ex = strchr (word[1], '!');
|
ex = strchr (word[1], '!');
|
||||||
|
|||||||
173
src/common/secretstore.c
Normal file
173
src/common/secretstore.c
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
#include "zoitechat.h"
|
||||||
|
#include "cfgfiles.h"
|
||||||
|
#include "secretstore.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <wincred.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSECRET
|
||||||
|
#include <libsecret/secret.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char *secretstore_target (const char *network_name)
|
||||||
|
{
|
||||||
|
return g_strdup_printf ("zoitechat/network/%s", network_name ? network_name : "default");
|
||||||
|
}
|
||||||
|
|
||||||
|
int secretstore_is_keyring_available (void)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
return TRUE;
|
||||||
|
#elif defined(HAVE_LIBSECRET)
|
||||||
|
return TRUE;
|
||||||
|
#else
|
||||||
|
return FALSE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
char *secretstore_get_network_password (const char *network_name)
|
||||||
|
{
|
||||||
|
char *target;
|
||||||
|
target = secretstore_target (network_name);
|
||||||
|
#ifdef WIN32
|
||||||
|
{
|
||||||
|
PCREDENTIALA cred = NULL;
|
||||||
|
char *ret = NULL;
|
||||||
|
if (CredReadA (target, CRED_TYPE_GENERIC, 0, &cred))
|
||||||
|
{
|
||||||
|
ret = g_strndup ((const char *) cred->CredentialBlob, cred->CredentialBlobSize);
|
||||||
|
CredFree (cred);
|
||||||
|
}
|
||||||
|
g_free (target);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_LIBSECRET)
|
||||||
|
{
|
||||||
|
static const SecretSchema schema = {
|
||||||
|
"net.zoite.ZoiteChat.Network", SECRET_SCHEMA_NONE,
|
||||||
|
{
|
||||||
|
{ "network", SECRET_SCHEMA_ATTRIBUTE_STRING },
|
||||||
|
{ NULL, 0 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
char *ret = secret_password_lookup_sync (&schema, NULL, NULL, "network", target, NULL);
|
||||||
|
g_free (target);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
g_free (target);
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int secretstore_set_network_password (const char *network_name, const char *password)
|
||||||
|
{
|
||||||
|
char *target;
|
||||||
|
target = secretstore_target (network_name);
|
||||||
|
#ifdef WIN32
|
||||||
|
{
|
||||||
|
CREDENTIALA cred;
|
||||||
|
memset (&cred, 0, sizeof (cred));
|
||||||
|
cred.Type = CRED_TYPE_GENERIC;
|
||||||
|
cred.TargetName = target;
|
||||||
|
cred.CredentialBlobSize = (DWORD) strlen (password);
|
||||||
|
cred.CredentialBlob = (LPBYTE) password;
|
||||||
|
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
|
||||||
|
cred.UserName = "zoitechat";
|
||||||
|
if (!CredWriteA (&cred, 0))
|
||||||
|
{
|
||||||
|
g_free (target);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
g_free (target);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_LIBSECRET)
|
||||||
|
{
|
||||||
|
static const SecretSchema schema = {
|
||||||
|
"net.zoite.ZoiteChat.Network", SECRET_SCHEMA_NONE,
|
||||||
|
{
|
||||||
|
{ "network", SECRET_SCHEMA_ATTRIBUTE_STRING },
|
||||||
|
{ NULL, 0 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
gboolean ok = secret_password_store_sync (&schema, SECRET_COLLECTION_DEFAULT,
|
||||||
|
"ZoiteChat network password", password, NULL, NULL, "network", target, NULL);
|
||||||
|
g_free (target);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
g_free (target);
|
||||||
|
return FALSE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int secretstore_delete_network_password (const char *network_name)
|
||||||
|
{
|
||||||
|
char *target;
|
||||||
|
target = secretstore_target (network_name);
|
||||||
|
#ifdef WIN32
|
||||||
|
{
|
||||||
|
gboolean ok = CredDeleteA (target, CRED_TYPE_GENERIC, 0);
|
||||||
|
g_free (target);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_LIBSECRET)
|
||||||
|
{
|
||||||
|
static const SecretSchema schema = {
|
||||||
|
"net.zoite.ZoiteChat.Network", SECRET_SCHEMA_NONE,
|
||||||
|
{
|
||||||
|
{ "network", SECRET_SCHEMA_ATTRIBUTE_STRING },
|
||||||
|
{ NULL, 0 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
gboolean ok = secret_password_clear_sync (&schema, NULL, NULL, "network", target, NULL);
|
||||||
|
g_free (target);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
g_free (target);
|
||||||
|
return FALSE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int secretstore_require_unlock (const char *network_name)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
return TRUE;
|
||||||
|
#elif defined(HAVE_LIBSECRET)
|
||||||
|
{
|
||||||
|
static const SecretSchema schema = {
|
||||||
|
"net.zoite.ZoiteChat.Network", SECRET_SCHEMA_NONE,
|
||||||
|
{
|
||||||
|
{ "network", SECRET_SCHEMA_ATTRIBUTE_STRING },
|
||||||
|
{ NULL, 0 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
char *target;
|
||||||
|
char *password;
|
||||||
|
GError *error = NULL;
|
||||||
|
target = secretstore_target (network_name);
|
||||||
|
password = secret_password_lookup_sync (&schema, NULL, &error, "network", target, NULL);
|
||||||
|
g_free (target);
|
||||||
|
if (password)
|
||||||
|
{
|
||||||
|
memset (password, 0, strlen (password));
|
||||||
|
g_free (password);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_error_free (error);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return TRUE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
10
src/common/secretstore.h
Normal file
10
src/common/secretstore.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef ZOITECHAT_SECRETSTORE_H
|
||||||
|
#define ZOITECHAT_SECRETSTORE_H
|
||||||
|
|
||||||
|
char *secretstore_get_network_password (const char *network_name);
|
||||||
|
int secretstore_set_network_password (const char *network_name, const char *password);
|
||||||
|
int secretstore_delete_network_password (const char *network_name);
|
||||||
|
int secretstore_is_keyring_available (void);
|
||||||
|
int secretstore_require_unlock (const char *network_name);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -522,7 +522,7 @@ ssl_cb_verify (int ok, X509_STORE_CTX * ctx)
|
|||||||
X509 *current_cert = X509_STORE_CTX_get_current_cert (ctx);
|
X509 *current_cert = X509_STORE_CTX_get_current_cert (ctx);
|
||||||
|
|
||||||
if (!current_cert)
|
if (!current_cert)
|
||||||
return TRUE;
|
return ok;
|
||||||
|
|
||||||
X509_NAME_oneline (X509_get_subject_name (current_cert),
|
X509_NAME_oneline (X509_get_subject_name (current_cert),
|
||||||
subject, sizeof (subject));
|
subject, sizeof (subject));
|
||||||
@@ -534,13 +534,21 @@ ssl_cb_verify (int ok, X509_STORE_CTX * ctx)
|
|||||||
g_snprintf (buf, sizeof (buf), "* Issuer: %s", issuer);
|
g_snprintf (buf, sizeof (buf), "* Issuer: %s", issuer);
|
||||||
EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
|
EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
|
||||||
|
|
||||||
return TRUE;
|
if (!ok)
|
||||||
|
{
|
||||||
|
int err = X509_STORE_CTX_get_error (ctx);
|
||||||
|
g_snprintf (buf, sizeof (buf), "* Verify E: %s (%d)",
|
||||||
|
X509_verify_cert_error_string (err), err);
|
||||||
|
EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ssl_do_connect (server * serv)
|
ssl_do_connect (server * serv)
|
||||||
{
|
{
|
||||||
char buf[256]; // ERR_error_string() MUST have this size
|
char buf[256];
|
||||||
|
|
||||||
g_sess = serv->server_session;
|
g_sess = serv->server_session;
|
||||||
|
|
||||||
@@ -559,9 +567,10 @@ ssl_do_connect (server * serv)
|
|||||||
if (SSL_connect (serv->ssl) <= 0)
|
if (SSL_connect (serv->ssl) <= 0)
|
||||||
{
|
{
|
||||||
char err_buf[128];
|
char err_buf[128];
|
||||||
int err;
|
int err, ssl_err;
|
||||||
|
|
||||||
g_sess = NULL;
|
g_sess = NULL;
|
||||||
|
ssl_err = SSL_get_error (serv->ssl, -1);
|
||||||
if ((err = ERR_get_error ()) > 0)
|
if ((err = ERR_get_error ()) > 0)
|
||||||
{
|
{
|
||||||
ERR_error_string (err, err_buf);
|
ERR_error_string (err, err_buf);
|
||||||
@@ -571,6 +580,8 @@ ssl_do_connect (server * serv)
|
|||||||
|
|
||||||
if (ERR_GET_REASON (err) == SSL_R_WRONG_VERSION_NUMBER)
|
if (ERR_GET_REASON (err) == SSL_R_WRONG_VERSION_NUMBER)
|
||||||
PrintText (serv->server_session, _("Are you sure this is a SSL capable server and port?\n"));
|
PrintText (serv->server_session, _("Are you sure this is a SSL capable server and port?\n"));
|
||||||
|
else if (ssl_err == SSL_ERROR_SSL)
|
||||||
|
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, "* TLS handshake rejected by protocol/certificate/cipher policy", NULL, NULL, NULL, 0);
|
||||||
|
|
||||||
server_cleanup (serv);
|
server_cleanup (serv);
|
||||||
|
|
||||||
@@ -649,29 +660,13 @@ ssl_do_connect (server * serv)
|
|||||||
int hostname_err;
|
int hostname_err;
|
||||||
if ((hostname_err = _SSL_check_hostname(cert, serv->hostname)) != 0)
|
if ((hostname_err = _SSL_check_hostname(cert, serv->hostname)) != 0)
|
||||||
{
|
{
|
||||||
g_snprintf (buf, sizeof (buf), "* Verify E: Failed to validate hostname? (%d)%s",
|
g_snprintf (buf, sizeof (buf), "* Verify E: Failed to validate hostname (%d)",
|
||||||
hostname_err, serv->accept_invalid_cert ? " -- Ignored" : "");
|
hostname_err);
|
||||||
if (serv->accept_invalid_cert)
|
|
||||||
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, 0);
|
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, 0);
|
||||||
else
|
|
||||||
goto conn_fail;
|
goto conn_fail;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
|
||||||
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
|
|
||||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
|
||||||
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
|
||||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
|
||||||
if (serv->accept_invalid_cert)
|
|
||||||
{
|
|
||||||
g_snprintf (buf, sizeof (buf), "* Verify E: %s.? (%d) -- Ignored",
|
|
||||||
X509_verify_cert_error_string (verify_error),
|
|
||||||
verify_error);
|
|
||||||
EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
|
|
||||||
NULL, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
g_snprintf (buf, sizeof (buf), "%s.? (%d)",
|
g_snprintf (buf, sizeof (buf), "%s.? (%d)",
|
||||||
X509_verify_cert_error_string (verify_error),
|
X509_verify_cert_error_string (verify_error),
|
||||||
@@ -881,7 +876,7 @@ server_read_child (GIOChannel *source, GIOCondition condition, server *serv)
|
|||||||
if (prefs.hex_net_auto_reconnectonfail)
|
if (prefs.hex_net_auto_reconnectonfail)
|
||||||
auto_reconnect (serv, FALSE, -1);
|
auto_reconnect (serv, FALSE, -1);
|
||||||
break;
|
break;
|
||||||
case '3': /* gethostbyname finished */
|
case '3': /* resolver finished */
|
||||||
waitline2 (source, host, sizeof host);
|
waitline2 (source, host, sizeof host);
|
||||||
waitline2 (source, ip, sizeof ip);
|
waitline2 (source, ip, sizeof ip);
|
||||||
waitline2 (source, outbuf, sizeof outbuf);
|
waitline2 (source, outbuf, sizeof outbuf);
|
||||||
@@ -932,7 +927,7 @@ server_read_child (GIOChannel *source, GIOCondition condition, server *serv)
|
|||||||
waitline2 (source, tbuf, sizeof tbuf);
|
waitline2 (source, tbuf, sizeof tbuf);
|
||||||
prefs.local_ip = inet_addr (tbuf);
|
prefs.local_ip = inet_addr (tbuf);
|
||||||
break;
|
break;
|
||||||
case '7': /* gethostbyname (prefs.hex_net_bind_host) failed */
|
case '7': /* prefs.hex_net_bind_host resolve failed */
|
||||||
sprintf (outbuf,
|
sprintf (outbuf,
|
||||||
_("Cannot resolve hostname %s\nCheck your IP Settings!\n"),
|
_("Cannot resolve hostname %s\nCheck your IP Settings!\n"),
|
||||||
prefs.hex_net_bind_host);
|
prefs.hex_net_bind_host);
|
||||||
|
|||||||
@@ -33,9 +33,152 @@
|
|||||||
#include "text.h"
|
#include "text.h"
|
||||||
#include "util.h" /* token_foreach */
|
#include "util.h" /* token_foreach */
|
||||||
#include "zoitechatc.h"
|
#include "zoitechatc.h"
|
||||||
|
#include "secretstore.h"
|
||||||
|
|
||||||
#include "servlist.h"
|
#include "servlist.h"
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *
|
||||||
|
servlist_password_encrypt_for_storage (const char *pass)
|
||||||
|
{
|
||||||
|
gchar *material;
|
||||||
|
unsigned char salt[16];
|
||||||
|
unsigned char iv[16];
|
||||||
|
unsigned char key[32];
|
||||||
|
unsigned char *ciphertext;
|
||||||
|
int outlen1;
|
||||||
|
int outlen2;
|
||||||
|
int inlen;
|
||||||
|
int cipherlen;
|
||||||
|
EVP_CIPHER_CTX *ctx;
|
||||||
|
char *b64;
|
||||||
|
char *ret;
|
||||||
|
if (!pass || !*pass)
|
||||||
|
return NULL;
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
if (RAND_bytes (salt, sizeof (salt)) != 1 || RAND_bytes (iv, sizeof (iv)) != 1)
|
||||||
|
return NULL;
|
||||||
|
material = g_strdup_printf ("%s|%s", g_get_user_name (), get_xdir ());
|
||||||
|
if (!PKCS5_PBKDF2_HMAC (material, -1, salt, sizeof (salt), 300000, EVP_sha256 (), sizeof (key), key))
|
||||||
|
{
|
||||||
|
g_free (material);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
g_free (material);
|
||||||
|
inlen = (int) strlen (pass);
|
||||||
|
ciphertext = g_malloc (inlen + EVP_MAX_BLOCK_LENGTH);
|
||||||
|
ctx = EVP_CIPHER_CTX_new ();
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
memset (key, 0, sizeof (key));
|
||||||
|
g_free (ciphertext);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (EVP_EncryptInit_ex (ctx, EVP_aes_256_cbc (), NULL, key, iv) != 1 ||
|
||||||
|
EVP_EncryptUpdate (ctx, ciphertext, &outlen1, (const unsigned char *) pass, inlen) != 1 ||
|
||||||
|
EVP_EncryptFinal_ex (ctx, ciphertext + outlen1, &outlen2) != 1)
|
||||||
|
{
|
||||||
|
EVP_CIPHER_CTX_free (ctx);
|
||||||
|
memset (key, 0, sizeof (key));
|
||||||
|
g_free (ciphertext);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
EVP_CIPHER_CTX_free (ctx);
|
||||||
|
cipherlen = outlen1 + outlen2;
|
||||||
|
{
|
||||||
|
gsize payload_len = sizeof (salt) + sizeof (iv) + (gsize) cipherlen;
|
||||||
|
unsigned char *payload = g_malloc (payload_len);
|
||||||
|
memcpy (payload, salt, sizeof (salt));
|
||||||
|
memcpy (payload + sizeof (salt), iv, sizeof (iv));
|
||||||
|
memcpy (payload + sizeof (salt) + sizeof (iv), ciphertext, cipherlen);
|
||||||
|
b64 = g_base64_encode (payload, payload_len);
|
||||||
|
memset (payload, 0, payload_len);
|
||||||
|
g_free (payload);
|
||||||
|
}
|
||||||
|
memset (key, 0, sizeof (key));
|
||||||
|
memset (ciphertext, 0, inlen + EVP_MAX_BLOCK_LENGTH);
|
||||||
|
g_free (ciphertext);
|
||||||
|
#else
|
||||||
|
b64 = g_base64_encode ((const guchar *) pass, strlen (pass));
|
||||||
|
#endif
|
||||||
|
ret = g_strdup_printf ("enc:%s", b64);
|
||||||
|
g_free (b64);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
servlist_password_is_encrypted (const char *pass)
|
||||||
|
{
|
||||||
|
return pass && g_str_has_prefix (pass, "enc:");
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
servlist_password_decrypt_for_storage (const char *enc)
|
||||||
|
{
|
||||||
|
guchar *raw;
|
||||||
|
gsize len;
|
||||||
|
char *ret;
|
||||||
|
if (!enc || !*enc)
|
||||||
|
return NULL;
|
||||||
|
if (!g_str_has_prefix (enc, "enc:"))
|
||||||
|
return g_strdup (enc);
|
||||||
|
raw = g_base64_decode (enc + 4, &len);
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
if (len <= 32)
|
||||||
|
{
|
||||||
|
g_free (raw);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
unsigned char *salt = raw;
|
||||||
|
unsigned char *iv = raw + 16;
|
||||||
|
unsigned char *ciphertext = raw + 32;
|
||||||
|
int cipherlen = (int) (len - 32);
|
||||||
|
unsigned char key[32];
|
||||||
|
gchar *material = g_strdup_printf ("%s|%s", g_get_user_name (), get_xdir ());
|
||||||
|
unsigned char *plaintext = g_malloc ((gsize) cipherlen + 1);
|
||||||
|
int outlen1;
|
||||||
|
int outlen2;
|
||||||
|
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
||||||
|
if (!ctx || !PKCS5_PBKDF2_HMAC (material, -1, salt, 16, 300000, EVP_sha256 (), sizeof (key), key))
|
||||||
|
{
|
||||||
|
g_free (material);
|
||||||
|
if (ctx)
|
||||||
|
EVP_CIPHER_CTX_free (ctx);
|
||||||
|
g_free (plaintext);
|
||||||
|
g_free (raw);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
g_free (material);
|
||||||
|
if (EVP_DecryptInit_ex (ctx, EVP_aes_256_cbc (), NULL, key, iv) != 1 ||
|
||||||
|
EVP_DecryptUpdate (ctx, plaintext, &outlen1, ciphertext, cipherlen) != 1 ||
|
||||||
|
EVP_DecryptFinal_ex (ctx, plaintext + outlen1, &outlen2) != 1)
|
||||||
|
{
|
||||||
|
EVP_CIPHER_CTX_free (ctx);
|
||||||
|
memset (key, 0, sizeof (key));
|
||||||
|
memset (plaintext, 0, (gsize) cipherlen + 1);
|
||||||
|
g_free (plaintext);
|
||||||
|
g_free (raw);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
EVP_CIPHER_CTX_free (ctx);
|
||||||
|
memset (key, 0, sizeof (key));
|
||||||
|
plaintext[outlen1 + outlen2] = 0;
|
||||||
|
ret = g_strdup ((const char *) plaintext);
|
||||||
|
memset (plaintext, 0, (gsize) cipherlen + 1);
|
||||||
|
g_free (plaintext);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ret = g_strndup ((const char *) raw, len);
|
||||||
|
#endif
|
||||||
|
g_free (raw);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct defaultserver
|
struct defaultserver
|
||||||
{
|
{
|
||||||
@@ -344,10 +487,29 @@ servlist_connect (session *sess, ircnet *net, gboolean join)
|
|||||||
}
|
}
|
||||||
|
|
||||||
serv->password[0] = 0;
|
serv->password[0] = 0;
|
||||||
|
if ((net->flags & FLAG_USE_KEYRING) && net->name)
|
||||||
if (net->pass)
|
|
||||||
{
|
{
|
||||||
safe_strcpy (serv->password, net->pass, sizeof (serv->password));
|
char *stored_pass = secretstore_get_network_password (net->name);
|
||||||
|
if (stored_pass && *stored_pass)
|
||||||
|
{
|
||||||
|
safe_strcpy (serv->password, stored_pass, sizeof (serv->password));
|
||||||
|
}
|
||||||
|
if (stored_pass)
|
||||||
|
{
|
||||||
|
memset (stored_pass, 0, strlen (stored_pass));
|
||||||
|
g_free (stored_pass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (net->pass)
|
||||||
|
{
|
||||||
|
char *plain = servlist_password_decrypt_for_storage (net->pass);
|
||||||
|
if (plain && *plain)
|
||||||
|
safe_strcpy (serv->password, plain, sizeof (serv->password));
|
||||||
|
if (plain)
|
||||||
|
{
|
||||||
|
memset (plain, 0, strlen (plain));
|
||||||
|
g_free (plain);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (net->flags & FLAG_USE_GLOBAL)
|
if (net->flags & FLAG_USE_GLOBAL)
|
||||||
@@ -982,24 +1144,6 @@ servlist_load (void)
|
|||||||
*
|
*
|
||||||
* Should be removed at some point.
|
* Should be removed at some point.
|
||||||
*/
|
*/
|
||||||
case 'A':
|
|
||||||
if (!net->pass)
|
|
||||||
{
|
|
||||||
net->pass = g_strdup (buf + 2);
|
|
||||||
if (!net->logintype)
|
|
||||||
{
|
|
||||||
net->logintype = LOGIN_SASL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 'B':
|
|
||||||
if (!net->pass)
|
|
||||||
{
|
|
||||||
net->pass = g_strdup (buf + 2);
|
|
||||||
if (!net->logintype)
|
|
||||||
{
|
|
||||||
net->logintype = LOGIN_NICKSERV;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (buf[0] == 'N')
|
if (buf[0] == 'N')
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ extern GSList *network_list;
|
|||||||
#define FLAG_USE_PROXY 16
|
#define FLAG_USE_PROXY 16
|
||||||
#define FLAG_ALLOW_INVALID 32
|
#define FLAG_ALLOW_INVALID 32
|
||||||
#define FLAG_FAVORITE 64
|
#define FLAG_FAVORITE 64
|
||||||
#define FLAG_COUNT 7
|
#define FLAG_USE_KEYRING 128
|
||||||
|
#define FLAG_COUNT 8
|
||||||
|
|
||||||
/* Login methods. Use server password by default - if we had a NickServ password, it'd be set to 2 already by servlist_load() */
|
/* Login methods. Use server password by default - if we had a NickServ password, it'd be set to 2 already by servlist_load() */
|
||||||
#define LOGIN_DEFAULT_REAL LOGIN_PASS /* this is to set the default login method for unknown servers */
|
#define LOGIN_DEFAULT_REAL LOGIN_PASS /* this is to set the default login method for unknown servers */
|
||||||
@@ -124,5 +125,8 @@ favchannel *servlist_favchan_copy (favchannel *fav);
|
|||||||
GSList *servlist_favchan_listadd (GSList *chanlist, char *channel, char *key);
|
GSList *servlist_favchan_listadd (GSList *chanlist, char *channel, char *key);
|
||||||
|
|
||||||
gboolean joinlist_is_in_list (server *serv, char *channel);
|
gboolean joinlist_is_in_list (server *serv, char *channel);
|
||||||
|
char *servlist_password_encrypt_for_storage (const char *pass);
|
||||||
|
char *servlist_password_decrypt_for_storage (const char *pass);
|
||||||
|
gboolean servlist_password_is_encrypted (const char *pass);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -86,15 +86,17 @@ _SSL_context_init (void (*info_cb_func))
|
|||||||
|
|
||||||
SSLeay_add_ssl_algorithms ();
|
SSLeay_add_ssl_algorithms ();
|
||||||
SSL_load_error_strings ();
|
SSL_load_error_strings ();
|
||||||
ctx = SSL_CTX_new (SSLv23_client_method ());
|
ctx = SSL_CTX_new (TLS_client_method ());
|
||||||
|
|
||||||
SSL_CTX_set_session_cache_mode (ctx, SSL_SESS_CACHE_BOTH);
|
SSL_CTX_set_session_cache_mode (ctx, SSL_SESS_CACHE_BOTH);
|
||||||
SSL_CTX_set_timeout (ctx, 300);
|
SSL_CTX_set_timeout (ctx, 300);
|
||||||
SSL_CTX_set_options (ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3
|
SSL_CTX_set_options (ctx, SSL_OP_NO_COMPRESSION
|
||||||
|SSL_OP_NO_COMPRESSION
|
|
||||||
|SSL_OP_SINGLE_DH_USE|SSL_OP_SINGLE_ECDH_USE
|
|SSL_OP_SINGLE_DH_USE|SSL_OP_SINGLE_ECDH_USE
|
||||||
|SSL_OP_NO_TICKET
|
|SSL_OP_NO_TICKET
|
||||||
|SSL_OP_CIPHER_SERVER_PREFERENCE);
|
|SSL_OP_NO_RENEGOTIATION);
|
||||||
|
SSL_CTX_set_min_proto_version (ctx, TLS1_2_VERSION);
|
||||||
|
SSL_CTX_set_cipher_list (ctx, "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!DSS");
|
||||||
|
SSL_CTX_set_ciphersuites (ctx, "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256");
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined (OPENSSL_NO_COMP) /* workaround for OpenSSL 0.9.8 */
|
#if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined (OPENSSL_NO_COMP) /* workaround for OpenSSL 0.9.8 */
|
||||||
sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
|
sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
|
||||||
@@ -311,7 +313,7 @@ _SSL_socket (SSL_CTX *ctx, int sd)
|
|||||||
#else
|
#else
|
||||||
method = SSL_CTX_get_ssl_method (ctx);
|
method = SSL_CTX_get_ssl_method (ctx);
|
||||||
#endif
|
#endif
|
||||||
if (method == SSLv23_client_method())
|
if (method == TLS_client_method())
|
||||||
SSL_set_connect_state (ssl);
|
SSL_set_connect_state (ssl);
|
||||||
else
|
else
|
||||||
SSL_set_accept_state(ssl);
|
SSL_set_accept_state(ssl);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -74,6 +75,18 @@ typedef struct
|
|||||||
static bool string_builder_init (StringBuilder *builder);
|
static bool string_builder_init (StringBuilder *builder);
|
||||||
static void string_builder_free (StringBuilder *builder);
|
static void string_builder_free (StringBuilder *builder);
|
||||||
static bool string_builder_append (StringBuilder *builder, const char *text);
|
static bool string_builder_append (StringBuilder *builder, const char *text);
|
||||||
|
static int size_to_int (size_t value);
|
||||||
|
|
||||||
|
static int
|
||||||
|
size_to_int (size_t value)
|
||||||
|
{
|
||||||
|
if (value > (size_t) INT_MAX)
|
||||||
|
{
|
||||||
|
return INT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) value;
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
sysinfo_get_cpu (void)
|
sysinfo_get_cpu (void)
|
||||||
@@ -511,6 +524,7 @@ static char *read_hdd_info (IWbemClassObject *object)
|
|||||||
static char *bstr_to_utf8 (BSTR bstr)
|
static char *bstr_to_utf8 (BSTR bstr)
|
||||||
{
|
{
|
||||||
int utf8_len;
|
int utf8_len;
|
||||||
|
int wide_len;
|
||||||
char *utf8;
|
char *utf8;
|
||||||
|
|
||||||
if (bstr == NULL)
|
if (bstr == NULL)
|
||||||
@@ -518,7 +532,8 @@ static char *bstr_to_utf8 (BSTR bstr)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
utf8_len = WideCharToMultiByte (CP_UTF8, 0, bstr, SysStringLen (bstr), NULL, 0, NULL, NULL);
|
wide_len = size_to_int ((size_t) SysStringLen (bstr));
|
||||||
|
utf8_len = WideCharToMultiByte (CP_UTF8, 0, bstr, wide_len, NULL, 0, NULL, NULL);
|
||||||
if (utf8_len <= 0)
|
if (utf8_len <= 0)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -530,7 +545,7 @@ static char *bstr_to_utf8 (BSTR bstr)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WideCharToMultiByte (CP_UTF8, 0, bstr, SysStringLen (bstr), utf8, utf8_len, NULL, NULL) <= 0)
|
if (WideCharToMultiByte (CP_UTF8, 0, bstr, wide_len, utf8, utf8_len, NULL, NULL) <= 0)
|
||||||
{
|
{
|
||||||
free (utf8);
|
free (utf8);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -1809,12 +1809,97 @@ format_event (session *sess, int index, char **args, char *o, gsize sizeofo, uns
|
|||||||
o[0] = 0;
|
o[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
text_event_without_hostmask_format (const char *format, int host_arg)
|
||||||
|
{
|
||||||
|
char token[3];
|
||||||
|
const char *arg;
|
||||||
|
const char *open;
|
||||||
|
const char *close;
|
||||||
|
const char *start;
|
||||||
|
char *out;
|
||||||
|
gsize prefix_len;
|
||||||
|
|
||||||
|
g_snprintf (token, sizeof (token), "$%d", host_arg);
|
||||||
|
arg = strstr (format, token);
|
||||||
|
if (!arg)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
open = arg;
|
||||||
|
while (open > format && *open != '(' && *open != '\n')
|
||||||
|
open--;
|
||||||
|
|
||||||
|
close = arg + strlen (token);
|
||||||
|
while (*close && *close != ')' && *close != '\n')
|
||||||
|
close++;
|
||||||
|
|
||||||
|
if (*open != '(' || *close != ')')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
start = open;
|
||||||
|
if (start > format && start[-1] == ' ')
|
||||||
|
start--;
|
||||||
|
|
||||||
|
prefix_len = start - format;
|
||||||
|
out = g_malloc (prefix_len + strlen (close + 1) + 1);
|
||||||
|
memcpy (out, format, prefix_len);
|
||||||
|
strcpy (out + prefix_len, close + 1);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
display_event_string (session *sess, int event, char **args, char *format,
|
||||||
|
unsigned int stripcolor_args, time_t timestamp)
|
||||||
|
{
|
||||||
|
char *compiled;
|
||||||
|
char *saved;
|
||||||
|
char o[4096];
|
||||||
|
int max_arg;
|
||||||
|
|
||||||
|
if (pevt_build_string (format, &compiled, &max_arg) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
saved = pntevts[event];
|
||||||
|
pntevts[event] = compiled;
|
||||||
|
format_event (sess, event, args, o, sizeof (o), stripcolor_args);
|
||||||
|
pntevts[event] = saved;
|
||||||
|
g_free (compiled);
|
||||||
|
|
||||||
|
if (o[0])
|
||||||
|
PrintTextTimeStamp (sess, o, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
display_event (session *sess, int event, char **args,
|
display_event (session *sess, int event, char **args,
|
||||||
unsigned int stripcolor_args, time_t timestamp)
|
unsigned int stripcolor_args, time_t timestamp)
|
||||||
{
|
{
|
||||||
char o[4096];
|
char o[4096];
|
||||||
|
char *format;
|
||||||
|
char *host;
|
||||||
|
int host_arg;
|
||||||
|
|
||||||
|
if (prefs.hex_irc_hide_join_part_hostmask &&
|
||||||
|
(event == XP_TE_JOIN || event == XP_TE_PART || event == XP_TE_PARTREASON))
|
||||||
|
{
|
||||||
|
host_arg = event == XP_TE_JOIN ? 3 : 2;
|
||||||
|
format = text_event_without_hostmask_format (pntevts_text[event], host_arg);
|
||||||
|
if (format)
|
||||||
|
{
|
||||||
|
display_event_string (sess, event, args, format, stripcolor_args, timestamp);
|
||||||
|
g_free (format);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
host = args[host_arg];
|
||||||
|
args[host_arg] = "";
|
||||||
format_event (sess, event, args, o, sizeof (o), stripcolor_args);
|
format_event (sess, event, args, o, sizeof (o), stripcolor_args);
|
||||||
|
args[host_arg] = host;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
format_event (sess, event, args, o, sizeof (o), stripcolor_args);
|
||||||
|
}
|
||||||
|
|
||||||
if (o[0])
|
if (o[0])
|
||||||
PrintTextTimeStamp (sess, o, timestamp);
|
PrintTextTimeStamp (sess, o, timestamp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ url_check_line (char *buf)
|
|||||||
for (i = 0; i < ARRAY_SIZE (commands); i++)
|
for (i = 0; i < ARRAY_SIZE (commands); i++)
|
||||||
{
|
{
|
||||||
char *cmd = commands[i];
|
char *cmd = commands[i];
|
||||||
int len = strlen (cmd);
|
size_t len = strlen (cmd);
|
||||||
|
|
||||||
if (strncmp (cmd, po, len) == 0)
|
if (strncmp (cmd, po, len) == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ path_part (char *file, char *path, int pathlen)
|
|||||||
char * /* like strstr(), but nocase */
|
char * /* like strstr(), but nocase */
|
||||||
nocasestrstr (const char *s, const char *wanted)
|
nocasestrstr (const char *s, const char *wanted)
|
||||||
{
|
{
|
||||||
register const int len = strlen (wanted);
|
register const size_t len = strlen (wanted);
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return (char *)s;
|
return (char *)s;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
* Copyright (C) 1998-2010 Peter Zelezny.
|
* Copyright (C) 1998-2010 Peter Zelezny.
|
||||||
* Copyright (C) 2009-2013 Berke Viktor.
|
* Copyright (C) 2009-2013 Berke Viktor.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or
|
||||||
* it under the terms of the GNU General Public License as published by
|
* modify it under the terms of the GNU General Public License
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* as published by the Free Software Foundation; either version 2
|
||||||
* (at your option) any later version.
|
* of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, see
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
* <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* You can distribute this header with your plugins for easy compilation */
|
/* You can distribute this header with your plugins for easy compilation */
|
||||||
|
|||||||
@@ -379,6 +379,7 @@ lag_check (void)
|
|||||||
char tbuf[128];
|
char tbuf[128];
|
||||||
time_t now = time (0);
|
time_t now = time (0);
|
||||||
time_t lag;
|
time_t lag;
|
||||||
|
time_t ping_age;
|
||||||
|
|
||||||
tim = make_ping_time ();
|
tim = make_ping_time ();
|
||||||
|
|
||||||
@@ -388,7 +389,7 @@ lag_check (void)
|
|||||||
if (serv->connected && serv->end_of_motd)
|
if (serv->connected && serv->end_of_motd)
|
||||||
{
|
{
|
||||||
lag = now - serv->ping_recv;
|
lag = now - serv->ping_recv;
|
||||||
if (prefs.hex_net_ping_timeout != 0 && lag > prefs.hex_net_ping_timeout && lag > 0)
|
if (serv->lag_sent && prefs.hex_net_ping_timeout != 0 && lag > prefs.hex_net_ping_timeout && lag > 0)
|
||||||
{
|
{
|
||||||
sprintf (tbuf, "%" G_GINT64_FORMAT, (gint64) lag);
|
sprintf (tbuf, "%" G_GINT64_FORMAT, (gint64) lag);
|
||||||
EMIT_SIGNAL (XP_TE_PINGTIMEOUT, serv->server_session, tbuf, NULL,
|
EMIT_SIGNAL (XP_TE_PINGTIMEOUT, serv->server_session, tbuf, NULL,
|
||||||
@@ -397,12 +398,12 @@ lag_check (void)
|
|||||||
serv->auto_reconnect (serv, FALSE, -1);
|
serv->auto_reconnect (serv, FALSE, -1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
ping_age = now - serv->ping_recv;
|
||||||
|
if (!serv->lag_sent && prefs.hex_net_lag_check > 0 && ping_age >= prefs.hex_net_lag_check)
|
||||||
{
|
{
|
||||||
g_snprintf (tbuf, sizeof (tbuf), "LAG%lu", tim);
|
g_snprintf (tbuf, sizeof (tbuf), "LAG%lu", tim);
|
||||||
serv->p_ping (serv, "", tbuf);
|
serv->p_ping (serv, "", tbuf);
|
||||||
|
|
||||||
if (!serv->lag_sent)
|
|
||||||
{
|
|
||||||
serv->lag_sent = tim;
|
serv->lag_sent = tim;
|
||||||
fe_set_lag (serv, -1);
|
fe_set_lag (serv, -1);
|
||||||
}
|
}
|
||||||
@@ -525,7 +526,7 @@ zoitechat_reinit_timers (void)
|
|||||||
if ((prefs.hex_net_ping_timeout != 0 || prefs.hex_gui_lagometer)
|
if ((prefs.hex_net_ping_timeout != 0 || prefs.hex_gui_lagometer)
|
||||||
&& lag_check_tag == 0)
|
&& lag_check_tag == 0)
|
||||||
{
|
{
|
||||||
lag_check_tag = fe_timeout_add_seconds (30, zoitechat_lag_check, NULL);
|
lag_check_tag = fe_timeout_add_seconds (1, zoitechat_lag_check, NULL);
|
||||||
}
|
}
|
||||||
else if ((!prefs.hex_net_ping_timeout && !prefs.hex_gui_lagometer)
|
else if ((!prefs.hex_net_ping_timeout && !prefs.hex_gui_lagometer)
|
||||||
&& lag_check_tag != 0)
|
&& lag_check_tag != 0)
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ struct zoitechatprefs
|
|||||||
unsigned int hex_irc_conf_mode;
|
unsigned int hex_irc_conf_mode;
|
||||||
unsigned int hex_irc_hidehost;
|
unsigned int hex_irc_hidehost;
|
||||||
unsigned int hex_irc_hide_nickchange;
|
unsigned int hex_irc_hide_nickchange;
|
||||||
|
unsigned int hex_irc_hide_join_part_hostmask;
|
||||||
unsigned int hex_irc_hide_version;
|
unsigned int hex_irc_hide_version;
|
||||||
unsigned int hex_irc_invisible;
|
unsigned int hex_irc_invisible;
|
||||||
unsigned int hex_irc_logging;
|
unsigned int hex_irc_logging;
|
||||||
@@ -267,6 +268,7 @@ struct zoitechatprefs
|
|||||||
int hex_gui_tab_layout;
|
int hex_gui_tab_layout;
|
||||||
int hex_gui_tab_closebuttons;
|
int hex_gui_tab_closebuttons;
|
||||||
int hex_gui_tab_middleclose;
|
int hex_gui_tab_middleclose;
|
||||||
|
int hex_gui_mouse_scroll_speed;
|
||||||
int hex_gui_tab_newtofront;
|
int hex_gui_tab_newtofront;
|
||||||
int hex_gui_tab_pos;
|
int hex_gui_tab_pos;
|
||||||
int hex_gui_tab_small;
|
int hex_gui_tab_small;
|
||||||
@@ -289,6 +291,10 @@ struct zoitechatprefs
|
|||||||
int hex_irc_join_delay;
|
int hex_irc_join_delay;
|
||||||
int hex_irc_notice_pos;
|
int hex_irc_notice_pos;
|
||||||
int hex_net_ping_timeout;
|
int hex_net_ping_timeout;
|
||||||
|
int hex_net_lag_check;
|
||||||
|
int hex_net_keepalive_idle;
|
||||||
|
int hex_net_keepalive_interval;
|
||||||
|
int hex_net_keepalive_count;
|
||||||
int hex_net_proxy_port;
|
int hex_net_proxy_port;
|
||||||
int hex_net_proxy_type; /* 0=disabled, 1=wingate 2=socks4, 3=socks5, 4=http */
|
int hex_net_proxy_type; /* 0=disabled, 1=wingate 2=socks4, 3=socks5, 4=http */
|
||||||
int hex_net_proxy_use; /* 0=all 1=IRC_ONLY 2=DCC_ONLY */
|
int hex_net_proxy_use; /* 0=all 1=IRC_ONLY 2=DCC_ONLY */
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ void
|
|||||||
fe_add_chan_list (server *serv, char *chan, char *users, char *topic)
|
fe_add_chan_list (server *serv, char *chan, char *users, char *topic)
|
||||||
{
|
{
|
||||||
chanlistrow *next_row;
|
chanlistrow *next_row;
|
||||||
int len = strlen (chan) + 1;
|
size_t len = strlen (chan) + 1;
|
||||||
|
|
||||||
/* we allocate the struct and channel string in one go */
|
/* we allocate the struct and channel string in one go */
|
||||||
next_row = g_malloc (sizeof (chanlistrow) + len);
|
next_row = g_malloc (sizeof (chanlistrow) + len);
|
||||||
|
|||||||
@@ -305,11 +305,13 @@ static gboolean
|
|||||||
tab_scroll_cb (GtkWidget *widget, GdkEventScroll *event, gpointer cv)
|
tab_scroll_cb (GtkWidget *widget, GdkEventScroll *event, gpointer cv)
|
||||||
{
|
{
|
||||||
int direction = cv_scroll_direction (event);
|
int direction = cv_scroll_direction (event);
|
||||||
|
int i;
|
||||||
|
|
||||||
if (prefs.hex_gui_tab_scrollchans)
|
if (prefs.hex_gui_tab_scrollchans)
|
||||||
{
|
{
|
||||||
if (direction != 0)
|
if (direction != 0)
|
||||||
{
|
{
|
||||||
|
for (i = 0; i < cv_scroll_step_count (); i++)
|
||||||
mg_switch_page (1, direction);
|
mg_switch_page (1, direction);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -318,11 +320,13 @@ tab_scroll_cb (GtkWidget *widget, GdkEventScroll *event, gpointer cv)
|
|||||||
{
|
{
|
||||||
if (direction < 0)
|
if (direction < 0)
|
||||||
{
|
{
|
||||||
|
for (i = 0; i < cv_scroll_step_count (); i++)
|
||||||
tab_scroll_left_up_clicked (widget, cv);
|
tab_scroll_left_up_clicked (widget, cv);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
else if (direction > 0)
|
else if (direction > 0)
|
||||||
{
|
{
|
||||||
|
for (i = 0; i < cv_scroll_step_count (); i++)
|
||||||
tab_scroll_right_down_clicked (widget, cv);
|
tab_scroll_right_down_clicked (widget, cv);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -353,13 +357,12 @@ cv_tabs_init (chanview *cv)
|
|||||||
|
|
||||||
viewport = gtk_scrolled_window_new (0, 0);
|
viewport = gtk_scrolled_window_new (0, 0);
|
||||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (viewport), GTK_SHADOW_NONE);
|
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (viewport), GTK_SHADOW_NONE);
|
||||||
gtk_scrolled_window_set_overlay_scrolling (GTK_SCROLLED_WINDOW (viewport), FALSE);
|
|
||||||
if (cv->vertical)
|
if (cv->vertical)
|
||||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (viewport),
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (viewport),
|
||||||
GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
|
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||||
else
|
else
|
||||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (viewport),
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (viewport),
|
||||||
GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
|
||||||
gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (viewport), 1);
|
gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (viewport), 1);
|
||||||
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (viewport), 1);
|
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (viewport), 1);
|
||||||
gtk_widget_set_hexpand (viewport, TRUE);
|
gtk_widget_set_hexpand (viewport, TRUE);
|
||||||
|
|||||||
@@ -112,8 +112,10 @@ cv_tree_scroll_event_cb (GtkWidget *widget, GdkEventScroll *event, gpointer user
|
|||||||
if (prefs.hex_gui_tab_scrollchans)
|
if (prefs.hex_gui_tab_scrollchans)
|
||||||
{
|
{
|
||||||
int direction = cv_scroll_direction (event);
|
int direction = cv_scroll_direction (event);
|
||||||
|
int i;
|
||||||
|
|
||||||
if (direction != 0)
|
if (direction != 0)
|
||||||
|
for (i = 0; i < cv_scroll_step_count (); i++)
|
||||||
mg_switch_page (1, direction);
|
mg_switch_page (1, direction);
|
||||||
|
|
||||||
return direction != 0;
|
return direction != 0;
|
||||||
|
|||||||
@@ -126,6 +126,15 @@ cv_scroll_direction (GdkEventScroll *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cv_scroll_step_count (void)
|
||||||
|
{
|
||||||
|
int speed = prefs.hex_gui_mouse_scroll_speed;
|
||||||
|
if (speed < 1)
|
||||||
|
speed = 1;
|
||||||
|
return (speed + 9) / 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ======= TABS ======= */
|
/* ======= TABS ======= */
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,25 @@ create_msg_dialog (gchar *title, gchar *message)
|
|||||||
|
|
||||||
static char *win32_argv0_dir;
|
static char *win32_argv0_dir;
|
||||||
|
|
||||||
|
static void
|
||||||
|
win32_set_appusermodelid (void)
|
||||||
|
{
|
||||||
|
HMODULE shell32;
|
||||||
|
HRESULT (WINAPI *set_appid) (PCWSTR);
|
||||||
|
|
||||||
|
shell32 = GetModuleHandleW (L"shell32.dll");
|
||||||
|
if (!shell32)
|
||||||
|
shell32 = LoadLibraryW (L"shell32.dll");
|
||||||
|
if (!shell32)
|
||||||
|
return;
|
||||||
|
|
||||||
|
set_appid = (HRESULT (WINAPI *) (PCWSTR)) GetProcAddress (shell32, "SetCurrentProcessExplicitAppUserModelID");
|
||||||
|
if (!set_appid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
set_appid (L"ZoiteChat.Desktop.Notify");
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
win32_set_gsettings_schema_dir (void)
|
win32_set_gsettings_schema_dir (void)
|
||||||
{
|
{
|
||||||
@@ -422,6 +441,7 @@ fe_args (int argc, char *argv[])
|
|||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
win32_set_gsettings_schema_dir ();
|
win32_set_gsettings_schema_dir ();
|
||||||
|
win32_set_appusermodelid ();
|
||||||
win32_configure_pixbuf_loaders ();
|
win32_configure_pixbuf_loaders ();
|
||||||
|
|
||||||
/* this is mainly for irc:// URL handling. When windows calls us from */
|
/* this is mainly for irc:// URL handling. When windows calls us from */
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ void key_action_tab_clean (void);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Remember that the *number* of actions is this *plus* 1 --AGL */
|
/* Remember that the *number* of actions is this *plus* 1 --AGL */
|
||||||
#define KEY_MAX_ACTIONS 14
|
#define KEY_MAX_ACTIONS 16
|
||||||
|
|
||||||
struct key_binding
|
struct key_binding
|
||||||
{
|
{
|
||||||
@@ -142,6 +142,13 @@ static int key_action_move_tab_family_right (GtkWidget * wid, GdkEventKey * evt,
|
|||||||
static int key_action_put_history (GtkWidget * wid, GdkEventKey * evt,
|
static int key_action_put_history (GtkWidget * wid, GdkEventKey * evt,
|
||||||
char *d1, char *d2,
|
char *d1, char *d2,
|
||||||
struct session *sess);
|
struct session *sess);
|
||||||
|
static int key_action_menu_shortcut (GtkWidget * wid, GdkEventKey * evt,
|
||||||
|
char *d1, char *d2,
|
||||||
|
struct session *sess);
|
||||||
|
static int key_action_reopen_closed_tab (GtkWidget * wid, GdkEventKey * evt,
|
||||||
|
char *d1, char *d2,
|
||||||
|
struct session *sess);
|
||||||
|
|
||||||
|
|
||||||
static GSList *keybind_list = NULL;
|
static GSList *keybind_list = NULL;
|
||||||
|
|
||||||
@@ -260,7 +267,7 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
|
|||||||
{key_action_handle_command, "Run Command",
|
{key_action_handle_command, "Run Command",
|
||||||
N_("The \002Run Command\002 action runs the data in Data 1 as if it had been typed into the entry box where you pressed the key sequence. Thus it can contain text (which will be sent to the channel/person), commands or user commands. Escapes in Data 1 are interpreted (for example \002\\n\002, \002\\r\002, \002\\t\002, \002\\xNN\002 and \002\\\\\002), so it is possible to run more than one command by using newlines.")},
|
N_("The \002Run Command\002 action runs the data in Data 1 as if it had been typed into the entry box where you pressed the key sequence. Thus it can contain text (which will be sent to the channel/person), commands or user commands. Escapes in Data 1 are interpreted (for example \002\\n\002, \002\\r\002, \002\\t\002, \002\\xNN\002 and \002\\\\\002), so it is possible to run more than one command by using newlines.")},
|
||||||
{key_action_page_switch, "Change Page",
|
{key_action_page_switch, "Change Page",
|
||||||
N_("The \002Change Page\002 command switches between pages in the notebook. Set Data 1 to the page you want to switch to. If Data 2 is set to anything then the switch will be relative to the current position. Set Data 1 to auto to switch to the page with the most recent and important activity (queries first, then channels with hilight, channels with dialogue, channels with other data)")},
|
N_("The \002Change Page\002 command switches between pages in the notebook. Set Data 1 to the page number, channel name, network/channel, or auto. If Data 2 is set to anything then numeric switches are relative to the current position. Auto switches to the page with the most recent and important activity (queries first, then channels with hilight, channels with dialogue, channels with other data)")},
|
||||||
{key_action_insert, "Insert in Buffer",
|
{key_action_insert, "Insert in Buffer",
|
||||||
N_("The \002Insert in Buffer\002 command will insert the contents of Data 1 into the entry where the key sequence was pressed at the current cursor position. Escapes in Data 1 are interpreted (for example \002\\n\002, \002\\r\002, \002\\t\002, \002\\xNN\002 and \002\\\\\002).")},
|
N_("The \002Insert in Buffer\002 command will insert the contents of Data 1 into the entry where the key sequence was pressed at the current cursor position. Escapes in Data 1 are interpreted (for example \002\\n\002, \002\\r\002, \002\\t\002, \002\\xNN\002 and \002\\\\\002).")},
|
||||||
{key_action_scroll_page, "Scroll Page",
|
{key_action_scroll_page, "Scroll Page",
|
||||||
@@ -287,6 +294,10 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
|
|||||||
N_("This command moves the current tab family to the right")},
|
N_("This command moves the current tab family to the right")},
|
||||||
{key_action_put_history, "Push input line into history",
|
{key_action_put_history, "Push input line into history",
|
||||||
N_("Push input line into history but doesn't send to server")},
|
N_("Push input line into history but doesn't send to server")},
|
||||||
|
{key_action_menu_shortcut, "Menu Shortcut",
|
||||||
|
N_("Runs one of the built-in menu shortcuts. Set Data 1 to: network-list, new-server-tab, new-server-window, close, quit, menu-toggle, user-list-toggle, fullscreen-toggle, away-toggle, reset-marker, move-marker, copy-selection, search-text, search-next, search-previous or contents.")},
|
||||||
|
{key_action_reopen_closed_tab, "Reopen Closed Tab",
|
||||||
|
N_("Reopens the most recently closed channel tab")},
|
||||||
};
|
};
|
||||||
|
|
||||||
#define default_kb_cfg \
|
#define default_kb_cfg \
|
||||||
@@ -329,7 +340,86 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
|
|||||||
"ACCEL=<Alt>Right\nMove front tab right\nD1!\nD2!\n\n"\
|
"ACCEL=<Alt>Right\nMove front tab right\nD1!\nD2!\n\n"\
|
||||||
"ACCEL=<Primary><Shift>Page_Up\nMove tab family left\nD1!\nD2!\n\n"\
|
"ACCEL=<Primary><Shift>Page_Up\nMove tab family left\nD1!\nD2!\n\n"\
|
||||||
"ACCEL=<Primary><Shift>Page_Down\nMove tab family right\nD1!\nD2!\n\n"\
|
"ACCEL=<Primary><Shift>Page_Down\nMove tab family right\nD1!\nD2!\n\n"\
|
||||||
"ACCEL=F9\nRun Command\nD1:/GUI MENU TOGGLE\nD2!\n\n"
|
"ACCEL=<Primary>s\nMenu Shortcut\nD1:network-list\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary>t\nMenu Shortcut\nD1:new-server-tab\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary>n\nMenu Shortcut\nD1:new-server-window\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary>w\nMenu Shortcut\nD1:close\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary>q\nMenu Shortcut\nD1:quit\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary>F9\nMenu Shortcut\nD1:menu-toggle\nD2!\n\n"\
|
||||||
|
"ACCEL=F7\nMenu Shortcut\nD1:user-list-toggle\nD2!\n\n"\
|
||||||
|
"ACCEL=F11\nMenu Shortcut\nD1:fullscreen-toggle\nD2!\n\n"\
|
||||||
|
"ACCEL=<Alt>a\nMenu Shortcut\nD1:away-toggle\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary>m\nMenu Shortcut\nD1:reset-marker\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary><Shift>M\nMenu Shortcut\nD1:move-marker\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary><Shift>C\nMenu Shortcut\nD1:copy-selection\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary>f\nMenu Shortcut\nD1:search-text\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary>g\nMenu Shortcut\nD1:search-next\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary><Shift>G\nMenu Shortcut\nD1:search-previous\nD2!\n\n"\
|
||||||
|
"ACCEL=F1\nMenu Shortcut\nD1:contents\nD2!\n\n"\
|
||||||
|
"ACCEL=<Primary><Shift>T\nReopen Closed Tab\nD1!\nD2!\n\n"
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
key_builtin_data_match (char *line, char *data)
|
||||||
|
{
|
||||||
|
if (line[2] == '!')
|
||||||
|
return data == NULL || data[0] == 0;
|
||||||
|
|
||||||
|
if (line[2] == ':')
|
||||||
|
return !strcmp (&line[3], data ? data : "");
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
key_binding_is_builtin (struct key_binding *kb)
|
||||||
|
{
|
||||||
|
char *buf, *ibuf;
|
||||||
|
char *action;
|
||||||
|
int pnt = 0;
|
||||||
|
int state = 0;
|
||||||
|
gboolean match = FALSE;
|
||||||
|
gboolean d1_match = FALSE;
|
||||||
|
off_t size;
|
||||||
|
|
||||||
|
if (kb->action < 0 || kb->action > KEY_MAX_ACTIONS)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
action = key_actions[kb->action].name;
|
||||||
|
ibuf = g_strdup (default_kb_cfg);
|
||||||
|
size = strlen (default_kb_cfg);
|
||||||
|
|
||||||
|
while (buf_get_line (ibuf, &buf, &pnt, size))
|
||||||
|
{
|
||||||
|
if (strlen (buf) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
state = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
match = !strcmp (buf, action);
|
||||||
|
state = 2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
d1_match = match && key_builtin_data_match (buf, kb->data1);
|
||||||
|
state = 3;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (d1_match && key_builtin_data_match (buf, kb->data2))
|
||||||
|
{
|
||||||
|
g_free (ibuf);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
state = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (ibuf);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
key_init ()
|
key_init ()
|
||||||
@@ -443,28 +533,6 @@ key_handle_key_press (GtkWidget *wid, GdkEventKey *evt, session *sess)
|
|||||||
if (!list)
|
if (!list)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
current_sess = sess;
|
current_sess = sess;
|
||||||
if ((evt->state & GDK_CONTROL_MASK) &&
|
|
||||||
!(evt->state & (GDK_MOD1_MASK | GDK_META_MASK)))
|
|
||||||
{
|
|
||||||
if (!(evt->state & GDK_SHIFT_MASK) &&
|
|
||||||
(evt->keyval == GDK_KEY_w || evt->keyval == GDK_KEY_W))
|
|
||||||
{
|
|
||||||
if (sess->type == SESS_CHANNEL)
|
|
||||||
{
|
|
||||||
fe_close_window (sess);
|
|
||||||
g_signal_stop_emission_by_name (G_OBJECT (wid), "key-press-event");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((evt->state & GDK_SHIFT_MASK) &&
|
|
||||||
(evt->keyval == GDK_KEY_t || evt->keyval == GDK_KEY_T))
|
|
||||||
{
|
|
||||||
mg_reopen_closed_channel_tab ();
|
|
||||||
g_signal_stop_emission_by_name (G_OBJECT (wid), "key-press-event");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plugin_emit_keypress (sess, evt->state, evt->keyval, gdk_keyval_to_unicode (evt->keyval)))
|
if (plugin_emit_keypress (sess, evt->state, evt->keyval, gdk_keyval_to_unicode (evt->keyval)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -508,6 +576,31 @@ key_handle_key_press (GtkWidget *wid, GdkEventKey *evt, session *sess)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
key_get_menu_accel (const char *name, guint *keyval, GdkModifierType *mod)
|
||||||
|
{
|
||||||
|
struct key_binding *kb;
|
||||||
|
GSList *list;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
list = keybind_list;
|
||||||
|
while (list)
|
||||||
|
{
|
||||||
|
kb = (struct key_binding*)list->data;
|
||||||
|
if (kb->action >= 0 && kb->action <= KEY_MAX_ACTIONS && kb->keyval != 0 && !strcmp (key_actions[kb->action].name, "Menu Shortcut") && kb->data1 && !strcmp (kb->data1, name))
|
||||||
|
{
|
||||||
|
*keyval = kb->keyval;
|
||||||
|
*mod = kb->mod;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
list = g_slist_next (list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ***** GUI code here ******************* */
|
/* ***** GUI code here ******************* */
|
||||||
|
|
||||||
@@ -518,6 +611,7 @@ enum
|
|||||||
ACTION_COLUMN,
|
ACTION_COLUMN,
|
||||||
D1_COLUMN,
|
D1_COLUMN,
|
||||||
D2_COLUMN,
|
D2_COLUMN,
|
||||||
|
CUSTOM_COLUMN,
|
||||||
N_COLUMNS
|
N_COLUMNS
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -642,15 +736,31 @@ key_dialog_keypress (GtkWidget *wid, GdkEventKey *evt, gpointer userdata)
|
|||||||
|
|
||||||
if (handled)
|
if (handled)
|
||||||
{
|
{
|
||||||
|
gboolean custom1, custom2;
|
||||||
|
|
||||||
sel = gtk_tree_view_get_selection (view);
|
sel = gtk_tree_view_get_selection (view);
|
||||||
gtk_tree_selection_get_selected (sel, &store, &iter1);
|
if (!gtk_tree_selection_get_selected (sel, &store, &iter1))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
path = gtk_tree_model_get_path (store, &iter1);
|
path = gtk_tree_model_get_path (store, &iter1);
|
||||||
if (delta == 1)
|
if (delta == 1)
|
||||||
gtk_tree_path_next (path);
|
gtk_tree_path_next (path);
|
||||||
else
|
else if (!gtk_tree_path_prev (path))
|
||||||
gtk_tree_path_prev (path);
|
{
|
||||||
gtk_tree_model_get_iter (store, &iter2, path);
|
|
||||||
gtk_tree_path_free (path);
|
gtk_tree_path_free (path);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gtk_tree_model_get_iter (store, &iter2, path))
|
||||||
|
{
|
||||||
|
gtk_tree_path_free (path);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_tree_path_free (path);
|
||||||
|
gtk_tree_model_get (store, &iter1, CUSTOM_COLUMN, &custom1, -1);
|
||||||
|
gtk_tree_model_get (store, &iter2, CUSTOM_COLUMN, &custom2, -1);
|
||||||
|
if (custom1 && custom2)
|
||||||
gtk_list_store_swap (GTK_LIST_STORE (store), &iter1, &iter2);
|
gtk_list_store_swap (GTK_LIST_STORE (store), &iter1, &iter2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -663,14 +773,23 @@ key_dialog_selection_changed (GtkTreeSelection *sel, gpointer userdata)
|
|||||||
GtkTreeModel *model;
|
GtkTreeModel *model;
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
GtkXText *xtext;
|
GtkXText *xtext;
|
||||||
|
GtkWidget *delete_button;
|
||||||
char *actiontext;
|
char *actiontext;
|
||||||
|
gboolean custom;
|
||||||
int action;
|
int action;
|
||||||
|
|
||||||
|
delete_button = g_object_get_data (G_OBJECT (key_dialog), "delete_button");
|
||||||
if (!gtk_tree_selection_get_selected (sel, &model, &iter) || model == NULL)
|
if (!gtk_tree_selection_get_selected (sel, &model, &iter) || model == NULL)
|
||||||
|
{
|
||||||
|
if (delete_button)
|
||||||
|
gtk_widget_set_sensitive (delete_button, FALSE);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
xtext = GTK_XTEXT (g_object_get_data (G_OBJECT (key_dialog), "xtext"));
|
xtext = GTK_XTEXT (g_object_get_data (G_OBJECT (key_dialog), "xtext"));
|
||||||
gtk_tree_model_get (model, &iter, ACTION_COLUMN, &actiontext, -1);
|
gtk_tree_model_get (model, &iter, ACTION_COLUMN, &actiontext, CUSTOM_COLUMN, &custom, -1);
|
||||||
|
if (delete_button)
|
||||||
|
gtk_widget_set_sensitive (delete_button, custom);
|
||||||
|
|
||||||
if (actiontext)
|
if (actiontext)
|
||||||
{
|
{
|
||||||
@@ -745,7 +864,10 @@ key_dialog_save (GtkWidget *wid, gpointer userdata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (key_save_kbs () == 0)
|
if (key_save_kbs () == 0)
|
||||||
|
{
|
||||||
|
menu_update_quit_accel ();
|
||||||
key_dialog_close (wid, NULL);
|
key_dialog_close (wid, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -758,6 +880,7 @@ key_dialog_add (GtkWidget *wid, gpointer userdata)
|
|||||||
GtkTreePath *path;
|
GtkTreePath *path;
|
||||||
|
|
||||||
gtk_list_store_append (store, &iter);
|
gtk_list_store_append (store, &iter);
|
||||||
|
gtk_list_store_set (store, &iter, CUSTOM_COLUMN, TRUE, -1);
|
||||||
|
|
||||||
/* make sure the new row is visible and selected */
|
/* make sure the new row is visible and selected */
|
||||||
path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
|
path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
|
||||||
@@ -774,9 +897,14 @@ key_dialog_delete (GtkWidget *wid, gpointer userdata)
|
|||||||
GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
|
GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
GtkTreePath *path;
|
GtkTreePath *path;
|
||||||
|
gboolean custom;
|
||||||
|
|
||||||
if (gtkutil_treeview_get_selected (view, &iter, -1))
|
if (gtkutil_treeview_get_selected (view, &iter, -1))
|
||||||
{
|
{
|
||||||
|
gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, CUSTOM_COLUMN, &custom, -1);
|
||||||
|
if (!custom)
|
||||||
|
return;
|
||||||
|
|
||||||
/* delete this row, select next one */
|
/* delete this row, select next one */
|
||||||
if (gtk_list_store_remove (store, &iter))
|
if (gtk_list_store_remove (store, &iter))
|
||||||
{
|
{
|
||||||
@@ -803,13 +931,13 @@ key_dialog_treeview_new (GtkWidget *box)
|
|||||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
|
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
|
||||||
|
|
||||||
store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
|
store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
|
||||||
G_TYPE_STRING, G_TYPE_STRING);
|
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
|
||||||
g_return_val_if_fail (store != NULL, NULL);
|
g_return_val_if_fail (store != NULL, NULL);
|
||||||
|
|
||||||
view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
|
view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
|
||||||
gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE);
|
gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE);
|
||||||
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view), FALSE);
|
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view), FALSE);
|
||||||
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), TRUE);
|
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), FALSE);
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (view), "key-press-event",
|
g_signal_connect (G_OBJECT (view), "key-press-event",
|
||||||
G_CALLBACK (key_dialog_keypress), NULL);
|
G_CALLBACK (key_dialog_keypress), NULL);
|
||||||
@@ -880,6 +1008,7 @@ key_dialog_treeview_new (GtkWidget *box)
|
|||||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), ACTION_COLUMN,
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), ACTION_COLUMN,
|
||||||
"Action", render,
|
"Action", render,
|
||||||
"text", ACTION_COLUMN,
|
"text", ACTION_COLUMN,
|
||||||
|
"editable", CUSTOM_COLUMN,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
render = gtk_cell_renderer_text_new ();
|
render = gtk_cell_renderer_text_new ();
|
||||||
@@ -890,6 +1019,7 @@ key_dialog_treeview_new (GtkWidget *box)
|
|||||||
GTK_TREE_VIEW (view), D1_COLUMN,
|
GTK_TREE_VIEW (view), D1_COLUMN,
|
||||||
"Data1", render,
|
"Data1", render,
|
||||||
"text", D1_COLUMN,
|
"text", D1_COLUMN,
|
||||||
|
"editable", CUSTOM_COLUMN,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
render = gtk_cell_renderer_text_new ();
|
render = gtk_cell_renderer_text_new ();
|
||||||
@@ -900,6 +1030,7 @@ key_dialog_treeview_new (GtkWidget *box)
|
|||||||
GTK_TREE_VIEW (view), D2_COLUMN,
|
GTK_TREE_VIEW (view), D2_COLUMN,
|
||||||
"Data2", render,
|
"Data2", render,
|
||||||
"text", D2_COLUMN,
|
"text", D2_COLUMN,
|
||||||
|
"editable", CUSTOM_COLUMN,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), KEY_COLUMN);
|
col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), KEY_COLUMN);
|
||||||
@@ -945,7 +1076,8 @@ key_dialog_load (GtkListStore *store)
|
|||||||
ACCEL_COLUMN, accel_text,
|
ACCEL_COLUMN, accel_text,
|
||||||
ACTION_COLUMN, key_actions[kb->action].name,
|
ACTION_COLUMN, key_actions[kb->action].name,
|
||||||
D1_COLUMN, kb->data1,
|
D1_COLUMN, kb->data1,
|
||||||
D2_COLUMN, kb->data2, -1);
|
D2_COLUMN, kb->data2,
|
||||||
|
CUSTOM_COLUMN, !key_binding_is_builtin (kb), -1);
|
||||||
|
|
||||||
g_free (accel_text);
|
g_free (accel_text);
|
||||||
g_free (label_text);
|
g_free (label_text);
|
||||||
@@ -958,7 +1090,7 @@ void
|
|||||||
key_dialog_show ()
|
key_dialog_show ()
|
||||||
{
|
{
|
||||||
GtkWidget *vbox, *box;
|
GtkWidget *vbox, *box;
|
||||||
GtkWidget *view, *xtext;
|
GtkWidget *view, *xtext, *delete_button;
|
||||||
GtkListStore *store;
|
GtkListStore *store;
|
||||||
XTextColor xtext_palette[XTEXT_COLS];
|
XTextColor xtext_palette[XTEXT_COLS];
|
||||||
char buf[128];
|
char buf[128];
|
||||||
@@ -992,8 +1124,10 @@ key_dialog_show ()
|
|||||||
|
|
||||||
gtkutil_button (box, ICON_FKEYS_NEW, NULL, key_dialog_add,
|
gtkutil_button (box, ICON_FKEYS_NEW, NULL, key_dialog_add,
|
||||||
NULL, _("Add"));
|
NULL, _("Add"));
|
||||||
gtkutil_button (box, ICON_FKEYS_DELETE, NULL, key_dialog_delete,
|
delete_button = gtkutil_button (box, ICON_FKEYS_DELETE, NULL, key_dialog_delete,
|
||||||
NULL, _("Delete"));
|
NULL, _("Delete"));
|
||||||
|
g_object_set_data (G_OBJECT (key_dialog), "delete_button", delete_button);
|
||||||
|
gtk_widget_set_sensitive (delete_button, FALSE);
|
||||||
gtkutil_button (box, ICON_FKEYS_CANCEL, NULL, key_dialog_close,
|
gtkutil_button (box, ICON_FKEYS_CANCEL, NULL, key_dialog_close,
|
||||||
NULL, _("Cancel"));
|
NULL, _("Cancel"));
|
||||||
gtkutil_button (box, ICON_FKEYS_SAVE, NULL, key_dialog_save,
|
gtkutil_button (box, ICON_FKEYS_SAVE, NULL, key_dialog_save,
|
||||||
@@ -1289,6 +1423,24 @@ key_action_handle_command (GtkWidget * wid, GdkEventKey * evt, char *d1,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
key_action_menu_shortcut (GtkWidget * wid, GdkEventKey * evt, char *d1,
|
||||||
|
char *d2, struct session *sess)
|
||||||
|
{
|
||||||
|
if (menu_key_action (d1, evt->keyval, evt->state))
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
key_action_reopen_closed_tab (GtkWidget * wid, GdkEventKey * evt, char *d1,
|
||||||
|
char *d2, struct session *sess)
|
||||||
|
{
|
||||||
|
mg_reopen_closed_channel_tab ();
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the given session is inside the main window. This predicate
|
* Check if the given session is inside the main window. This predicate
|
||||||
* is passed to lastact_getfirst() as a way to filter out detached sessions.
|
* is passed to lastact_getfirst() as a way to filter out detached sessions.
|
||||||
@@ -1307,6 +1459,9 @@ key_action_page_switch (GtkWidget * wid, GdkEventKey * evt, char *d1,
|
|||||||
char *d2, struct session *sess)
|
char *d2, struct session *sess)
|
||||||
{
|
{
|
||||||
session *newsess;
|
session *newsess;
|
||||||
|
char *network;
|
||||||
|
char *channel;
|
||||||
|
char *slash;
|
||||||
int len, i, num;
|
int len, i, num;
|
||||||
|
|
||||||
if (!d1)
|
if (!d1)
|
||||||
@@ -1318,21 +1473,13 @@ key_action_page_switch (GtkWidget * wid, GdkEventKey * evt, char *d1,
|
|||||||
|
|
||||||
if (g_ascii_strcasecmp(d1, "auto") == 0)
|
if (g_ascii_strcasecmp(d1, "auto") == 0)
|
||||||
{
|
{
|
||||||
/* Auto switch makes no sense in detached sessions */
|
|
||||||
if (!sess->gui->is_tab)
|
if (!sess->gui->is_tab)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Obtain a session with recent activity */
|
|
||||||
newsess = lastact_getfirst(session_check_is_tab);
|
newsess = lastact_getfirst(session_check_is_tab);
|
||||||
|
|
||||||
if (newsess)
|
if (newsess)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Only sessions in the current window should be considered (i.e.
|
|
||||||
* we don't want to move the focus on a different window). This
|
|
||||||
* call could, in theory, do this, but we checked before that
|
|
||||||
* newsess->gui->is_tab and sess->gui->is_tab.
|
|
||||||
*/
|
|
||||||
mg_bring_tofront_sess(newsess);
|
mg_bring_tofront_sess(newsess);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1346,7 +1493,26 @@ key_action_page_switch (GtkWidget * wid, GdkEventKey * evt, char *d1,
|
|||||||
{
|
{
|
||||||
if (i == 0 && (d1[i] == '+' || d1[i] == '-'))
|
if (i == 0 && (d1[i] == '+' || d1[i] == '-'))
|
||||||
continue;
|
continue;
|
||||||
else
|
|
||||||
|
network = NULL;
|
||||||
|
channel = d1;
|
||||||
|
slash = strchr (d1, '/');
|
||||||
|
|
||||||
|
if (slash && slash[1])
|
||||||
|
{
|
||||||
|
network = g_strndup (d1, slash - d1);
|
||||||
|
channel = slash + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
newsess = plugin_find_context (network, channel, sess->server);
|
||||||
|
g_free (network);
|
||||||
|
|
||||||
|
if (newsess && newsess->gui)
|
||||||
|
{
|
||||||
|
mg_bring_tofront_sess(newsess);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,5 +35,6 @@ int key_handle_key_press (GtkWidget * wid, GdkEventKey * evt, session *sess);
|
|||||||
int key_action_insert (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2,
|
int key_action_insert (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2,
|
||||||
session *sess);
|
session *sess);
|
||||||
void key_check_replace_on_change (GtkEditable *editable, gpointer data);
|
void key_check_replace_on_change (GtkEditable *editable, gpointer data);
|
||||||
|
gboolean key_get_menu_accel (const char *name, guint *keyval, GdkModifierType *mod);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -272,13 +272,6 @@ gtkutil_apply_palette (GtkWidget *widget, const GdkRGBA *bg, const GdkRGBA *fg,
|
|||||||
theme_manager_apply_palette_widget (widget, bg, fg, font_desc);
|
theme_manager_apply_palette_widget (widget, bg, fg, font_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gtkutil_file_req_destroy (GtkWidget * wid, struct file_req *freq)
|
|
||||||
{
|
|
||||||
freq->callback (freq->userdata, NULL);
|
|
||||||
g_free (freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtkutil_check_file (char *filename, struct file_req *freq)
|
gtkutil_check_file (char *filename, struct file_req *freq)
|
||||||
{
|
{
|
||||||
@@ -390,26 +383,6 @@ gtkutil_file_req_done_chooser (GtkFileChooser *fs, struct file_req *freq)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gtkutil_file_req_done (GtkWidget * wid, struct file_req *freq)
|
|
||||||
{
|
|
||||||
gtkutil_file_req_done_chooser (GTK_FILE_CHOOSER (freq->dialog), freq);
|
|
||||||
gtk_widget_destroy (freq->dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gtkutil_file_req_response (GtkWidget *dialog, gint res, struct file_req *freq)
|
|
||||||
{
|
|
||||||
if (res == GTK_RESPONSE_ACCEPT)
|
|
||||||
{
|
|
||||||
gtkutil_file_req_done (dialog, freq);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_widget_destroy (dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gtkutil_native_dialog_unref_idle (gpointer native)
|
gtkutil_native_dialog_unref_idle (gpointer native)
|
||||||
{
|
{
|
||||||
@@ -423,27 +396,16 @@ gtkutil_native_file_req_response (GtkNativeDialog *dialog, gint res, struct file
|
|||||||
if (res == GTK_RESPONSE_ACCEPT)
|
if (res == GTK_RESPONSE_ACCEPT)
|
||||||
gtkutil_file_req_done_chooser (GTK_FILE_CHOOSER (dialog), freq);
|
gtkutil_file_req_done_chooser (GTK_FILE_CHOOSER (dialog), freq);
|
||||||
|
|
||||||
/* Match gtk dialog flow by always sending NULL to indicate completion. */
|
|
||||||
freq->callback (freq->userdata, NULL);
|
freq->callback (freq->userdata, NULL);
|
||||||
g_free (freq);
|
g_free (freq);
|
||||||
|
|
||||||
/*
|
|
||||||
* Defer unref until idle to avoid disposing the native chooser while
|
|
||||||
* still in the button-release signal stack on Windows.
|
|
||||||
*/
|
|
||||||
g_idle_add (gtkutil_native_dialog_unref_idle, dialog);
|
g_idle_add (gtkutil_native_dialog_unref_idle, dialog);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
void
|
||||||
gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *userdata, char *filter, char *extensions,
|
gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *userdata, char *filter, char *extensions,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
struct file_req *freq;
|
struct file_req *freq;
|
||||||
GtkWidget *dialog;
|
|
||||||
GtkFileFilter *filefilter;
|
|
||||||
char *token;
|
|
||||||
char *tokenbuffer;
|
|
||||||
const char *xdir;
|
const char *xdir;
|
||||||
GtkWindow *effective_parent = parent;
|
GtkWindow *effective_parent = parent;
|
||||||
|
|
||||||
@@ -453,7 +415,6 @@ gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *us
|
|||||||
|
|
||||||
xdir = get_xdir ();
|
xdir = get_xdir ();
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
{
|
{
|
||||||
GtkFileChooserNative *native = gtk_file_chooser_native_new (
|
GtkFileChooserNative *native = gtk_file_chooser_native_new (
|
||||||
title,
|
title,
|
||||||
@@ -522,110 +483,14 @@ gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *us
|
|||||||
|
|
||||||
g_signal_connect (native, "response",
|
g_signal_connect (native, "response",
|
||||||
G_CALLBACK (gtkutil_native_file_req_response), freq);
|
G_CALLBACK (gtkutil_native_file_req_response), freq);
|
||||||
|
|
||||||
|
if (flags & FRF_MODAL)
|
||||||
|
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (native), TRUE);
|
||||||
|
|
||||||
gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
|
gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (flags & FRF_WRITE)
|
|
||||||
{
|
|
||||||
dialog = gtk_file_chooser_dialog_new (title, NULL,
|
|
||||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
|
||||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
|
||||||
_("_Save"), GTK_RESPONSE_ACCEPT,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (!(flags & FRF_NOASKOVERWRITE))
|
|
||||||
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
dialog = gtk_file_chooser_dialog_new (title, NULL,
|
|
||||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
||||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
|
||||||
_("_Open"), GTK_RESPONSE_ACCEPT,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
theme_manager_attach_window (dialog);
|
|
||||||
|
|
||||||
if (filter && filter[0] && (flags & FRF_FILTERISINITIAL))
|
|
||||||
{
|
|
||||||
if (flags & FRF_WRITE)
|
|
||||||
{
|
|
||||||
char temp[1024];
|
|
||||||
path_part (filter, temp, sizeof (temp));
|
|
||||||
if (temp[0] && g_file_test (temp, G_FILE_TEST_IS_DIR))
|
|
||||||
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), temp);
|
|
||||||
else if (xdir && xdir[0] && g_file_test (xdir, G_FILE_TEST_IS_DIR))
|
|
||||||
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), xdir);
|
|
||||||
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), file_part (filter));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (g_file_test (filter, G_FILE_TEST_IS_DIR))
|
|
||||||
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), filter);
|
|
||||||
else if (xdir && xdir[0] && g_file_test (xdir, G_FILE_TEST_IS_DIR))
|
|
||||||
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), xdir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!(flags & FRF_RECENTLYUSED))
|
|
||||||
{
|
|
||||||
if (xdir && xdir[0] && g_file_test (xdir, G_FILE_TEST_IS_DIR))
|
|
||||||
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), xdir);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & FRF_MULTIPLE)
|
|
||||||
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), TRUE);
|
|
||||||
if (flags & FRF_CHOOSEFOLDER)
|
|
||||||
gtk_file_chooser_set_action (GTK_FILE_CHOOSER (dialog), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
|
|
||||||
|
|
||||||
if ((flags & FRF_EXTENSIONS || flags & FRF_MIMETYPES) && extensions != NULL)
|
|
||||||
{
|
|
||||||
filefilter = gtk_file_filter_new ();
|
|
||||||
tokenbuffer = g_strdup (extensions);
|
|
||||||
token = strtok (tokenbuffer, ";");
|
|
||||||
|
|
||||||
while (token != NULL)
|
|
||||||
{
|
|
||||||
if (flags & FRF_EXTENSIONS)
|
|
||||||
gtk_file_filter_add_pattern (filefilter, token);
|
|
||||||
else
|
|
||||||
gtk_file_filter_add_mime_type (filefilter, token);
|
|
||||||
token = strtok (NULL, ";");
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (tokenbuffer);
|
|
||||||
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filefilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xdir && xdir[0] && g_file_test (xdir, G_FILE_TEST_IS_DIR))
|
|
||||||
{
|
|
||||||
GError *shortcut_error = NULL;
|
|
||||||
|
|
||||||
gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog), xdir, &shortcut_error);
|
|
||||||
if (shortcut_error)
|
|
||||||
g_error_free (shortcut_error);
|
|
||||||
}
|
|
||||||
freq = g_new (struct file_req, 1);
|
|
||||||
freq->dialog = dialog;
|
|
||||||
freq->flags = flags;
|
|
||||||
freq->callback = callback;
|
|
||||||
freq->userdata = userdata;
|
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (dialog), "response",
|
|
||||||
G_CALLBACK (gtkutil_file_req_response), freq);
|
|
||||||
g_signal_connect (G_OBJECT (dialog), "destroy",
|
|
||||||
G_CALLBACK (gtkutil_file_req_destroy), (gpointer) freq);
|
|
||||||
|
|
||||||
if (effective_parent)
|
|
||||||
gtk_window_set_transient_for (GTK_WINDOW (dialog), effective_parent);
|
|
||||||
|
|
||||||
if (flags & FRF_MODAL)
|
|
||||||
{
|
|
||||||
g_assert (effective_parent);
|
|
||||||
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_widget_show (dialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -972,7 +837,7 @@ gtkutil_copy_to_clipboard (GtkWidget *widget, GdkAtom selection,
|
|||||||
win = gtk_widget_get_toplevel (GTK_WIDGET (widget));
|
win = gtk_widget_get_toplevel (GTK_WIDGET (widget));
|
||||||
if (gtk_widget_is_toplevel (win))
|
if (gtk_widget_is_toplevel (win))
|
||||||
{
|
{
|
||||||
int len = strlen (str);
|
gint len = (gint) strlen (str);
|
||||||
|
|
||||||
if (selection)
|
if (selection)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -872,6 +872,10 @@ fe_set_title (session *sess)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
mg_topicbar_update_height (GtkWidget *topic);
|
mg_topicbar_update_height (GtkWidget *topic);
|
||||||
|
static void
|
||||||
|
mg_topicbar_queue_relayout (GtkWidget *topic);
|
||||||
|
static void
|
||||||
|
mg_queue_window_relayout (GtkWidget *window);
|
||||||
|
|
||||||
static session *
|
static session *
|
||||||
mg_session_from_window (GtkWidget *wid)
|
mg_session_from_window (GtkWidget *wid)
|
||||||
@@ -891,6 +895,57 @@ mg_session_from_window (GtkWidget *wid)
|
|||||||
return current_sess;
|
return current_sess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
mg_window_relayout_idle_cb (gpointer userdata)
|
||||||
|
{
|
||||||
|
GtkWidget *window = GTK_WIDGET (userdata);
|
||||||
|
session *sess;
|
||||||
|
|
||||||
|
g_object_set_data (G_OBJECT (window), "mg-window-relayout-source", NULL);
|
||||||
|
|
||||||
|
sess = mg_session_from_window (window);
|
||||||
|
if (sess && sess->gui)
|
||||||
|
{
|
||||||
|
if (GTK_IS_WIDGET (sess->gui->topic_entry))
|
||||||
|
mg_topicbar_queue_relayout (sess->gui->topic_entry);
|
||||||
|
|
||||||
|
if (GTK_IS_XTEXT (sess->gui->xtext))
|
||||||
|
{
|
||||||
|
gtk_xtext_refresh (GTK_XTEXT (sess->gui->xtext));
|
||||||
|
gtk_widget_queue_resize (sess->gui->xtext);
|
||||||
|
gtk_widget_queue_draw (sess->gui->xtext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GTK_IS_WIDGET (sess->gui->window))
|
||||||
|
{
|
||||||
|
gtk_widget_queue_resize (sess->gui->window);
|
||||||
|
gtk_widget_queue_draw (sess->gui->window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (window);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_queue_window_relayout (GtkWidget *window)
|
||||||
|
{
|
||||||
|
guint source_id;
|
||||||
|
|
||||||
|
if (!window || !GTK_IS_WIDGET (window))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (g_object_get_data (G_OBJECT (window), "mg-window-relayout-source") != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
|
||||||
|
mg_window_relayout_idle_cb,
|
||||||
|
g_object_ref (window),
|
||||||
|
NULL);
|
||||||
|
g_object_set_data (G_OBJECT (window), "mg-window-relayout-source",
|
||||||
|
GUINT_TO_POINTER (source_id));
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
mg_windowstate_cb (GtkWindow *wid, GdkEventWindowState *event, gpointer userdata)
|
mg_windowstate_cb (GtkWindow *wid, GdkEventWindowState *event, gpointer userdata)
|
||||||
{
|
{
|
||||||
@@ -902,7 +957,12 @@ mg_windowstate_cb (GtkWindow *wid, GdkEventWindowState *event, gpointer userdata
|
|||||||
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) &&
|
||||||
prefs.hex_gui_tray_minimize && prefs.hex_gui_tray &&
|
prefs.hex_gui_tray_minimize && prefs.hex_gui_tray &&
|
||||||
gtkutil_tray_icon_supported (wid))
|
gtkutil_tray_icon_supported (wid)
|
||||||
|
#ifndef WIN32
|
||||||
|
)
|
||||||
|
#else
|
||||||
|
&& !gtk_window_is_active (wid))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
tray_toggle_visibility (TRUE);
|
tray_toggle_visibility (TRUE);
|
||||||
}
|
}
|
||||||
@@ -934,22 +994,17 @@ mg_windowstate_cb (GtkWindow *wid, GdkEventWindowState *event, gpointer userdata
|
|||||||
}
|
}
|
||||||
|
|
||||||
sess = mg_session_from_window (GTK_WIDGET (wid));
|
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))
|
if (sess && sess->gui && GTK_IS_WIDGET (sess->gui->window))
|
||||||
gtk_widget_queue_draw (sess->gui->window);
|
mg_queue_window_relayout (sess->gui->window);
|
||||||
|
else
|
||||||
|
mg_queue_window_relayout (GTK_WIDGET (wid));
|
||||||
|
|
||||||
|
if (current_sess && current_sess->gui)
|
||||||
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
|
||||||
|
if (event->changed_mask &
|
||||||
|
(GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN))
|
||||||
mg_win32_allow_autohide_taskbar (wid, event);
|
mg_win32_allow_autohide_taskbar (wid, event);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1044,21 +1099,10 @@ mg_configure_cb (GtkWidget *wid, GdkEventConfigure *event, session *sess)
|
|||||||
}
|
}
|
||||||
|
|
||||||
target_sess = mg_session_from_window (wid);
|
target_sess = mg_session_from_window (wid);
|
||||||
if (target_sess && target_sess->gui)
|
if (target_sess && target_sess->gui && GTK_IS_WIDGET (target_sess->gui->window))
|
||||||
{
|
mg_queue_window_relayout (target_sess->gui->window);
|
||||||
if (GTK_IS_WIDGET (target_sess->gui->topic_entry))
|
else
|
||||||
{
|
mg_queue_window_relayout (wid);
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -2412,9 +2456,9 @@ mg_userlist_button (GtkWidget * box, char *label, char *cmd,
|
|||||||
g_signal_connect (G_OBJECT (wid), "clicked",
|
g_signal_connect (G_OBJECT (wid), "clicked",
|
||||||
G_CALLBACK (userlist_button_cb), cmd);
|
G_CALLBACK (userlist_button_cb), cmd);
|
||||||
gtk_widget_set_hexpand (wid, TRUE);
|
gtk_widget_set_hexpand (wid, TRUE);
|
||||||
gtk_widget_set_vexpand (wid, TRUE);
|
gtk_widget_set_vexpand (wid, FALSE);
|
||||||
gtk_widget_set_halign (wid, GTK_ALIGN_FILL);
|
gtk_widget_set_halign (wid, GTK_ALIGN_FILL);
|
||||||
gtk_widget_set_valign (wid, GTK_ALIGN_FILL);
|
gtk_widget_set_valign (wid, GTK_ALIGN_CENTER);
|
||||||
gtk_grid_attach (GTK_GRID (box), wid, a, c, b - a, d - c);
|
gtk_grid_attach (GTK_GRID (box), wid, a, c, b - a, d - c);
|
||||||
show_and_unfocus (wid);
|
show_and_unfocus (wid);
|
||||||
}
|
}
|
||||||
@@ -2699,7 +2743,6 @@ mg_changui_destroy (session *sess)
|
|||||||
/* it fixes: Gdk-CRITICAL **: gdk_colormap_get_screen: */
|
/* it fixes: Gdk-CRITICAL **: gdk_colormap_get_screen: */
|
||||||
/* assertion `GDK_IS_COLORMAP (cmap)' failed */
|
/* assertion `GDK_IS_COLORMAP (cmap)' failed */
|
||||||
ret = sess->gui->window;
|
ret = sess->gui->window;
|
||||||
g_free (sess->gui);
|
|
||||||
sess->gui = NULL;
|
sess->gui = NULL;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -2721,13 +2764,17 @@ mg_link_irctab (session *sess, int focus)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_gui *old_gui;
|
||||||
|
|
||||||
mg_unpopulate (sess);
|
mg_unpopulate (sess);
|
||||||
|
old_gui = sess->gui;
|
||||||
win = mg_changui_destroy (sess);
|
win = mg_changui_destroy (sess);
|
||||||
mg_changui_new (sess, sess->res, 1, focus);
|
mg_changui_new (sess, sess->res, 1, focus);
|
||||||
/* the buffer is now attached to a different widget */
|
/* the buffer is now attached to a different widget */
|
||||||
((xtext_buffer *)sess->res->buffer)->xtext = (GtkXText *)sess->gui->xtext;
|
((xtext_buffer *)sess->res->buffer)->xtext = (GtkXText *)sess->gui->xtext;
|
||||||
if (win)
|
if (win)
|
||||||
gtk_widget_destroy (win);
|
gtk_widget_destroy (win);
|
||||||
|
g_free (old_gui);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -3102,32 +3149,50 @@ mg_create_dialogbuttons (GtkWidget *box)
|
|||||||
static void
|
static void
|
||||||
mg_topicbar_update_height (GtkWidget *topic)
|
mg_topicbar_update_height (GtkWidget *topic)
|
||||||
{
|
{
|
||||||
GtkWidget *scroller;
|
GtkWidget *parent;
|
||||||
|
GtkWidget *grandparent;
|
||||||
GtkTextBuffer *buffer;
|
GtkTextBuffer *buffer;
|
||||||
GtkTextIter start;
|
GtkTextIter start;
|
||||||
GtkTextIter end;
|
GtkTextIter end;
|
||||||
|
GtkTextView *view;
|
||||||
PangoLayout *layout;
|
PangoLayout *layout;
|
||||||
char *text;
|
char *text;
|
||||||
int width;
|
int width;
|
||||||
int line_height;
|
int line_height;
|
||||||
int line_count;
|
int line_count;
|
||||||
int target_height;
|
int target_height;
|
||||||
|
int margin_left;
|
||||||
|
int margin_right;
|
||||||
|
int margin_top;
|
||||||
|
int margin_bottom;
|
||||||
|
int old_height;
|
||||||
PangoContext *context;
|
PangoContext *context;
|
||||||
PangoFontMetrics *metrics;
|
PangoFontMetrics *metrics;
|
||||||
|
|
||||||
if (!topic || !GTK_IS_TEXT_VIEW (topic))
|
if (!topic || !GTK_IS_TEXT_VIEW (topic))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
scroller = gtk_widget_get_parent (topic);
|
view = GTK_TEXT_VIEW (topic);
|
||||||
|
parent = gtk_widget_get_parent (topic);
|
||||||
|
grandparent = parent ? gtk_widget_get_parent (parent) : NULL;
|
||||||
|
|
||||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (topic));
|
margin_left = gtk_text_view_get_left_margin (view);
|
||||||
|
margin_right = gtk_text_view_get_right_margin (view);
|
||||||
|
margin_top = gtk_text_view_get_top_margin (view);
|
||||||
|
margin_bottom = gtk_text_view_get_bottom_margin (view);
|
||||||
|
|
||||||
|
buffer = gtk_text_view_get_buffer (view);
|
||||||
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
||||||
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
|
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
|
||||||
layout = gtk_widget_create_pango_layout (topic, text && text[0] ? text : " ");
|
layout = gtk_widget_create_pango_layout (topic, text && text[0] ? text : " ");
|
||||||
g_free (text);
|
g_free (text);
|
||||||
|
|
||||||
width = gtk_widget_get_allocated_width (topic) - 8;
|
width = gtk_widget_get_allocated_width (topic);
|
||||||
if (width > 0)
|
if (width <= 1 && parent)
|
||||||
|
width = gtk_widget_get_allocated_width (parent);
|
||||||
|
width -= margin_left + margin_right;
|
||||||
|
if (width < 1)
|
||||||
|
width = 1;
|
||||||
pango_layout_set_width (layout, width * PANGO_SCALE);
|
pango_layout_set_width (layout, width * PANGO_SCALE);
|
||||||
pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
|
pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
|
||||||
|
|
||||||
@@ -3140,44 +3205,95 @@ mg_topicbar_update_height (GtkWidget *topic)
|
|||||||
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);
|
line_count = pango_layout_get_line_count (layout);
|
||||||
if (line_count <= 0)
|
if (line_count <= 0)
|
||||||
line_count = 1;
|
line_count = 1;
|
||||||
target_height = line_height * line_count;
|
|
||||||
if (target_height < line_height)
|
|
||||||
target_height = line_height;
|
|
||||||
|
|
||||||
|
target_height = (line_height * line_count) + margin_top + margin_bottom;
|
||||||
|
if (target_height < line_height + margin_top + margin_bottom)
|
||||||
|
target_height = line_height + margin_top + margin_bottom;
|
||||||
|
|
||||||
|
old_height = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (topic),
|
||||||
|
"mg-topicbar-target-height"));
|
||||||
|
if (old_height != target_height)
|
||||||
|
{
|
||||||
|
g_object_set_data (G_OBJECT (topic), "mg-topicbar-target-height",
|
||||||
|
GINT_TO_POINTER (target_height));
|
||||||
gtk_widget_set_size_request (topic, -1, target_height);
|
gtk_widget_set_size_request (topic, -1, target_height);
|
||||||
if (scroller && GTK_IS_SCROLLED_WINDOW (scroller))
|
|
||||||
|
if (parent && GTK_IS_SCROLLED_WINDOW (parent))
|
||||||
{
|
{
|
||||||
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (scroller), -1);
|
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (parent), -1);
|
||||||
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (scroller), -1);
|
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (parent), -1);
|
||||||
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (scroller), target_height);
|
gtk_scrolled_window_set_max_content_height (GTK_SCROLLED_WINDOW (parent), target_height);
|
||||||
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (scroller), target_height);
|
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (parent), target_height);
|
||||||
gtk_widget_set_size_request (scroller, -1, target_height);
|
gtk_widget_set_size_request (parent, -1, target_height);
|
||||||
gtk_widget_queue_resize (scroller);
|
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
|
||||||
gtk_widget_queue_resize (topic);
|
gtk_widget_queue_resize (topic);
|
||||||
}
|
if (parent)
|
||||||
|
gtk_widget_queue_resize (parent);
|
||||||
|
if (grandparent)
|
||||||
|
gtk_widget_queue_resize (grandparent);
|
||||||
gtk_widget_queue_draw (topic);
|
gtk_widget_queue_draw (topic);
|
||||||
g_object_unref (layout);
|
g_object_unref (layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
mg_topicbar_relayout_idle_cb (gpointer userdata)
|
||||||
|
{
|
||||||
|
GtkWidget *topic = GTK_WIDGET (userdata);
|
||||||
|
|
||||||
|
g_object_set_data (G_OBJECT (topic), "mg-topicbar-relayout-source", NULL);
|
||||||
|
mg_topicbar_update_height (topic);
|
||||||
|
g_object_unref (topic);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_topicbar_queue_relayout (GtkWidget *topic)
|
||||||
|
{
|
||||||
|
guint source_id;
|
||||||
|
|
||||||
|
if (!topic || !GTK_IS_TEXT_VIEW (topic))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (g_object_get_data (G_OBJECT (topic), "mg-topicbar-relayout-source") != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
source_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
|
||||||
|
mg_topicbar_relayout_idle_cb,
|
||||||
|
g_object_ref (topic),
|
||||||
|
NULL);
|
||||||
|
g_object_set_data (G_OBJECT (topic), "mg-topicbar-relayout-source",
|
||||||
|
GUINT_TO_POINTER (source_id));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mg_topicbar_buffer_changed_cb (GtkTextBuffer *buffer, gpointer userdata)
|
mg_topicbar_buffer_changed_cb (GtkTextBuffer *buffer, gpointer userdata)
|
||||||
{
|
{
|
||||||
(void) buffer;
|
(void) buffer;
|
||||||
mg_topicbar_update_height (GTK_WIDGET (userdata));
|
mg_topicbar_queue_relayout (GTK_WIDGET (userdata));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mg_topicbar_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation, gpointer userdata)
|
mg_topicbar_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation, gpointer userdata)
|
||||||
{
|
{
|
||||||
(void) allocation;
|
int old_width;
|
||||||
|
|
||||||
(void) userdata;
|
(void) userdata;
|
||||||
mg_topicbar_update_height (widget);
|
|
||||||
|
old_width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
|
||||||
|
"mg-topicbar-allocated-width"));
|
||||||
|
if (allocation->width == old_width)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_object_set_data (G_OBJECT (widget), "mg-topicbar-allocated-width",
|
||||||
|
GINT_TO_POINTER (allocation->width));
|
||||||
|
mg_topicbar_queue_relayout (widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -3413,8 +3529,13 @@ mg_create_textarea (session *sess, GtkWidget *box)
|
|||||||
inbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 2);
|
inbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 2);
|
||||||
gtk_box_pack_start (GTK_BOX (vbox), inbox, TRUE, TRUE, 0);
|
gtk_box_pack_start (GTK_BOX (vbox), inbox, TRUE, TRUE, 0);
|
||||||
|
|
||||||
frame = gtk_frame_new (NULL);
|
frame = gtk_scrolled_window_new (NULL, NULL);
|
||||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
gtk_widget_set_hexpand (frame, TRUE);
|
||||||
|
gtk_widget_set_vexpand (frame, TRUE);
|
||||||
|
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (frame),
|
||||||
|
GTK_SHADOW_IN);
|
||||||
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (frame),
|
||||||
|
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||||
gtk_box_pack_start (GTK_BOX (inbox), frame, TRUE, TRUE, 0);
|
gtk_box_pack_start (GTK_BOX (inbox), frame, TRUE, TRUE, 0);
|
||||||
|
|
||||||
theme_get_xtext_colors_for_widget (frame, xtext_palette, XTEXT_COLS);
|
theme_get_xtext_colors_for_widget (frame, xtext_palette, XTEXT_COLS);
|
||||||
@@ -3431,9 +3552,7 @@ mg_create_textarea (session *sess, GtkWidget *box)
|
|||||||
g_signal_connect (G_OBJECT (xtext), "word_click",
|
g_signal_connect (G_OBJECT (xtext), "word_click",
|
||||||
G_CALLBACK (mg_word_clicked), NULL);
|
G_CALLBACK (mg_word_clicked), NULL);
|
||||||
|
|
||||||
gui->vscrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL,
|
gui->vscrollbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (frame));
|
||||||
GTK_XTEXT (xtext)->adj);
|
|
||||||
gtk_box_pack_start (GTK_BOX (inbox), gui->vscrollbar, FALSE, TRUE, 0);
|
|
||||||
|
|
||||||
gtk_drag_dest_set (gui->vscrollbar, 5, dnd_dest_targets, 2,
|
gtk_drag_dest_set (gui->vscrollbar, 5, dnd_dest_targets, 2,
|
||||||
GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
|
GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
|
||||||
@@ -3459,7 +3578,7 @@ mg_create_infoframe (GtkWidget *box)
|
|||||||
|
|
||||||
frame = gtk_frame_new (0);
|
frame = gtk_frame_new (0);
|
||||||
gtk_frame_set_shadow_type ((GtkFrame*)frame, GTK_SHADOW_OUT);
|
gtk_frame_set_shadow_type ((GtkFrame*)frame, GTK_SHADOW_OUT);
|
||||||
gtk_box_pack_start (GTK_BOX (box), frame, FALSE, TRUE, 0);
|
gtk_box_pack_start (GTK_BOX (box), frame, TRUE, TRUE, 0);
|
||||||
|
|
||||||
hbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
|
hbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
|
||||||
gtk_container_add (GTK_CONTAINER (frame), hbox);
|
gtk_container_add (GTK_CONTAINER (frame), hbox);
|
||||||
@@ -3476,11 +3595,11 @@ mg_create_meters (session_gui *gui, GtkWidget *parent_box)
|
|||||||
GtkWidget *infbox, *wid, *box;
|
GtkWidget *infbox, *wid, *box;
|
||||||
|
|
||||||
gui->meter_box = infbox = box = mg_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 1);
|
gui->meter_box = infbox = box = mg_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 1);
|
||||||
gtk_box_pack_start (GTK_BOX (parent_box), box, 0, 0, 0);
|
gtk_box_pack_end (GTK_BOX (parent_box), box, 0, 0, 0);
|
||||||
|
|
||||||
if ((prefs.hex_gui_lagometer & 2) || (prefs.hex_gui_throttlemeter & 2))
|
if ((prefs.hex_gui_lagometer & 2) || (prefs.hex_gui_throttlemeter & 2))
|
||||||
{
|
{
|
||||||
infbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
|
infbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, TRUE, 0);
|
||||||
gtk_box_pack_start (GTK_BOX (box), infbox, 0, 0, 0);
|
gtk_box_pack_start (GTK_BOX (box), infbox, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3661,8 +3780,14 @@ mg_create_userlist (session_gui *gui, GtkWidget *box)
|
|||||||
gtk_box_pack_start (GTK_BOX (box), vbox, TRUE, TRUE, 0);
|
gtk_box_pack_start (GTK_BOX (box), vbox, TRUE, TRUE, 0);
|
||||||
|
|
||||||
gui->namelistinfo = gtk_label_new (NULL);
|
gui->namelistinfo = gtk_label_new (NULL);
|
||||||
gtk_label_set_xalign (GTK_LABEL (gui->namelistinfo), 0.0f);
|
gtk_label_set_xalign (GTK_LABEL (gui->namelistinfo), 0.5f);
|
||||||
gtk_widget_set_halign (gui->namelistinfo, GTK_ALIGN_START);
|
gtk_label_set_justify (GTK_LABEL (gui->namelistinfo), GTK_JUSTIFY_CENTER);
|
||||||
|
gtk_label_set_ellipsize (GTK_LABEL (gui->namelistinfo), PANGO_ELLIPSIZE_END);
|
||||||
|
gtk_label_set_width_chars (GTK_LABEL (gui->namelistinfo), 1);
|
||||||
|
gtk_widget_set_margin_start (gui->namelistinfo, 0);
|
||||||
|
gtk_widget_set_margin_end (gui->namelistinfo, 0);
|
||||||
|
gtk_widget_set_hexpand (gui->namelistinfo, TRUE);
|
||||||
|
gtk_widget_set_halign (gui->namelistinfo, GTK_ALIGN_FILL);
|
||||||
if (prefs.hex_gui_ulist_count)
|
if (prefs.hex_gui_ulist_count)
|
||||||
gtk_box_pack_start (GTK_BOX (vbox), gui->namelistinfo, 0, 0, 0);
|
gtk_box_pack_start (GTK_BOX (vbox), gui->namelistinfo, 0, 0, 0);
|
||||||
|
|
||||||
@@ -4718,7 +4843,14 @@ mg_win32_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
|
|||||||
{
|
{
|
||||||
if (strcmp (command, "__WIN32_TASKBAR_TOGGLE__") == 0)
|
if (strcmp (command, "__WIN32_TASKBAR_TOGGLE__") == 0)
|
||||||
{
|
{
|
||||||
if (gtk_widget_get_visible (current_sess->gui->window))
|
GdkWindowState state = 0;
|
||||||
|
GdkWindow *gdk_window = gtk_widget_get_window (current_sess->gui->window);
|
||||||
|
|
||||||
|
if (gdk_window)
|
||||||
|
state = gdk_window_get_state (gdk_window);
|
||||||
|
|
||||||
|
if (gtk_widget_get_visible (current_sess->gui->window)
|
||||||
|
&& (state & GDK_WINDOW_STATE_ICONIFIED) == 0)
|
||||||
fe_ctrl_gui (current_sess, FE_GUI_ICONIFY, 0);
|
fe_ctrl_gui (current_sess, FE_GUI_ICONIFY, 0);
|
||||||
else
|
else
|
||||||
fe_ctrl_gui (current_sess, FE_GUI_SHOW, 0);
|
fe_ctrl_gui (current_sess, FE_GUI_SHOW, 0);
|
||||||
@@ -5232,9 +5364,14 @@ static void
|
|||||||
mg_handle_drop (GtkWidget *widget, int y, int *pos, int *other_pos)
|
mg_handle_drop (GtkWidget *widget, int y, int *pos, int *other_pos)
|
||||||
{
|
{
|
||||||
int height;
|
int height;
|
||||||
|
GdkWindow *window;
|
||||||
session_gui *gui = current_sess->gui;
|
session_gui *gui = current_sess->gui;
|
||||||
|
|
||||||
height = gdk_window_get_height (gtk_widget_get_window (widget));
|
window = gtk_widget_get_window (widget);
|
||||||
|
if (!window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
height = gdk_window_get_height (window);
|
||||||
|
|
||||||
if (y < height / 2)
|
if (y < height / 2)
|
||||||
{
|
{
|
||||||
@@ -5312,6 +5449,9 @@ mg_drag_begin_cb (GtkWidget *widget, GdkDragContext *context, gpointer userdata)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
window = gtk_widget_get_window (widget);
|
window = gtk_widget_get_window (widget);
|
||||||
|
if (!window)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
width = gdk_window_get_width (window);
|
width = gdk_window_get_width (window);
|
||||||
height = gdk_window_get_height (window);
|
height = gdk_window_get_height (window);
|
||||||
|
|
||||||
@@ -5389,11 +5529,16 @@ mg_drag_motion_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, gui
|
|||||||
width = allocation.width;
|
width = allocation.width;
|
||||||
height = allocation.height;
|
height = allocation.height;
|
||||||
window = gtk_widget_get_window (widget);
|
window = gtk_widget_get_window (widget);
|
||||||
|
if (!window)
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ox = oy = 0;
|
ox = oy = 0;
|
||||||
window = gtk_widget_get_window (widget);
|
window = gtk_widget_get_window (widget);
|
||||||
|
if (!window)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
width = gdk_window_get_width (window);
|
width = gdk_window_get_width (window);
|
||||||
height = gdk_window_get_height (window);
|
height = gdk_window_get_height (window);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1755,44 +1755,6 @@ 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)
|
||||||
{
|
{
|
||||||
@@ -1939,13 +1901,13 @@ menu_about (GtkWidget *wid, gpointer sess)
|
|||||||
|
|
||||||
static struct mymenu mymenu[] = {
|
static struct mymenu mymenu[] = {
|
||||||
{N_("_ZoiteChat"), 0, 0, M_NEWMENU, MENU_ID_ZOITECHAT, 0, 1},
|
{N_("_ZoiteChat"), 0, 0, M_NEWMENU, MENU_ID_ZOITECHAT, 0, 1},
|
||||||
{N_("Network Li_st"), menu_open_server_list, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_s},
|
{N_("Network Li_st"), menu_open_server_list, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{0, 0, 0, M_SEP, 0, 0, 0},
|
{0, 0, 0, M_SEP, 0, 0, 0},
|
||||||
|
|
||||||
{N_("_New"), 0, 0, M_MENUSUB, 0, 0, 1},
|
{N_("_New"), 0, 0, M_MENUSUB, 0, 0, 1},
|
||||||
{N_("Server Tab"), menu_newserver_tab, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_t},
|
{N_("Server Tab"), menu_newserver_tab, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{N_("Channel Tab"), menu_newchannel_tab, 0, M_MENUITEM, 0, 0, 1},
|
{N_("Channel Tab"), menu_newchannel_tab, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{N_("Server Window"), menu_newserver_window, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_n},
|
{N_("Server Window"), menu_newserver_window, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{N_("Channel Window"), menu_newchannel_window, 0, M_MENUITEM, 0, 0, 1},
|
{N_("Channel Window"), menu_newchannel_window, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{0, 0, 0, M_END, 0, 0, 0},
|
{0, 0, 0, M_END, 0, 0, 0},
|
||||||
{0, 0, 0, M_SEP, 0, 0, 0},
|
{0, 0, 0, M_SEP, 0, 0, 0},
|
||||||
@@ -1957,13 +1919,13 @@ 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, MENU_ID_QUIT, 0, 1, GDK_KEY_q}, /* 15 */
|
{N_("_Quit"), menu_quit, 0, M_MENUITEM, MENU_ID_QUIT, 0, 1}, /* 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)
|
||||||
{N_("_Menu Bar"), menu_bar_toggle_cb, 0, M_MENUTOG, MENU_ID_MENUBAR, 0, 1, GDK_KEY_F9},
|
{N_("_Menu Bar"), menu_bar_toggle_cb, 0, M_MENUTOG, MENU_ID_MENUBAR, 0, 1},
|
||||||
{N_("_Topic Bar"), menu_topicbar_toggle, 0, M_MENUTOG, MENU_ID_TOPICBAR, 0, 1},
|
{N_("_Topic Bar"), menu_topicbar_toggle, 0, M_MENUTOG, MENU_ID_TOPICBAR, 0, 1},
|
||||||
{N_("_User List"), menu_userlist_toggle, 0, M_MENUTOG, MENU_ID_USERLIST, 0, 1, GDK_KEY_F7},
|
{N_("_User List"), menu_userlist_toggle, 0, M_MENUTOG, MENU_ID_USERLIST, 0, 1},
|
||||||
{N_("U_ser List Buttons"), menu_ulbuttons_toggle, 0, M_MENUTOG, MENU_ID_ULBUTTONS, 0, 1},
|
{N_("U_ser List Buttons"), menu_ulbuttons_toggle, 0, M_MENUTOG, MENU_ID_ULBUTTONS, 0, 1},
|
||||||
{N_("M_ode Buttons"), menu_cmbuttons_toggle, 0, M_MENUTOG, MENU_ID_MODEBUTTONS, 0, 1},
|
{N_("M_ode Buttons"), menu_cmbuttons_toggle, 0, M_MENUTOG, MENU_ID_MODEBUTTONS, 0, 1},
|
||||||
{0, 0, 0, M_SEP, 0, 0, 0},
|
{0, 0, 0, M_SEP, 0, 0, 0},
|
||||||
@@ -1980,7 +1942,7 @@ static struct mymenu mymenu[] = {
|
|||||||
{N_("Both"), menu_metres_both, 0, M_MENURADIO, 0, 0, 1},
|
{N_("Both"), menu_metres_both, 0, M_MENURADIO, 0, 0, 1},
|
||||||
{0, 0, 0, M_END, 0, 0, 0}, /* 32 */
|
{0, 0, 0, M_END, 0, 0, 0}, /* 32 */
|
||||||
{ 0, 0, 0, M_SEP, 0, 0, 0 },
|
{ 0, 0, 0, M_SEP, 0, 0, 0 },
|
||||||
{N_ ("_Fullscreen"), menu_fullscreen_toggle, 0, M_MENUTOG, MENU_ID_FULLSCREEN, 0, 1, GDK_KEY_F11},
|
{N_ ("_Fullscreen"), menu_fullscreen_toggle, 0, M_MENUTOG, MENU_ID_FULLSCREEN, 0, 1},
|
||||||
|
|
||||||
{N_("_Server"), 0, 0, M_NEWMENU, 0, 0, 1},
|
{N_("_Server"), 0, 0, M_NEWMENU, 0, 0, 1},
|
||||||
{N_("_Disconnect"), menu_disconnect, 0, M_MENUITEM, MENU_ID_DISCONNECT, 0, 1},
|
{N_("_Disconnect"), menu_disconnect, 0, M_MENUITEM, MENU_ID_DISCONNECT, 0, 1},
|
||||||
@@ -1989,7 +1951,7 @@ static struct mymenu mymenu[] = {
|
|||||||
{N_("Channel _List"), menu_chanlist, 0, M_MENUITEM, 0, 0, 1},
|
{N_("Channel _List"), menu_chanlist, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{0, 0, 0, M_SEP, 0, 0, 0},
|
{0, 0, 0, M_SEP, 0, 0, 0},
|
||||||
#define AWAY_OFFSET (41)
|
#define AWAY_OFFSET (41)
|
||||||
{N_("Marked _Away"), menu_away_toggle, 0, M_MENUITEM, MENU_ID_AWAY, 0, 1, GDK_KEY_a},
|
{N_("Marked _Away"), menu_away_toggle, 0, M_MENUITEM, MENU_ID_AWAY, 0, 1},
|
||||||
|
|
||||||
{N_("_Usermenu"), 0, 0, M_NEWMENU, MENU_ID_USERMENU, 0, 1}, /* 40 */
|
{N_("_Usermenu"), 0, 0, M_NEWMENU, MENU_ID_USERMENU, 0, 1}, /* 40 */
|
||||||
|
|
||||||
@@ -2017,25 +1979,191 @@ static struct mymenu mymenu[] = {
|
|||||||
{N_("_Raw Log"), menu_rawlog, 0, M_MENUITEM, 0, 0, 1}, /* 61 */
|
{N_("_Raw Log"), menu_rawlog, 0, M_MENUITEM, 0, 0, 1}, /* 61 */
|
||||||
{N_("_URL Grabber"), url_opengui, 0, M_MENUITEM, 0, 0, 1},
|
{N_("_URL Grabber"), url_opengui, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{0, 0, 0, M_SEP, 0, 0, 0},
|
{0, 0, 0, M_SEP, 0, 0, 0},
|
||||||
{N_("Reset Marker Line"), menu_resetmarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_m},
|
{N_("Reset Marker Line"), menu_resetmarker, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{N_("Move to Marker Line"), menu_movetomarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_M},
|
{N_("Move to Marker Line"), menu_movetomarker, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{N_("_Copy Selection"), menu_copy_selection, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_C},
|
{N_("_Copy Selection"), menu_copy_selection, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{N_("C_lear Text"), menu_flushbuffer, 0, M_MENUITEM, 0, 0, 1},
|
{N_("C_lear Text"), menu_flushbuffer, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{N_("Save Text" ELLIPSIS), menu_savebuffer, 0, M_MENUITEM, 0, 0, 1},
|
{N_("Save Text" ELLIPSIS), menu_savebuffer, 0, M_MENUITEM, 0, 0, 1},
|
||||||
#define SEARCH_OFFSET (70)
|
#define SEARCH_OFFSET (70)
|
||||||
{N_("Search"), 0, 0, M_MENUSUB, 0, 0, 1},
|
{N_("Search"), 0, 0, M_MENUSUB, 0, 0, 1},
|
||||||
{N_("Search Text" ELLIPSIS), menu_search, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_f},
|
{N_("Search Text" ELLIPSIS), menu_search, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{N_("Search Next" ), menu_search_next, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_g},
|
{N_("Search Next" ), menu_search_next, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{N_("Search Previous" ), menu_search_prev, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_G},
|
{N_("Search Previous" ), menu_search_prev, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{0, 0, 0, M_END, 0, 0, 0},
|
{0, 0, 0, M_END, 0, 0, 0},
|
||||||
|
|
||||||
{N_("_Help"), 0, 0, M_NEWMENU, 0, 0, 1}, /* 74 */
|
{N_("_Help"), 0, 0, M_NEWMENU, 0, 0, 1}, /* 74 */
|
||||||
{N_("_Contents"), menu_docs, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_F1},
|
{N_("_Contents"), menu_docs, 0, M_MENUITEM, 0, 0, 1},
|
||||||
{N_("_About"), menu_about, 0, M_MENUITEM, 0, 0, 1},
|
{N_("_About"), menu_about, 0, M_MENUITEM, 0, 0, 1},
|
||||||
|
|
||||||
{0, 0, 0, M_END, 0, 0, 0},
|
{0, 0, 0, M_END, 0, 0, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
menu_get_key_action_name (int index)
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return "network-list";
|
||||||
|
case 4:
|
||||||
|
return "new-server-tab";
|
||||||
|
case 6:
|
||||||
|
return "new-server-window";
|
||||||
|
case CLOSE_OFFSET:
|
||||||
|
return "close";
|
||||||
|
case 15:
|
||||||
|
return "quit";
|
||||||
|
case MENUBAR_OFFSET:
|
||||||
|
return "menu-toggle";
|
||||||
|
case MENUBAR_OFFSET + 2:
|
||||||
|
return "user-list-toggle";
|
||||||
|
case 34:
|
||||||
|
return "fullscreen-toggle";
|
||||||
|
case AWAY_OFFSET:
|
||||||
|
return "away-toggle";
|
||||||
|
case 65:
|
||||||
|
return "reset-marker";
|
||||||
|
case 66:
|
||||||
|
return "move-marker";
|
||||||
|
case 67:
|
||||||
|
return "copy-selection";
|
||||||
|
case SEARCH_OFFSET + 1:
|
||||||
|
return "search-text";
|
||||||
|
case SEARCH_OFFSET + 2:
|
||||||
|
return "search-next";
|
||||||
|
case SEARCH_OFFSET + 3:
|
||||||
|
return "search-previous";
|
||||||
|
case 75:
|
||||||
|
return "contents";
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
menu_add_keybinding_accel (GtkWidget *item, GtkAccelGroup *accel_group, const char *name)
|
||||||
|
{
|
||||||
|
guint keyval;
|
||||||
|
GdkModifierType mod;
|
||||||
|
|
||||||
|
if (!accel_group || !key_get_menu_accel (name, &keyval, &mod))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!strcmp (name, "quit") && !prefs.hex_gui_ctrlq_quit && keyval == GDK_KEY_q && mod == STATE_CTRL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
gtk_widget_add_accelerator (item, "activate", accel_group, keyval, mod, GTK_ACCEL_VISIBLE);
|
||||||
|
g_object_set_data (G_OBJECT (item), "zc-key-accel-key", GUINT_TO_POINTER (keyval));
|
||||||
|
g_object_set_data (G_OBJECT (item), "zc-key-accel-mod", GUINT_TO_POINTER (mod));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
menu_refresh_keybinding_accels (GtkWidget *widget, gpointer data)
|
||||||
|
{
|
||||||
|
GtkAccelGroup *accel_group = data;
|
||||||
|
const char *name;
|
||||||
|
guint keyval;
|
||||||
|
GdkModifierType mod;
|
||||||
|
GtkWidget *submenu;
|
||||||
|
GList *children, *list;
|
||||||
|
|
||||||
|
if (GTK_IS_MENU_ITEM (widget))
|
||||||
|
{
|
||||||
|
keyval = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "zc-key-accel-key"));
|
||||||
|
mod = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "zc-key-accel-mod"));
|
||||||
|
if (keyval != 0)
|
||||||
|
{
|
||||||
|
gtk_widget_remove_accelerator (widget, accel_group, keyval, mod);
|
||||||
|
g_object_set_data (G_OBJECT (widget), "zc-key-accel-key", NULL);
|
||||||
|
g_object_set_data (G_OBJECT (widget), "zc-key-accel-mod", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
name = g_object_get_data (G_OBJECT (widget), "zc-key-action");
|
||||||
|
menu_add_keybinding_accel (widget, accel_group, name);
|
||||||
|
|
||||||
|
submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
|
||||||
|
if (submenu)
|
||||||
|
menu_refresh_keybinding_accels (submenu, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GTK_IS_CONTAINER (widget))
|
||||||
|
{
|
||||||
|
children = gtk_container_get_children (GTK_CONTAINER (widget));
|
||||||
|
for (list = children; list; list = g_list_next (list))
|
||||||
|
menu_refresh_keybinding_accels (list->data, data);
|
||||||
|
g_list_free (children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
menu_update_quit_accel (void)
|
||||||
|
{
|
||||||
|
session *sess;
|
||||||
|
GSList *list;
|
||||||
|
GtkAccelGroup *accel_group;
|
||||||
|
|
||||||
|
list = sess_list;
|
||||||
|
while (list)
|
||||||
|
{
|
||||||
|
sess = list->data;
|
||||||
|
if (sess && sess->gui && sess->gui->menu)
|
||||||
|
{
|
||||||
|
accel_group = g_object_get_data (G_OBJECT (sess->gui->menu), "accel");
|
||||||
|
if (accel_group)
|
||||||
|
menu_refresh_keybinding_accels (sess->gui->menu, accel_group);
|
||||||
|
}
|
||||||
|
list = g_slist_next (list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
menu_key_action (const char *name, guint keyval, GdkModifierType state)
|
||||||
|
{
|
||||||
|
if (!name)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!strcmp (name, "network-list"))
|
||||||
|
menu_open_server_list (NULL, NULL);
|
||||||
|
else if (!strcmp (name, "new-server-tab"))
|
||||||
|
menu_newserver_tab (NULL, NULL);
|
||||||
|
else if (!strcmp (name, "new-server-window"))
|
||||||
|
menu_newserver_window (NULL, NULL);
|
||||||
|
else if (!strcmp (name, "close"))
|
||||||
|
menu_close (NULL, NULL);
|
||||||
|
else if (!strcmp (name, "quit"))
|
||||||
|
{
|
||||||
|
if (!prefs.hex_gui_ctrlq_quit && keyval == GDK_KEY_q && (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) == STATE_CTRL)
|
||||||
|
return FALSE;
|
||||||
|
menu_quit (NULL, NULL);
|
||||||
|
}
|
||||||
|
else if (!strcmp (name, "menu-toggle"))
|
||||||
|
menu_bar_toggle_cb ();
|
||||||
|
else if (!strcmp (name, "user-list-toggle"))
|
||||||
|
menu_userlist_toggle (NULL, NULL);
|
||||||
|
else if (!strcmp (name, "fullscreen-toggle"))
|
||||||
|
menu_fullscreen_toggle (NULL, NULL);
|
||||||
|
else if (!strcmp (name, "away-toggle"))
|
||||||
|
menu_away_toggle (NULL, NULL);
|
||||||
|
else if (!strcmp (name, "reset-marker"))
|
||||||
|
menu_resetmarker (NULL, NULL);
|
||||||
|
else if (!strcmp (name, "move-marker"))
|
||||||
|
menu_movetomarker (NULL, NULL);
|
||||||
|
else if (!strcmp (name, "copy-selection"))
|
||||||
|
menu_copy_selection (NULL, NULL);
|
||||||
|
else if (!strcmp (name, "search-text"))
|
||||||
|
menu_search ();
|
||||||
|
else if (!strcmp (name, "search-next"))
|
||||||
|
menu_search_next (NULL);
|
||||||
|
else if (!strcmp (name, "search-previous"))
|
||||||
|
menu_search_prev (NULL);
|
||||||
|
else if (!strcmp (name, "contents"))
|
||||||
|
menu_docs (NULL, NULL);
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
menu_set_away (session_gui *gui, int away)
|
menu_set_away (session_gui *gui, int away)
|
||||||
{
|
{
|
||||||
@@ -2309,7 +2437,7 @@ menu_reorder (GtkMenu *menu, GtkWidget *item, int pos)
|
|||||||
if (pos < 0) /* position offset from end/bottom */
|
if (pos < 0) /* position offset from end/bottom */
|
||||||
{
|
{
|
||||||
GList *children = gtk_container_get_children (GTK_CONTAINER (menu));
|
GList *children = gtk_container_get_children (GTK_CONTAINER (menu));
|
||||||
int length = g_list_length (children);
|
gint length = (gint) g_list_length (children);
|
||||||
|
|
||||||
g_list_free (children);
|
g_list_free (children);
|
||||||
gtk_menu_reorder_child (menu, item, (length + pos) - 1);
|
gtk_menu_reorder_child (menu, item, (length + pos) - 1);
|
||||||
@@ -2381,7 +2509,7 @@ menu_add_sub (GtkWidget *menu, menu_entry *me)
|
|||||||
if (pos < 0) /* position offset from end/bottom */
|
if (pos < 0) /* position offset from end/bottom */
|
||||||
{
|
{
|
||||||
GList *children = gtk_container_get_children (GTK_CONTAINER (menu));
|
GList *children = gtk_container_get_children (GTK_CONTAINER (menu));
|
||||||
int length = g_list_length (children);
|
gint length = (gint) g_list_length (children);
|
||||||
|
|
||||||
g_list_free (children);
|
g_list_free (children);
|
||||||
pos = length + pos;
|
pos = length + pos;
|
||||||
@@ -2641,6 +2769,8 @@ 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:
|
||||||
|
g_object_set_data (G_OBJECT (item), "zc-key-action", (gpointer) menu_get_key_action_name (i));
|
||||||
|
menu_add_keybinding_accel (item, accel_group, menu_get_key_action_name (i));
|
||||||
if (mymenu[i].key != 0 && !(mymenu[i].id == MENU_ID_QUIT && !prefs.hex_gui_ctrlq_quit))
|
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,
|
||||||
@@ -2669,6 +2799,8 @@ normalitem:
|
|||||||
case M_MENUTOG:
|
case M_MENUTOG:
|
||||||
item = gtk_check_menu_item_new_with_mnemonic (_(mymenu[i].text));
|
item = gtk_check_menu_item_new_with_mnemonic (_(mymenu[i].text));
|
||||||
togitem:
|
togitem:
|
||||||
|
g_object_set_data (G_OBJECT (item), "zc-key-action", (gpointer) menu_get_key_action_name (i));
|
||||||
|
menu_add_keybinding_accel (item, accel_group, menu_get_key_action_name (i));
|
||||||
/* must avoid callback for Radio buttons */
|
/* must avoid callback for Radio buttons */
|
||||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), mymenu[i].state);
|
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), mymenu[i].state);
|
||||||
/*gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
|
/*gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ 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_update_quit_accel (void);
|
||||||
|
gboolean menu_key_action (const char *name, guint keyval, GdkModifierType state);
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -920,7 +920,10 @@ tray_menu_notify_cb (GObject *tray, GParamSpec *pspec, gpointer user_data)
|
|||||||
{
|
{
|
||||||
if (!tray_backend_is_embedded ())
|
if (!tray_backend_is_embedded ())
|
||||||
{
|
{
|
||||||
tray_restore_timer = g_timeout_add(500, (GSourceFunc)tray_menu_try_restore, NULL);
|
if (!tray_restore_timer)
|
||||||
|
{
|
||||||
|
tray_restore_timer = g_timeout_add (500, (GSourceFunc) tray_menu_try_restore, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -936,9 +939,10 @@ tray_menu_notify_cb (GObject *tray, GParamSpec *pspec, gpointer user_data)
|
|||||||
static gboolean
|
static gboolean
|
||||||
tray_menu_try_restore (void)
|
tray_menu_try_restore (void)
|
||||||
{
|
{
|
||||||
tray_cleanup();
|
tray_restore_timer = 0;
|
||||||
tray_init();
|
tray_cleanup ();
|
||||||
return TRUE;
|
tray_init ();
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "../common/servlist.h"
|
#include "../common/servlist.h"
|
||||||
#include "../common/cfgfiles.h"
|
#include "../common/cfgfiles.h"
|
||||||
#include "../common/fe.h"
|
#include "../common/fe.h"
|
||||||
|
#include "../common/secretstore.h"
|
||||||
#include "../common/util.h"
|
#include "../common/util.h"
|
||||||
|
|
||||||
#include "fe-gtk.h"
|
#include "fe-gtk.h"
|
||||||
@@ -85,6 +86,12 @@ static GtkWidget *edit_entry_nick2;
|
|||||||
static GtkWidget *edit_entry_user;
|
static GtkWidget *edit_entry_user;
|
||||||
static GtkWidget *edit_entry_real;
|
static GtkWidget *edit_entry_real;
|
||||||
static GtkWidget *edit_entry_pass;
|
static GtkWidget *edit_entry_pass;
|
||||||
|
static GtkWidget *edit_check_show_pass;
|
||||||
|
static GtkWidget *edit_check_use_keyring;
|
||||||
|
static GtkWidget *edit_button_encrypt_pass;
|
||||||
|
static GtkWidget *edit_button_import_pass;
|
||||||
|
static int edit_pass_changed;
|
||||||
|
static char *edit_loaded_password;
|
||||||
static GtkWidget *edit_label_nick;
|
static GtkWidget *edit_label_nick;
|
||||||
static GtkWidget *edit_label_nick2;
|
static GtkWidget *edit_label_nick2;
|
||||||
static GtkWidget *edit_label_real;
|
static GtkWidget *edit_label_real;
|
||||||
@@ -103,6 +110,168 @@ 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 void servlist_password_changed_cb (GtkEditable *editable, gpointer userdata);
|
||||||
|
|
||||||
|
static void
|
||||||
|
servlist_update_password_tools (ircnet *net)
|
||||||
|
{
|
||||||
|
gboolean has_local;
|
||||||
|
gboolean use_keyring;
|
||||||
|
|
||||||
|
if (!edit_button_encrypt_pass || !edit_button_import_pass)
|
||||||
|
return;
|
||||||
|
|
||||||
|
use_keyring = net && (net->flags & FLAG_USE_KEYRING);
|
||||||
|
has_local = net && net->pass && *net->pass && !use_keyring && !edit_pass_changed;
|
||||||
|
gtk_widget_set_sensitive (edit_button_encrypt_pass, has_local && !servlist_password_is_encrypted (net->pass));
|
||||||
|
gtk_widget_set_sensitive (edit_button_import_pass, has_local);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
servlist_entry_set_text_silent (GtkWidget *entry, const char *text)
|
||||||
|
{
|
||||||
|
g_signal_handlers_block_by_func (G_OBJECT (entry), G_CALLBACK (servlist_password_changed_cb), NULL);
|
||||||
|
gtk_entry_set_text (GTK_ENTRY (entry), text);
|
||||||
|
g_signal_handlers_unblock_by_func (G_OBJECT (entry), G_CALLBACK (servlist_password_changed_cb), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
servlist_display_password (ircnet *net)
|
||||||
|
{
|
||||||
|
if (!net)
|
||||||
|
return NULL;
|
||||||
|
if (edit_pass_changed)
|
||||||
|
return g_strdup (gtk_entry_get_text (GTK_ENTRY (edit_entry_pass)));
|
||||||
|
if (edit_loaded_password)
|
||||||
|
return g_strdup (edit_loaded_password);
|
||||||
|
if (net->flags & FLAG_USE_KEYRING)
|
||||||
|
return secretstore_get_network_password (net->name);
|
||||||
|
return servlist_password_decrypt_for_storage (net->pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
servlist_toggle_show_password_cb (GtkToggleButton *toggle, gpointer userdata)
|
||||||
|
{
|
||||||
|
if (gtk_toggle_button_get_active (toggle))
|
||||||
|
{
|
||||||
|
char *password = servlist_display_password (selected_net);
|
||||||
|
if (password)
|
||||||
|
{
|
||||||
|
if (edit_loaded_password)
|
||||||
|
{
|
||||||
|
memset (edit_loaded_password, 0, strlen (edit_loaded_password));
|
||||||
|
g_free (edit_loaded_password);
|
||||||
|
}
|
||||||
|
edit_loaded_password = g_strdup (password);
|
||||||
|
servlist_entry_set_text_silent (userdata, password);
|
||||||
|
memset (password, 0, strlen (password));
|
||||||
|
g_free (password);
|
||||||
|
}
|
||||||
|
gtk_entry_set_visibility (GTK_ENTRY (userdata), TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gtk_entry_set_visibility (GTK_ENTRY (userdata), FALSE);
|
||||||
|
if (edit_loaded_password && !edit_pass_changed)
|
||||||
|
servlist_entry_set_text_silent (userdata, "***");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
servlist_toggle_keyring_cb (GtkToggleButton *toggle, gpointer userdata)
|
||||||
|
{
|
||||||
|
servlist_update_password_tools (selected_net);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
servlist_password_changed_cb (GtkEditable *editable, gpointer userdata)
|
||||||
|
{
|
||||||
|
edit_pass_changed = 1;
|
||||||
|
if (edit_loaded_password && strcmp (gtk_entry_get_text (GTK_ENTRY (editable)), "***"))
|
||||||
|
{
|
||||||
|
memset (edit_loaded_password, 0, strlen (edit_loaded_password));
|
||||||
|
g_free (edit_loaded_password);
|
||||||
|
edit_loaded_password = NULL;
|
||||||
|
}
|
||||||
|
servlist_update_password_tools (selected_net);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
servlist_encrypt_password_cb (GtkWidget *button, gpointer userdata)
|
||||||
|
{
|
||||||
|
ircnet *net = userdata;
|
||||||
|
char *plain;
|
||||||
|
char *enc;
|
||||||
|
|
||||||
|
if (!net || (net->flags & FLAG_USE_KEYRING) || !net->pass || servlist_password_is_encrypted (net->pass))
|
||||||
|
return;
|
||||||
|
|
||||||
|
plain = servlist_password_decrypt_for_storage (net->pass);
|
||||||
|
if (!plain || !*plain)
|
||||||
|
{
|
||||||
|
if (plain)
|
||||||
|
{
|
||||||
|
memset (plain, 0, strlen (plain));
|
||||||
|
g_free (plain);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
enc = servlist_password_encrypt_for_storage (plain);
|
||||||
|
memset (plain, 0, strlen (plain));
|
||||||
|
g_free (plain);
|
||||||
|
if (!enc)
|
||||||
|
{
|
||||||
|
fe_message (_("Could not encrypt this password."), FE_MSG_WARN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (net->pass);
|
||||||
|
net->pass = enc;
|
||||||
|
servlist_save ();
|
||||||
|
servlist_update_password_tools (net);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
servlist_import_password_cb (GtkWidget *button, gpointer userdata)
|
||||||
|
{
|
||||||
|
ircnet *net = userdata;
|
||||||
|
char *plain;
|
||||||
|
|
||||||
|
if (!net || !net->name || (net->flags & FLAG_USE_KEYRING) || !net->pass || !*net->pass)
|
||||||
|
return;
|
||||||
|
|
||||||
|
plain = servlist_password_decrypt_for_storage (net->pass);
|
||||||
|
if (!plain || !*plain)
|
||||||
|
{
|
||||||
|
if (plain)
|
||||||
|
{
|
||||||
|
memset (plain, 0, strlen (plain));
|
||||||
|
g_free (plain);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!secretstore_set_network_password (net->name, plain))
|
||||||
|
{
|
||||||
|
memset (plain, 0, strlen (plain));
|
||||||
|
g_free (plain);
|
||||||
|
fe_message (_("Could not move this password into the system keyring."), FE_MSG_WARN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (plain, 0, strlen (plain));
|
||||||
|
g_free (plain);
|
||||||
|
g_free (net->pass);
|
||||||
|
net->pass = NULL;
|
||||||
|
net->flags |= FLAG_USE_KEYRING;
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (edit_check_use_keyring), TRUE);
|
||||||
|
servlist_entry_set_text_silent (edit_entry_pass, "***");
|
||||||
|
edit_pass_changed = 0;
|
||||||
|
servlist_save ();
|
||||||
|
servlist_update_password_tools (net);
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
servlist_get_cert_file (ircnet *net)
|
servlist_get_cert_file (ircnet *net)
|
||||||
@@ -1078,14 +1247,79 @@ servlist_update_from_entry (char **str, GtkWidget *entry)
|
|||||||
*str = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
|
*str = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
servlist_edit_current_password (ircnet *net)
|
||||||
|
{
|
||||||
|
if (!net)
|
||||||
|
return NULL;
|
||||||
|
if (net->flags & FLAG_USE_KEYRING)
|
||||||
|
return secretstore_get_network_password (net->name);
|
||||||
|
return servlist_password_decrypt_for_storage (net->pass);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
servlist_edit_update (ircnet *net)
|
servlist_edit_update (ircnet *net)
|
||||||
{
|
{
|
||||||
|
gboolean use_keyring;
|
||||||
|
gboolean keyring_changed;
|
||||||
|
char *password = NULL;
|
||||||
servlist_update_from_entry (&net->nick, edit_entry_nick);
|
servlist_update_from_entry (&net->nick, edit_entry_nick);
|
||||||
servlist_update_from_entry (&net->nick2, edit_entry_nick2);
|
servlist_update_from_entry (&net->nick2, edit_entry_nick2);
|
||||||
servlist_update_from_entry (&net->user, edit_entry_user);
|
servlist_update_from_entry (&net->user, edit_entry_user);
|
||||||
servlist_update_from_entry (&net->real, edit_entry_real);
|
servlist_update_from_entry (&net->real, edit_entry_real);
|
||||||
servlist_update_from_entry (&net->pass, edit_entry_pass);
|
if (net && net->name)
|
||||||
|
{
|
||||||
|
use_keyring = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (edit_check_use_keyring));
|
||||||
|
keyring_changed = !!(net->flags & FLAG_USE_KEYRING) != !!use_keyring;
|
||||||
|
if (!edit_pass_changed && !keyring_changed)
|
||||||
|
return;
|
||||||
|
if (edit_pass_changed)
|
||||||
|
password = g_strdup (gtk_entry_get_text (GTK_ENTRY (edit_entry_pass)));
|
||||||
|
else
|
||||||
|
password = servlist_edit_current_password (net);
|
||||||
|
if (use_keyring)
|
||||||
|
{
|
||||||
|
if (password && *password)
|
||||||
|
{
|
||||||
|
if (!secretstore_set_network_password (net->name, password))
|
||||||
|
{
|
||||||
|
fe_message (_("No system keyring is available. ZoiteChat can save this password using local encrypted fallback storage, but it is less protected than your desktop keyring."), FE_MSG_WARN);
|
||||||
|
memset (password, 0, strlen (password));
|
||||||
|
g_free (password);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
secretstore_delete_network_password (net->name);
|
||||||
|
net->flags |= FLAG_USE_KEYRING;
|
||||||
|
g_free (net->pass);
|
||||||
|
net->pass = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *enc = NULL;
|
||||||
|
if (password && *password)
|
||||||
|
{
|
||||||
|
enc = servlist_password_encrypt_for_storage (password);
|
||||||
|
if (!enc)
|
||||||
|
{
|
||||||
|
fe_message (_("Could not encrypt this password."), FE_MSG_WARN);
|
||||||
|
memset (password, 0, strlen (password));
|
||||||
|
g_free (password);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secretstore_delete_network_password (net->name);
|
||||||
|
net->flags &= ~FLAG_USE_KEYRING;
|
||||||
|
g_free (net->pass);
|
||||||
|
net->pass = enc;
|
||||||
|
}
|
||||||
|
if (password)
|
||||||
|
{
|
||||||
|
memset (password, 0, strlen (password));
|
||||||
|
g_free (password);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1093,9 +1327,19 @@ servlist_edit_close_cb (GtkWidget *button, gpointer userdata)
|
|||||||
{
|
{
|
||||||
if (selected_net)
|
if (selected_net)
|
||||||
servlist_edit_update (selected_net);
|
servlist_edit_update (selected_net);
|
||||||
|
if (edit_loaded_password)
|
||||||
|
{
|
||||||
|
memset (edit_loaded_password, 0, strlen (edit_loaded_password));
|
||||||
|
g_free (edit_loaded_password);
|
||||||
|
edit_loaded_password = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
gtk_widget_destroy (edit_win);
|
gtk_widget_destroy (edit_win);
|
||||||
edit_win = NULL;
|
edit_win = NULL;
|
||||||
|
edit_entry_pass = NULL;
|
||||||
|
edit_check_show_pass = NULL;
|
||||||
|
edit_button_encrypt_pass = NULL;
|
||||||
|
edit_button_import_pass = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
@@ -1126,6 +1370,10 @@ servlist_edit_cb (GtkWidget *but, gpointer none)
|
|||||||
{
|
{
|
||||||
if (!servlist_has_selection (GTK_TREE_VIEW (networks_tree)))
|
if (!servlist_has_selection (GTK_TREE_VIEW (networks_tree)))
|
||||||
return;
|
return;
|
||||||
|
if (!selected_net || !selected_net->name)
|
||||||
|
return;
|
||||||
|
if ((selected_net->flags & FLAG_USE_KEYRING) && !secretstore_require_unlock (selected_net->name))
|
||||||
|
return;
|
||||||
|
|
||||||
edit_win = servlist_open_edit (serverlist_win, selected_net);
|
edit_win = servlist_open_edit (serverlist_win, selected_net);
|
||||||
gtkutil_set_icon (edit_win);
|
gtkutil_set_icon (edit_win);
|
||||||
@@ -2317,7 +2565,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
|||||||
|
|
||||||
|
|
||||||
/* Checkboxes and entries */
|
/* Checkboxes and entries */
|
||||||
table3 = gtkutil_grid_new (14, 2, FALSE);
|
table3 = gtkutil_grid_new (17, 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);
|
||||||
@@ -2336,38 +2584,97 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
|||||||
#endif
|
#endif
|
||||||
servlist_create_check (1, net->flags & FLAG_USE_GLOBAL, table3, 5, 0, _("Use global user information"));
|
servlist_create_check (1, net->flags & FLAG_USE_GLOBAL, table3, 5, 0, _("Use global user information"));
|
||||||
|
|
||||||
edit_entry_nick = servlist_create_entry (table3, _("_Nick name:"), 6, net->nick, &edit_label_nick, 0);
|
edit_check_use_keyring = gtk_check_button_new_with_mnemonic (_("Use system keyring"));
|
||||||
edit_entry_nick2 = servlist_create_entry (table3, _("Second choice:"), 7, net->nick2, &edit_label_nick2, 0);
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (edit_check_use_keyring), net->flags & FLAG_USE_KEYRING);
|
||||||
edit_entry_real = servlist_create_entry (table3, _("Rea_l name:"), 8, net->real, &edit_label_real, 0);
|
servlist_table_attach (table3, edit_check_use_keyring, 0, 2, 6, 7,
|
||||||
edit_entry_user = servlist_create_entry (table3, _("_User name:"), 9, net->user, &edit_label_user, 0);
|
FALSE, FALSE,
|
||||||
|
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
|
||||||
|
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
|
||||||
|
g_signal_connect (G_OBJECT (edit_check_use_keyring), "toggled",
|
||||||
|
G_CALLBACK (servlist_toggle_keyring_cb), NULL);
|
||||||
|
|
||||||
|
edit_entry_nick = servlist_create_entry (table3, _("_Nick name:"), 7, net->nick, &edit_label_nick, 0);
|
||||||
|
edit_entry_nick2 = servlist_create_entry (table3, _("Second choice:"), 8, net->nick2, &edit_label_nick2, 0);
|
||||||
|
edit_entry_real = servlist_create_entry (table3, _("Rea_l name:"), 9, net->real, &edit_label_real, 0);
|
||||||
|
edit_entry_user = servlist_create_entry (table3, _("_User name:"), 10, net->user, &edit_label_user, 0);
|
||||||
|
|
||||||
label_logintype = gtk_label_new (_("Login method:"));
|
label_logintype = gtk_label_new (_("Login method:"));
|
||||||
servlist_table_attach (table3, label_logintype, 0, 1, 10, 11,
|
servlist_table_attach (table3, label_logintype, 0, 1, 11, 12,
|
||||||
FALSE, FALSE,
|
FALSE, FALSE,
|
||||||
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
|
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
|
||||||
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
|
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
|
||||||
gtk_widget_set_halign (label_logintype, GTK_ALIGN_START);
|
gtk_widget_set_halign (label_logintype, GTK_ALIGN_START);
|
||||||
gtk_widget_set_valign (label_logintype, GTK_ALIGN_CENTER);
|
gtk_widget_set_valign (label_logintype, GTK_ALIGN_CENTER);
|
||||||
combobox_logintypes = servlist_create_logintypecombo (notebook);
|
combobox_logintypes = servlist_create_logintypecombo (notebook);
|
||||||
servlist_table_attach (table3, combobox_logintypes, 1, 2, 10, 11,
|
servlist_table_attach (table3, combobox_logintypes, 1, 2, 11, 12,
|
||||||
FALSE, FALSE,
|
FALSE, FALSE,
|
||||||
SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL,
|
SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL,
|
||||||
4, 2);
|
4, 2);
|
||||||
|
|
||||||
edit_entry_pass = servlist_create_entry (table3, _("Password:"), 11, net->pass, 0, _("Password used for login. If in doubt, leave blank."));
|
edit_entry_pass = servlist_create_entry (table3, _("Password:"), 12, NULL, 0, _("Password used for login. If in doubt, leave blank."));
|
||||||
|
if (edit_loaded_password)
|
||||||
|
{
|
||||||
|
memset (edit_loaded_password, 0, strlen (edit_loaded_password));
|
||||||
|
g_free (edit_loaded_password);
|
||||||
|
edit_loaded_password = NULL;
|
||||||
|
}
|
||||||
|
edit_pass_changed = 0;
|
||||||
|
g_signal_connect (G_OBJECT (edit_entry_pass), "changed",
|
||||||
|
G_CALLBACK (servlist_password_changed_cb), NULL);
|
||||||
|
if (net->flags & FLAG_USE_KEYRING)
|
||||||
|
{
|
||||||
|
char *stored = secretstore_get_network_password (net->name);
|
||||||
|
if (stored && *stored)
|
||||||
|
{
|
||||||
|
edit_loaded_password = g_strdup (stored);
|
||||||
|
servlist_entry_set_text_silent (edit_entry_pass, "***");
|
||||||
|
}
|
||||||
|
if (stored)
|
||||||
|
{
|
||||||
|
memset (stored, 0, strlen (stored));
|
||||||
|
g_free (stored);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (net->pass && *net->pass)
|
||||||
|
{
|
||||||
|
servlist_entry_set_text_silent (edit_entry_pass, "***");
|
||||||
|
}
|
||||||
|
edit_pass_changed = 0;
|
||||||
gtk_entry_set_visibility (GTK_ENTRY (edit_entry_pass), FALSE);
|
gtk_entry_set_visibility (GTK_ENTRY (edit_entry_pass), FALSE);
|
||||||
if (selected_net && selected_net->logintype == LOGIN_SASLEXTERNAL)
|
if (selected_net && selected_net->logintype == LOGIN_SASLEXTERNAL)
|
||||||
gtk_widget_set_sensitive (edit_entry_pass, FALSE);
|
gtk_widget_set_sensitive (edit_entry_pass, FALSE);
|
||||||
|
edit_check_show_pass = gtk_check_button_new_with_mnemonic (_("Show password"));
|
||||||
|
servlist_table_attach (table3, edit_check_show_pass, 0, 2, 13, 14,
|
||||||
|
FALSE, FALSE,
|
||||||
|
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
|
||||||
|
4, 2);
|
||||||
|
g_signal_connect (G_OBJECT (edit_check_show_pass), "toggled",
|
||||||
|
G_CALLBACK (servlist_toggle_show_password_cb), edit_entry_pass);
|
||||||
|
|
||||||
|
edit_button_encrypt_pass = gtk_button_new_with_mnemonic (_("Encrypt saved password"));
|
||||||
|
servlist_table_attach (table3, edit_button_encrypt_pass, 0, 1, 14, 15,
|
||||||
|
FALSE, FALSE,
|
||||||
|
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
|
||||||
|
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
|
||||||
|
g_signal_connect (G_OBJECT (edit_button_encrypt_pass), "clicked",
|
||||||
|
G_CALLBACK (servlist_encrypt_password_cb), net);
|
||||||
|
edit_button_import_pass = gtk_button_new_with_mnemonic (_("Move password to keyring"));
|
||||||
|
servlist_table_attach (table3, edit_button_import_pass, 1, 2, 14, 15,
|
||||||
|
FALSE, FALSE,
|
||||||
|
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
|
||||||
|
4, 2);
|
||||||
|
g_signal_connect (G_OBJECT (edit_button_import_pass), "clicked",
|
||||||
|
G_CALLBACK (servlist_import_password_cb), net);
|
||||||
|
|
||||||
label34 = gtk_label_new (_("Character set:"));
|
label34 = gtk_label_new (_("Character set:"));
|
||||||
servlist_table_attach (table3, label34, 0, 1, 12, 13,
|
servlist_table_attach (table3, label34, 0, 1, 15, 16,
|
||||||
FALSE, FALSE,
|
FALSE, FALSE,
|
||||||
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
|
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
|
||||||
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
|
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
|
||||||
gtk_widget_set_halign (label34, GTK_ALIGN_START);
|
gtk_widget_set_halign (label34, GTK_ALIGN_START);
|
||||||
gtk_widget_set_valign (label34, GTK_ALIGN_CENTER);
|
gtk_widget_set_valign (label34, GTK_ALIGN_CENTER);
|
||||||
comboboxentry_charset = servlist_create_charsetcombo ();
|
comboboxentry_charset = servlist_create_charsetcombo ();
|
||||||
servlist_table_attach (table3, comboboxentry_charset, 1, 2, 12, 13,
|
servlist_table_attach (table3, comboboxentry_charset, 1, 2, 15, 16,
|
||||||
FALSE, FALSE,
|
FALSE, FALSE,
|
||||||
SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL,
|
SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL,
|
||||||
4, 2);
|
4, 2);
|
||||||
@@ -2393,7 +2700,7 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
|||||||
G_CALLBACK (servlist_delete_client_cert_cb), net);
|
G_CALLBACK (servlist_delete_client_cert_cb), net);
|
||||||
gtk_box_pack_start (GTK_BOX (hbox_cert_buttons), edit_button_cert_delete, FALSE, FALSE, 0);
|
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,
|
servlist_table_attach (table3, hbox_cert_buttons, 0, 2, 16, 17,
|
||||||
FALSE, FALSE,
|
FALSE, FALSE,
|
||||||
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
|
SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER,
|
||||||
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
|
SERVLIST_X_PADDING, SERVLIST_Y_PADDING);
|
||||||
@@ -2417,6 +2724,8 @@ servlist_open_edit (GtkWidget *parent, ircnet *net)
|
|||||||
{
|
{
|
||||||
servlist_toggle_global_user (FALSE);
|
servlist_toggle_global_user (FALSE);
|
||||||
}
|
}
|
||||||
|
servlist_toggle_keyring_cb (GTK_TOGGLE_BUTTON (edit_check_use_keyring), NULL);
|
||||||
|
servlist_update_password_tools (net);
|
||||||
|
|
||||||
gtk_widget_grab_focus (button10);
|
gtk_widget_grab_focus (button10);
|
||||||
gtk_widget_grab_default (button10);
|
gtk_widget_grab_default (button10);
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ static const setting appearance_advanced_settings[] =
|
|||||||
{ST_HEADER, N_("Advanced"),0,0,0},
|
{ST_HEADER, N_("Advanced"),0,0,0},
|
||||||
{ST_EFILE, N_ ("Background image:"), P_OFFSETNL (hex_text_background), 0, 0, sizeof prefs.hex_text_background},
|
{ST_EFILE, N_ ("Background image:"), P_OFFSETNL (hex_text_background), 0, 0, sizeof prefs.hex_text_background},
|
||||||
{ST_HSCALE, N_("Window opacity:"), P_OFFINTNL(hex_gui_transparency),0,0,0},
|
{ST_HSCALE, N_("Window opacity:"), P_OFFINTNL(hex_gui_transparency),0,0,0},
|
||||||
|
{ST_HSCALE, N_("Mouse wheel scroll speed (Slower ← → Faster):"), P_OFFINTNL(hex_gui_mouse_scroll_speed), 0, 0, 100},
|
||||||
|
|
||||||
{ST_END, 0, 0, 0, 0, 0}
|
{ST_END, 0, 0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
@@ -545,6 +546,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_("Hide hostmasks in join and part messages"), P_OFFINTNL(hex_irc_hide_join_part_hostmask), 0, 0, 0},
|
||||||
{ST_TOGGLE, N_("Enable Ctrl+Q to quit"), P_OFFINTNL(hex_gui_ctrlq_quit), 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}
|
||||||
@@ -582,6 +584,7 @@ static const setting advanced_settings[] =
|
|||||||
{ST_TOGGLE, N_("Display lists in compact mode"), P_OFFINTNL(hex_gui_compact), N_("Use less spacing between user list/channel tree rows."), 0, 0},
|
{ST_TOGGLE, N_("Display lists in compact mode"), P_OFFINTNL(hex_gui_compact), N_("Use less spacing between user list/channel tree rows."), 0, 0},
|
||||||
{ST_TOGGLE, N_("Use server time if supported"), P_OFFINTNL(hex_irc_cap_server_time), N_("Display timestamps obtained from server if it supports the time-server extension."), 0, 0},
|
{ST_TOGGLE, N_("Use server time if supported"), P_OFFINTNL(hex_irc_cap_server_time), N_("Display timestamps obtained from server if it supports the time-server extension."), 0, 0},
|
||||||
{ST_TOGGLE, N_("Automatically reconnect to servers on disconnect"), P_OFFINTNL(hex_net_auto_reconnect), 0, 0, 1},
|
{ST_TOGGLE, N_("Automatically reconnect to servers on disconnect"), P_OFFINTNL(hex_net_auto_reconnect), 0, 0, 1},
|
||||||
|
{ST_NUMBER, N_("Lag check interval:"), P_OFFINTNL(hex_net_lag_check), 0, (const char **)N_("seconds."), 9999},
|
||||||
{ST_NUMBER, N_("Auto reconnect delay:"), P_OFFINTNL(hex_net_reconnect_delay), 0, 0, 9999},
|
{ST_NUMBER, N_("Auto reconnect delay:"), P_OFFINTNL(hex_net_reconnect_delay), 0, 0, 9999},
|
||||||
{ST_NUMBER, N_("Auto join delay:"), P_OFFINTNL(hex_irc_join_delay), 0, 0, 9999},
|
{ST_NUMBER, N_("Auto join delay:"), P_OFFINTNL(hex_irc_join_delay), 0, 0, 9999},
|
||||||
{ST_MENU, N_("Ban Type:"), P_OFFINTNL(hex_irc_ban_type), N_("Attempt to use this banmask when banning or quieting. (requires irc_who_join)"), bantypemenu, 0},
|
{ST_MENU, N_("Ban Type:"), P_OFFINTNL(hex_irc_ban_type), N_("Attempt to use this banmask when banning or quieting. (requires irc_who_join)"), bantypemenu, 0},
|
||||||
@@ -655,6 +658,11 @@ static const setting network_settings[] =
|
|||||||
{ST_MENU, N_("Type:"), P_OFFINTNL(hex_net_proxy_type), 0, proxytypes, 0},
|
{ST_MENU, N_("Type:"), P_OFFINTNL(hex_net_proxy_type), 0, proxytypes, 0},
|
||||||
{ST_MENU, N_("Use proxy for:"), P_OFFINTNL(hex_net_proxy_use), 0, proxyuse, 0},
|
{ST_MENU, N_("Use proxy for:"), P_OFFINTNL(hex_net_proxy_use), 0, proxyuse, 0},
|
||||||
|
|
||||||
|
{ST_HEADER, N_("Connection Health"), 0, 0, 0, 0},
|
||||||
|
{ST_NUMBER, N_("TCP keepalive idle:"), P_OFFINTNL(hex_net_keepalive_idle), 0, (const char **)N_("seconds."), 7200},
|
||||||
|
{ST_NUMBER, N_("TCP keepalive interval:"), P_OFFINTNL(hex_net_keepalive_interval), 0, (const char **)N_("seconds."), 600},
|
||||||
|
{ST_NUMBER, N_("TCP keepalive probes:"), P_OFFINTNL(hex_net_keepalive_count), 0, 0, 20},
|
||||||
|
|
||||||
{ST_HEADER, N_("Proxy Authentication"), 0, 0, 0, 0},
|
{ST_HEADER, N_("Proxy Authentication"), 0, 0, 0, 0},
|
||||||
{ST_TOGGLE, N_("Use authentication (HTTP or SOCKS5 only)"), P_OFFINTNL(hex_net_proxy_auth), 0, 0, 0},
|
{ST_TOGGLE, N_("Use authentication (HTTP or SOCKS5 only)"), P_OFFINTNL(hex_net_proxy_auth), 0, 0, 0},
|
||||||
{ST_ENTRY, N_("Username:"), P_OFFSETNL(hex_net_proxy_user), 0, 0, sizeof prefs.hex_net_proxy_user},
|
{ST_ENTRY, N_("Username:"), P_OFFSETNL(hex_net_proxy_user), 0, 0, sizeof prefs.hex_net_proxy_user},
|
||||||
@@ -1364,7 +1372,7 @@ setup_entry_cb (GtkEntry *entry, setting *set)
|
|||||||
int size;
|
int size;
|
||||||
int pos;
|
int pos;
|
||||||
unsigned char *p = (unsigned char*)gtk_entry_get_text (entry);
|
unsigned char *p = (unsigned char*)gtk_entry_get_text (entry);
|
||||||
int len = strlen (p);
|
size_t len = strlen ((const char *) p);
|
||||||
|
|
||||||
/* need to truncate? */
|
/* need to truncate? */
|
||||||
if (len >= set->extra)
|
if (len >= set->extra)
|
||||||
@@ -2180,7 +2188,7 @@ unslash (char *dir)
|
|||||||
{
|
{
|
||||||
if (dir[0])
|
if (dir[0])
|
||||||
{
|
{
|
||||||
int len = strlen (dir) - 1;
|
size_t len = strlen (dir) - 1;
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
if (dir[len] == '/' || dir[len] == '\\')
|
if (dir[len] == '/' || dir[len] == '\\')
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -107,12 +107,23 @@ theme_manager_reset_mode_colors (unsigned int mode, gboolean *palette_changed)
|
|||||||
*palette_changed = FALSE;
|
*palette_changed = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
theme_runtime_clear_gtk_mapped_custom_tokens (void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
theme_manager_save_preferences (void)
|
theme_manager_save_preferences (void)
|
||||||
{
|
{
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
theme_manager_apply_to_window (GtkWidget *window)
|
||||||
|
{
|
||||||
|
(void)window;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
theme_manager_dispatch_changed (ThemeChangedReason reasons)
|
theme_manager_dispatch_changed (ThemeChangedReason reasons)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -88,9 +88,15 @@ theme_application_apply_toplevel_theme (gboolean dark)
|
|||||||
gboolean
|
gboolean
|
||||||
theme_application_apply_mode (unsigned int mode, gboolean *palette_changed)
|
theme_application_apply_mode (unsigned int mode, gboolean *palette_changed)
|
||||||
{
|
{
|
||||||
|
static gboolean runtime_loaded = FALSE;
|
||||||
gboolean dark;
|
gboolean dark;
|
||||||
|
|
||||||
|
if (!runtime_loaded)
|
||||||
|
{
|
||||||
theme_runtime_load ();
|
theme_runtime_load ();
|
||||||
|
runtime_loaded = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
dark = theme_runtime_apply_mode (mode, palette_changed);
|
dark = theme_runtime_apply_mode (mode, palette_changed);
|
||||||
theme_application_apply_toplevel_theme (dark);
|
theme_application_apply_toplevel_theme (dark);
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include "theme-gtk3.h"
|
#include "theme-gtk3.h"
|
||||||
#include "theme-manager.h"
|
#include "theme-manager.h"
|
||||||
#include "theme-preferences.h"
|
#include "theme-preferences.h"
|
||||||
|
#include "theme-runtime.h"
|
||||||
|
|
||||||
extern void load_text_events (void);
|
extern void load_text_events (void);
|
||||||
|
|
||||||
@@ -1417,11 +1418,50 @@ 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 void
|
||||||
|
theme_preferences_gtk3_sync_runtime_palette (theme_preferences_ui *ui)
|
||||||
|
{
|
||||||
|
ThemeWidgetStyleValues style_values;
|
||||||
|
GtkWidget *style_source = NULL;
|
||||||
|
|
||||||
|
if (ui && ui->parent)
|
||||||
|
style_source = GTK_WIDGET (ui->parent);
|
||||||
|
else if (ui && ui->gtk3_combo)
|
||||||
|
style_source = ui->gtk3_combo;
|
||||||
|
|
||||||
|
theme_runtime_clear_gtk_mapped_custom_tokens ();
|
||||||
|
|
||||||
|
theme_get_widget_style_values_for_widget (style_source, &style_values);
|
||||||
|
|
||||||
|
theme_preferences_staged_set_color (THEME_TOKEN_TEXT_FOREGROUND,
|
||||||
|
&style_values.foreground,
|
||||||
|
NULL,
|
||||||
|
TRUE);
|
||||||
|
theme_preferences_staged_set_color (THEME_TOKEN_TEXT_BACKGROUND,
|
||||||
|
&style_values.background,
|
||||||
|
NULL,
|
||||||
|
TRUE);
|
||||||
|
theme_preferences_staged_set_color (THEME_TOKEN_SELECTION_FOREGROUND,
|
||||||
|
&style_values.selection_foreground,
|
||||||
|
NULL,
|
||||||
|
TRUE);
|
||||||
|
theme_preferences_staged_set_color (THEME_TOKEN_SELECTION_BACKGROUND,
|
||||||
|
&style_values.selection_background,
|
||||||
|
NULL,
|
||||||
|
TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
theme_preferences_gtk3_apply_and_refresh (GError **error)
|
theme_preferences_gtk3_apply_and_refresh (theme_preferences_ui *ui, GError **error)
|
||||||
{
|
{
|
||||||
if (!theme_gtk3_apply_current (error))
|
if (!theme_gtk3_apply_current (error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
if (ui && ui->parent)
|
||||||
|
theme_manager_apply_to_window (GTK_WIDGET (ui->parent));
|
||||||
|
|
||||||
|
theme_preferences_gtk3_sync_runtime_palette (ui);
|
||||||
|
|
||||||
theme_manager_dispatch_changed (THEME_CHANGED_REASON_THEME_PACK |
|
theme_manager_dispatch_changed (THEME_CHANGED_REASON_THEME_PACK |
|
||||||
THEME_CHANGED_REASON_PALETTE |
|
THEME_CHANGED_REASON_PALETTE |
|
||||||
THEME_CHANGED_REASON_WIDGET_STYLE |
|
THEME_CHANGED_REASON_WIDGET_STYLE |
|
||||||
@@ -1463,7 +1503,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_preferences_gtk3_apply_and_refresh (&error))
|
if (selection_changed && !theme_preferences_gtk3_apply_and_refresh (ui, &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."));
|
||||||
@@ -1552,7 +1592,7 @@ theme_preferences_populate_gtk3 (theme_preferences_ui *ui)
|
|||||||
g_free (final_id);
|
g_free (final_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (should_apply && !theme_preferences_gtk3_apply_and_refresh (&error))
|
if (should_apply && !theme_preferences_gtk3_apply_and_refresh (ui, &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."));
|
||||||
|
|||||||
@@ -410,6 +410,20 @@ theme_runtime_reset_mode_colors (gboolean dark_mode)
|
|||||||
dark_mode_active = FALSE;
|
dark_mode_active = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
theme_runtime_clear_gtk_mapped_custom_tokens (void)
|
||||||
|
{
|
||||||
|
light_custom_tokens[THEME_TOKEN_TEXT_FOREGROUND] = FALSE;
|
||||||
|
light_custom_tokens[THEME_TOKEN_TEXT_BACKGROUND] = FALSE;
|
||||||
|
light_custom_tokens[THEME_TOKEN_SELECTION_FOREGROUND] = FALSE;
|
||||||
|
light_custom_tokens[THEME_TOKEN_SELECTION_BACKGROUND] = FALSE;
|
||||||
|
|
||||||
|
dark_custom_tokens[THEME_TOKEN_TEXT_FOREGROUND] = FALSE;
|
||||||
|
dark_custom_tokens[THEME_TOKEN_TEXT_BACKGROUND] = FALSE;
|
||||||
|
dark_custom_tokens[THEME_TOKEN_SELECTION_FOREGROUND] = FALSE;
|
||||||
|
dark_custom_tokens[THEME_TOKEN_SELECTION_BACKGROUND] = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
theme_runtime_load (void)
|
theme_runtime_load (void)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ gboolean theme_runtime_apply_dark_mode (gboolean enable);
|
|||||||
void theme_runtime_user_set_color (ThemeSemanticToken token, const GdkRGBA *col);
|
void theme_runtime_user_set_color (ThemeSemanticToken token, const GdkRGBA *col);
|
||||||
void theme_runtime_dark_set_color (ThemeSemanticToken token, const GdkRGBA *col);
|
void theme_runtime_dark_set_color (ThemeSemanticToken token, const GdkRGBA *col);
|
||||||
void theme_runtime_reset_mode_colors (gboolean dark_mode);
|
void theme_runtime_reset_mode_colors (gboolean dark_mode);
|
||||||
|
void theme_runtime_clear_gtk_mapped_custom_tokens (void);
|
||||||
gboolean theme_runtime_get_color (ThemeSemanticToken token, GdkRGBA *out_rgba);
|
gboolean theme_runtime_get_color (ThemeSemanticToken token, GdkRGBA *out_rgba);
|
||||||
gboolean theme_runtime_mode_has_user_colors (gboolean dark_mode);
|
gboolean theme_runtime_mode_has_user_colors (gboolean dark_mode);
|
||||||
void theme_runtime_get_widget_style_values (ThemeWidgetStyleValues *out_values);
|
void theme_runtime_get_widget_style_values (ThemeWidgetStyleValues *out_values);
|
||||||
|
|||||||
@@ -93,23 +93,14 @@ userlist_apply_saved_column_width (GtkTreeViewColumn *column, int width)
|
|||||||
static void
|
static void
|
||||||
userlist_update_min_width (session *sess)
|
userlist_update_min_width (session *sess)
|
||||||
{
|
{
|
||||||
GtkRequisition minimum;
|
|
||||||
GtkRequisition natural;
|
|
||||||
GtkWidget *scrolled_window;
|
GtkWidget *scrolled_window;
|
||||||
int width;
|
|
||||||
|
|
||||||
if (!sess || !sess->gui || !sess->gui->user_box || !sess->gui->namelistinfo || !sess->gui->user_tree)
|
if (!sess || !sess->gui || !sess->gui->user_tree)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gtk_widget_get_preferred_size (sess->gui->namelistinfo, &minimum, &natural);
|
|
||||||
width = MAX (minimum.width, natural.width);
|
|
||||||
if (width < 1)
|
|
||||||
width = 1;
|
|
||||||
|
|
||||||
scrolled_window = gtk_widget_get_parent (sess->gui->user_tree);
|
scrolled_window = gtk_widget_get_parent (sess->gui->user_tree);
|
||||||
if (GTK_IS_SCROLLED_WINDOW (scrolled_window))
|
if (GTK_IS_SCROLLED_WINDOW (scrolled_window))
|
||||||
gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (scrolled_window), width);
|
gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (scrolled_window), 1);
|
||||||
gtk_widget_set_size_request (sess->gui->user_box, width, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GdkPixbuf *
|
GdkPixbuf *
|
||||||
@@ -909,17 +900,19 @@ userlist_create (GtkWidget *box)
|
|||||||
};
|
};
|
||||||
|
|
||||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||||
|
gtk_widget_set_hexpand (sw, TRUE);
|
||||||
|
gtk_widget_set_vexpand (sw, TRUE);
|
||||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
|
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
|
||||||
GTK_SHADOW_ETCHED_IN);
|
GTK_SHADOW_IN);
|
||||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||||
prefs.hex_gui_ulist_show_hosts ?
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||||
GTK_POLICY_AUTOMATIC :
|
gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (sw), 1);
|
||||||
GTK_POLICY_NEVER,
|
|
||||||
GTK_POLICY_AUTOMATIC);
|
|
||||||
gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
|
gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
|
||||||
gtk_widget_show (sw);
|
gtk_widget_show (sw);
|
||||||
|
|
||||||
treeview = gtk_tree_view_new ();
|
treeview = gtk_tree_view_new ();
|
||||||
|
gtk_widget_set_hexpand (treeview, TRUE);
|
||||||
|
gtk_widget_set_vexpand (treeview, TRUE);
|
||||||
gtk_widget_set_name (treeview, "zoitechat-userlist");
|
gtk_widget_set_name (treeview, "zoitechat-userlist");
|
||||||
gtk_widget_set_can_focus (treeview, TRUE);
|
gtk_widget_set_can_focus (treeview, TRUE);
|
||||||
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
|
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
|
||||||
|
|||||||
@@ -110,6 +110,15 @@ enum
|
|||||||
TARGET_COMPOUND_TEXT
|
TARGET_COMPOUND_TEXT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_HADJUSTMENT,
|
||||||
|
PROP_VADJUSTMENT,
|
||||||
|
PROP_HSCROLL_POLICY,
|
||||||
|
PROP_VSCROLL_POLICY
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Selection targets for PRIMARY selection / copy-paste.
|
/* Selection targets for PRIMARY selection / copy-paste.
|
||||||
*
|
*
|
||||||
@@ -158,7 +167,8 @@ gtk_xtext_install_selection_targets (GtkWidget *widget)
|
|||||||
|
|
||||||
static guint xtext_signals[LAST_SIGNAL];
|
static guint xtext_signals[LAST_SIGNAL];
|
||||||
|
|
||||||
G_DEFINE_TYPE (GtkXText, gtk_xtext, GTK_TYPE_WIDGET)
|
G_DEFINE_TYPE_WITH_CODE (GtkXText, gtk_xtext, GTK_TYPE_WIDGET,
|
||||||
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
|
||||||
|
|
||||||
char *nocasestrstr (const char *text, const char *tofind); /* util.c */
|
char *nocasestrstr (const char *text, const char *tofind); /* util.c */
|
||||||
int xtext_get_stamp_str (time_t, char **);
|
int xtext_get_stamp_str (time_t, char **);
|
||||||
@@ -171,6 +181,10 @@ static void gtk_xtext_adjustment_changed (GtkAdjustment * adj,
|
|||||||
GtkXText * xtext);
|
GtkXText * xtext);
|
||||||
static void gtk_xtext_scroll_adjustments (GtkXText *xtext, GtkAdjustment *hadj,
|
static void gtk_xtext_scroll_adjustments (GtkXText *xtext, GtkAdjustment *hadj,
|
||||||
GtkAdjustment *vadj);
|
GtkAdjustment *vadj);
|
||||||
|
static void gtk_xtext_set_property (GObject *object, guint prop_id,
|
||||||
|
const GValue *value, GParamSpec *pspec);
|
||||||
|
static void gtk_xtext_get_property (GObject *object, guint prop_id,
|
||||||
|
GValue *value, GParamSpec *pspec);
|
||||||
static int gtk_xtext_render_ents (GtkXText * xtext, textentry *, textentry *);
|
static int gtk_xtext_render_ents (GtkXText * xtext, textentry *, textentry *);
|
||||||
static void gtk_xtext_recalc_widths (xtext_buffer *buf, int);
|
static void gtk_xtext_recalc_widths (xtext_buffer *buf, int);
|
||||||
static void gtk_xtext_fix_indent (xtext_buffer *buf);
|
static void gtk_xtext_fix_indent (xtext_buffer *buf);
|
||||||
@@ -794,6 +808,9 @@ gtk_xtext_init (GtkXText * xtext)
|
|||||||
xtext->recycle = FALSE;
|
xtext->recycle = FALSE;
|
||||||
xtext->dont_render = FALSE;
|
xtext->dont_render = FALSE;
|
||||||
xtext->dont_render2 = FALSE;
|
xtext->dont_render2 = FALSE;
|
||||||
|
xtext->hadj = NULL;
|
||||||
|
xtext->hscroll_policy = GTK_SCROLL_MINIMUM;
|
||||||
|
xtext->vscroll_policy = GTK_SCROLL_MINIMUM;
|
||||||
gtk_xtext_scroll_adjustments (xtext, NULL, NULL);
|
gtk_xtext_scroll_adjustments (xtext, NULL, NULL);
|
||||||
|
|
||||||
gtk_xtext_install_selection_targets (GTK_WIDGET (xtext));
|
gtk_xtext_install_selection_targets (GTK_WIDGET (xtext));
|
||||||
@@ -886,6 +903,66 @@ gtk_xtext_adjustment_changed (GtkAdjustment * adj, GtkXText * xtext)
|
|||||||
xtext->buffer->old_value = xtext_adj_get_value (adj);
|
xtext->buffer->old_value = xtext_adj_get_value (adj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_xtext_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GtkXText *xtext = GTK_XTEXT (object);
|
||||||
|
GtkAdjustment *adj;
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_HADJUSTMENT:
|
||||||
|
adj = g_value_get_object (value);
|
||||||
|
if (xtext->hadj == adj)
|
||||||
|
break;
|
||||||
|
if (xtext->hadj)
|
||||||
|
g_object_unref (xtext->hadj);
|
||||||
|
xtext->hadj = adj ? g_object_ref (adj) : NULL;
|
||||||
|
g_object_notify (object, "hadjustment");
|
||||||
|
break;
|
||||||
|
case PROP_VADJUSTMENT:
|
||||||
|
gtk_xtext_scroll_adjustments (xtext, NULL, g_value_get_object (value));
|
||||||
|
g_object_notify (object, "vadjustment");
|
||||||
|
break;
|
||||||
|
case PROP_HSCROLL_POLICY:
|
||||||
|
xtext->hscroll_policy = g_value_get_enum (value);
|
||||||
|
g_object_notify (object, "hscroll-policy");
|
||||||
|
break;
|
||||||
|
case PROP_VSCROLL_POLICY:
|
||||||
|
xtext->vscroll_policy = g_value_get_enum (value);
|
||||||
|
g_object_notify (object, "vscroll-policy");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_xtext_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GtkXText *xtext = GTK_XTEXT (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_HADJUSTMENT:
|
||||||
|
g_value_set_object (value, xtext->hadj);
|
||||||
|
break;
|
||||||
|
case PROP_VADJUSTMENT:
|
||||||
|
g_value_set_object (value, xtext->adj);
|
||||||
|
break;
|
||||||
|
case PROP_HSCROLL_POLICY:
|
||||||
|
g_value_set_enum (value, xtext->hscroll_policy);
|
||||||
|
break;
|
||||||
|
case PROP_VSCROLL_POLICY:
|
||||||
|
g_value_set_enum (value, xtext->vscroll_policy);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GtkWidget *
|
GtkWidget *
|
||||||
gtk_xtext_new (const XTextColor *palette, int separator)
|
gtk_xtext_new (const XTextColor *palette, int separator)
|
||||||
{
|
{
|
||||||
@@ -952,6 +1029,11 @@ gtk_xtext_cleanup (GtkXText *xtext)
|
|||||||
xtext->adj = NULL;
|
xtext->adj = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xtext->hadj)
|
||||||
|
{
|
||||||
|
g_object_unref (G_OBJECT (xtext->hadj));
|
||||||
|
xtext->hadj = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (xtext->hand_cursor)
|
if (xtext->hand_cursor)
|
||||||
{
|
{
|
||||||
@@ -2218,6 +2300,12 @@ gtk_xtext_leave_notify (GtkWidget * widget, GdkEventCrossing * event)
|
|||||||
xtext->hilight_ent = NULL;
|
xtext->hilight_ent = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xtext->tooltip_stamp_set)
|
||||||
|
{
|
||||||
|
gtk_widget_set_tooltip_text (widget, NULL);
|
||||||
|
xtext->tooltip_stamp_set = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2384,7 +2472,7 @@ gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xtext->urlcheck_function == NULL)
|
if (xtext->urlcheck_function == NULL)
|
||||||
return FALSE;
|
goto tooltip_check;
|
||||||
|
|
||||||
word_type = gtk_xtext_get_word_adjust (xtext, x, y, &word_ent, &offset, &len);
|
word_type = gtk_xtext_get_word_adjust (xtext, x, y, &word_ent, &offset, &len);
|
||||||
if (word_type > 0)
|
if (word_type > 0)
|
||||||
@@ -2422,6 +2510,46 @@ gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tooltip_check:
|
||||||
|
if (xtext->buffer->time_stamp && xtext->buffer->indent > 0 && x >= 0 && x < xtext->stamp_width)
|
||||||
|
{
|
||||||
|
textentry *ent = gtk_xtext_find_char (xtext, x, y, NULL, NULL);
|
||||||
|
if (ent && (!xtext->tooltip_stamp_set || xtext->tooltip_stamp != ent->stamp))
|
||||||
|
{
|
||||||
|
char tooltip[96];
|
||||||
|
strftime_utf8 (tooltip, sizeof (tooltip), "%Y-%m-%d", ent->stamp);
|
||||||
|
gtk_widget_set_tooltip_text (widget, tooltip);
|
||||||
|
xtext->tooltip_stamp = ent->stamp;
|
||||||
|
xtext->tooltip_stamp_set = TRUE;
|
||||||
|
}
|
||||||
|
if (ent)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if (!xtext->buffer->time_stamp && x >= xtext->buffer->indent)
|
||||||
|
{
|
||||||
|
textentry *ent = gtk_xtext_find_char (xtext, x, y, NULL, NULL);
|
||||||
|
if (ent && ent->stamp && (!xtext->tooltip_stamp_set || xtext->tooltip_stamp != ent->stamp))
|
||||||
|
{
|
||||||
|
char tooltip[128];
|
||||||
|
char date[64];
|
||||||
|
char *stamp_text;
|
||||||
|
strftime_utf8 (date, sizeof (date), "%Y-%m-%d", ent->stamp);
|
||||||
|
xtext_get_stamp_str (ent->stamp, &stamp_text);
|
||||||
|
g_snprintf (tooltip, sizeof (tooltip), "%s %s", date, stamp_text);
|
||||||
|
gtk_widget_set_tooltip_text (widget, tooltip);
|
||||||
|
g_free (stamp_text);
|
||||||
|
xtext->tooltip_stamp = ent->stamp;
|
||||||
|
xtext->tooltip_stamp_set = TRUE;
|
||||||
|
}
|
||||||
|
if (ent)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if (xtext->tooltip_stamp_set)
|
||||||
|
{
|
||||||
|
gtk_widget_set_tooltip_text (widget, NULL);
|
||||||
|
xtext->tooltip_stamp_set = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
gtk_xtext_leave_notify (widget, NULL);
|
gtk_xtext_leave_notify (widget, NULL);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -2856,19 +2984,41 @@ gtk_xtext_scroll (GtkWidget *widget, GdkEventScroll *event)
|
|||||||
{
|
{
|
||||||
GtkXText *xtext = GTK_XTEXT (widget);
|
GtkXText *xtext = GTK_XTEXT (widget);
|
||||||
gfloat new_value;
|
gfloat new_value;
|
||||||
|
gfloat step;
|
||||||
|
gdouble dx;
|
||||||
|
gdouble dy;
|
||||||
|
int direction = 0;
|
||||||
|
int speed = prefs.hex_gui_mouse_scroll_speed;
|
||||||
|
|
||||||
if (event->direction == GDK_SCROLL_UP) /* mouse wheel pageUp */
|
if (speed < 1)
|
||||||
|
speed = 1;
|
||||||
|
step = (xtext_adj_get_page_increment (xtext->adj) * speed) / 100.0f;
|
||||||
|
|
||||||
|
if (event->direction == GDK_SCROLL_SMOOTH &&
|
||||||
|
gdk_event_get_scroll_deltas ((GdkEvent *)event, &dx, &dy))
|
||||||
|
{
|
||||||
|
if (dy > 0)
|
||||||
|
direction = 1;
|
||||||
|
else if (dy < 0)
|
||||||
|
direction = -1;
|
||||||
|
}
|
||||||
|
else if (event->direction == GDK_SCROLL_UP)
|
||||||
|
direction = -1;
|
||||||
|
else if (event->direction == GDK_SCROLL_DOWN)
|
||||||
|
direction = 1;
|
||||||
|
|
||||||
|
if (direction < 0)
|
||||||
{
|
{
|
||||||
new_value = xtext_adj_get_value (xtext->adj) -
|
new_value = xtext_adj_get_value (xtext->adj) -
|
||||||
(xtext_adj_get_page_increment (xtext->adj) / 10);
|
step;
|
||||||
if (new_value < xtext_adj_get_lower (xtext->adj))
|
if (new_value < xtext_adj_get_lower (xtext->adj))
|
||||||
new_value = xtext_adj_get_lower (xtext->adj);
|
new_value = xtext_adj_get_lower (xtext->adj);
|
||||||
xtext_adj_set_value (xtext->adj, new_value);
|
xtext_adj_set_value (xtext->adj, new_value);
|
||||||
}
|
}
|
||||||
else if (event->direction == GDK_SCROLL_DOWN) /* mouse wheel pageDn */
|
else if (direction > 0)
|
||||||
{
|
{
|
||||||
new_value = xtext_adj_get_value (xtext->adj) +
|
new_value = xtext_adj_get_value (xtext->adj) +
|
||||||
(xtext_adj_get_page_increment (xtext->adj) / 10);
|
step;
|
||||||
if (new_value > (xtext_adj_get_upper (xtext->adj) -
|
if (new_value > (xtext_adj_get_upper (xtext->adj) -
|
||||||
xtext_adj_get_page_size (xtext->adj)))
|
xtext_adj_get_page_size (xtext->adj)))
|
||||||
new_value = xtext_adj_get_upper (xtext->adj) -
|
new_value = xtext_adj_get_upper (xtext->adj) -
|
||||||
@@ -2876,7 +3026,7 @@ gtk_xtext_scroll (GtkWidget *widget, GdkEventScroll *event)
|
|||||||
xtext_adj_set_value (xtext->adj, new_value);
|
xtext_adj_set_value (xtext->adj, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return direction != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -2924,6 +3074,13 @@ gtk_xtext_class_init (GtkXTextClass * class)
|
|||||||
widget_class = (GtkWidgetClass *) class;
|
widget_class = (GtkWidgetClass *) class;
|
||||||
xtext_class = (GtkXTextClass *) class;
|
xtext_class = (GtkXTextClass *) class;
|
||||||
|
|
||||||
|
object_class->set_property = gtk_xtext_set_property;
|
||||||
|
object_class->get_property = gtk_xtext_get_property;
|
||||||
|
g_object_class_override_property (object_class, PROP_HADJUSTMENT, "hadjustment");
|
||||||
|
g_object_class_override_property (object_class, PROP_VADJUSTMENT, "vadjustment");
|
||||||
|
g_object_class_override_property (object_class, PROP_HSCROLL_POLICY, "hscroll-policy");
|
||||||
|
g_object_class_override_property (object_class, PROP_VSCROLL_POLICY, "vscroll-policy");
|
||||||
|
|
||||||
xtext_signals[WORD_CLICK] =
|
xtext_signals[WORD_CLICK] =
|
||||||
g_signal_new ("word_click",
|
g_signal_new ("word_click",
|
||||||
G_TYPE_FROM_CLASS (object_class),
|
G_TYPE_FROM_CLASS (object_class),
|
||||||
@@ -4830,13 +4987,12 @@ gtk_xtext_check_marker_visibility (GtkXText * xtext)
|
|||||||
static void
|
static void
|
||||||
gtk_xtext_unstrip_color (gint start, gint end, GSList *slp, GList **gl, gint maxo)
|
gtk_xtext_unstrip_color (gint start, gint end, GSList *slp, GList **gl, gint maxo)
|
||||||
{
|
{
|
||||||
gint off1, off2, curlen;
|
gint off1, off2;
|
||||||
GSList *cursl;
|
GSList *cursl;
|
||||||
offsets_t marks;
|
offsets_t marks;
|
||||||
offlen_t *meta;
|
offlen_t *meta;
|
||||||
|
|
||||||
off1 = 0;
|
off1 = 0;
|
||||||
curlen = 0;
|
|
||||||
cursl = slp;
|
cursl = slp;
|
||||||
while (cursl)
|
while (cursl)
|
||||||
{
|
{
|
||||||
@@ -4846,7 +5002,6 @@ gtk_xtext_unstrip_color (gint start, gint end, GSList *slp, GList **gl, gint max
|
|||||||
off1 = meta->off + start;
|
off1 = meta->off + start;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
curlen += meta->len;
|
|
||||||
start -= meta->len;
|
start -= meta->len;
|
||||||
end -= meta->len;
|
end -= meta->len;
|
||||||
cursl = g_slist_next (cursl);
|
cursl = g_slist_next (cursl);
|
||||||
@@ -4861,7 +5016,6 @@ gtk_xtext_unstrip_color (gint start, gint end, GSList *slp, GList **gl, gint max
|
|||||||
off2 = meta->off + end;
|
off2 = meta->off + end;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
curlen += meta->len;
|
|
||||||
end -= meta->len;
|
end -= meta->len;
|
||||||
cursl = g_slist_next (cursl);
|
cursl = g_slist_next (cursl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,6 +134,9 @@ struct _GtkXText
|
|||||||
xtext_buffer *selection_buffer;
|
xtext_buffer *selection_buffer;
|
||||||
|
|
||||||
GtkAdjustment *adj;
|
GtkAdjustment *adj;
|
||||||
|
GtkAdjustment *hadj;
|
||||||
|
GtkScrollablePolicy hscroll_policy;
|
||||||
|
GtkScrollablePolicy vscroll_policy;
|
||||||
cairo_surface_t *background_surface; /* 0 = use palette[19] */
|
cairo_surface_t *background_surface; /* 0 = use palette[19] */
|
||||||
cairo_surface_t *background_clip_surface;
|
cairo_surface_t *background_clip_surface;
|
||||||
GdkWindow *draw_window; /* points to ->window */
|
GdkWindow *draw_window; /* points to ->window */
|
||||||
@@ -187,6 +190,8 @@ struct _GtkXText
|
|||||||
textentry *hilight_ent;
|
textentry *hilight_ent;
|
||||||
int hilight_start;
|
int hilight_start;
|
||||||
int hilight_end;
|
int hilight_end;
|
||||||
|
time_t tooltip_stamp;
|
||||||
|
unsigned int tooltip_stamp_set:1;
|
||||||
|
|
||||||
guint16 fontwidth[128]; /* each char's width, only the ASCII ones */
|
guint16 fontwidth[128]; /* each char's width, only the ASCII ones */
|
||||||
|
|
||||||
|
|||||||
@@ -313,7 +313,8 @@ fe_print_text (struct session *sess, char *text, time_t stamp,
|
|||||||
gboolean no_activity)
|
gboolean no_activity)
|
||||||
{
|
{
|
||||||
int dotime = FALSE;
|
int dotime = FALSE;
|
||||||
int comma, k, i = 0, j = 0, len = strlen (text);
|
int comma, k, i = 0, j = 0;
|
||||||
|
size_t len = strlen (text);
|
||||||
|
|
||||||
unsigned char *newtext = g_malloc (len + 1024);
|
unsigned char *newtext = g_malloc (len + 1024);
|
||||||
|
|
||||||
|
|||||||
@@ -26,12 +26,19 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
#include "typedef.h" // for ssize_t
|
#include "typedef.h" // for ssize_t
|
||||||
#include <enchant-provider.h>
|
#include <enchant-provider.h>
|
||||||
|
|
||||||
ENCHANT_PLUGIN_DECLARE ("win8")
|
ENCHANT_PLUGIN_DECLARE ("win8")
|
||||||
|
|
||||||
|
static int
|
||||||
|
size_to_int (size_t value)
|
||||||
|
{
|
||||||
|
return value > static_cast<size_t>(INT_MAX) ? INT_MAX : static_cast<int>(value);
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
utf16_to_utf8 (const wchar_t * const str, bool from_bcp47)
|
utf16_to_utf8 (const wchar_t * const str, bool from_bcp47)
|
||||||
{
|
{
|
||||||
@@ -136,7 +143,7 @@ static void
|
|||||||
win8_dict_add_to_personal (EnchantDict *dict, const char *const word, size_t len)
|
win8_dict_add_to_personal (EnchantDict *dict, const char *const word, size_t len)
|
||||||
{
|
{
|
||||||
auto checker = static_cast<ISpellChecker*>(dict->user_data);
|
auto checker = static_cast<ISpellChecker*>(dict->user_data);
|
||||||
wchar_t *wword = utf8_to_utf16 (word, static_cast<int>(len), false);
|
wchar_t *wword = utf8_to_utf16 (word, size_to_int (len), false);
|
||||||
|
|
||||||
checker->Add (wword);
|
checker->Add (wword);
|
||||||
std::free (wword);
|
std::free (wword);
|
||||||
@@ -146,7 +153,7 @@ static void
|
|||||||
win8_dict_add_to_session (EnchantDict *dict, const char *const word, size_t len)
|
win8_dict_add_to_session (EnchantDict *dict, const char *const word, size_t len)
|
||||||
{
|
{
|
||||||
auto checker = static_cast<ISpellChecker*>(dict->user_data);
|
auto checker = static_cast<ISpellChecker*>(dict->user_data);
|
||||||
wchar_t *wword = utf8_to_utf16 (word, static_cast<int>(len), false);
|
wchar_t *wword = utf8_to_utf16 (word, size_to_int (len), false);
|
||||||
|
|
||||||
checker->Ignore (wword);
|
checker->Ignore (wword);
|
||||||
std::free (wword);
|
std::free (wword);
|
||||||
@@ -156,7 +163,7 @@ static int
|
|||||||
win8_dict_check (EnchantDict *dict, const char *const word, size_t len)
|
win8_dict_check (EnchantDict *dict, const char *const word, size_t len)
|
||||||
{
|
{
|
||||||
auto checker = static_cast<ISpellChecker*>(dict->user_data);
|
auto checker = static_cast<ISpellChecker*>(dict->user_data);
|
||||||
wchar_t *wword = utf8_to_utf16 (word, static_cast<int>(len), false);
|
wchar_t *wword = utf8_to_utf16 (word, size_to_int (len), false);
|
||||||
IEnumSpellingError *errors;
|
IEnumSpellingError *errors;
|
||||||
ISpellingError *error = nullptr;
|
ISpellingError *error = nullptr;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
@@ -184,7 +191,7 @@ static char **
|
|||||||
win8_dict_suggest (EnchantDict *dict, const char *const word, size_t len, size_t *out_n_suggs)
|
win8_dict_suggest (EnchantDict *dict, const char *const word, size_t len, size_t *out_n_suggs)
|
||||||
{
|
{
|
||||||
auto checker = static_cast<ISpellChecker*>(dict->user_data);
|
auto checker = static_cast<ISpellChecker*>(dict->user_data);
|
||||||
wchar_t *wword = utf8_to_utf16 (word, static_cast<int>(len), false);
|
wchar_t *wword = utf8_to_utf16 (word, size_to_int (len), false);
|
||||||
IEnumString *suggestions;
|
IEnumString *suggestions;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ PrivilegesRequired=none
|
|||||||
ShowComponentSizes=no
|
ShowComponentSizes=no
|
||||||
CreateUninstallRegKey=not IsTaskSelected('portable')
|
CreateUninstallRegKey=not IsTaskSelected('portable')
|
||||||
Uninstallable=not IsTaskSelected('portable')
|
Uninstallable=not IsTaskSelected('portable')
|
||||||
ArchitecturesAllowed=x64
|
ArchitecturesAllowed=x64compatible
|
||||||
ArchitecturesInstallIn64BitMode=x64
|
ArchitecturesInstallIn64BitMode=x64compatible
|
||||||
MinVersion=6.1
|
MinVersion=6.1
|
||||||
WizardImageFile={#PROJECTDIR}wizardimage.bmp
|
WizardImageFile={#PROJECTDIR}wizardimage.bmp
|
||||||
WizardSmallImageFile={#PROJECTDIR}wizardsmallimage.bmp
|
WizardSmallImageFile={#PROJECTDIR}wizardsmallimage.bmp
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.18.0
|
2.18.1
|
||||||
|
|||||||
@@ -128,7 +128,7 @@
|
|||||||
|
|
||||||
<ArchiveDefs Condition="'$(ArchiveLib)'=='archive_static.lib' or '$(ArchiveLib)'=='libarchive_static.lib'">LIBARCHIVE_STATIC</ArchiveDefs>
|
<ArchiveDefs Condition="'$(ArchiveLib)'=='archive_static.lib' or '$(ArchiveLib)'=='libarchive_static.lib'">LIBARCHIVE_STATIC</ArchiveDefs>
|
||||||
|
|
||||||
<DepLibs>$(Gtk3Lib);$(Gdk3Lib);wininet.lib;winmm.lib;ws2_32.lib;atk-1.0.lib;gio-2.0.lib;gdk_pixbuf-2.0.lib;pangowin32-1.0.lib;pangocairo-1.0.lib;pango-1.0.lib;cairo.lib;gobject-2.0.lib;gmodule-2.0.lib;glib-2.0.lib;$(IntlLib);$(IconvLib);$(ZlibLib);$(Xml2Lib);$(JpegLib);$(PngLib);$(ArchiveLib);$(OpenSslLibs)</DepLibs>
|
<DepLibs>$(Gtk3Lib);$(Gdk3Lib);wininet.lib;winmm.lib;ws2_32.lib;advapi32.lib;atk-1.0.lib;gio-2.0.lib;gdk_pixbuf-2.0.lib;pangowin32-1.0.lib;pangocairo-1.0.lib;pango-1.0.lib;cairo.lib;gobject-2.0.lib;gmodule-2.0.lib;glib-2.0.lib;$(IntlLib);$(IconvLib);$(ZlibLib);$(Xml2Lib);$(JpegLib);$(PngLib);$(ArchiveLib);$(OpenSslLibs)</DepLibs>
|
||||||
|
|
||||||
<DataDir>$(SolutionDir)..\data\\</DataDir>
|
<DataDir>$(SolutionDir)..\data\\</DataDir>
|
||||||
<ZoiteChatBuild>$(SolutionDir)..\..\zoitechat-build</ZoiteChatBuild>
|
<ZoiteChatBuild>$(SolutionDir)..\..\zoitechat-build</ZoiteChatBuild>
|
||||||
|
|||||||
Reference in New Issue
Block a user