mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-04-01 10:10:18 +00:00
Compare commits
22 Commits
zoitechat-
...
e90f0188c1
| Author | SHA1 | Date | |
|---|---|---|---|
| e90f0188c1 | |||
| 0ab7eb7207 | |||
| 81dcdbe648 | |||
| f4090cb0e5 | |||
| 0f5dfb147e | |||
| 0bcd369426 | |||
|
|
b316d4a281 | ||
| 86ab0135ce | |||
| 2d42d4e181 | |||
| 23e6313e2f | |||
| b5c5810913 | |||
| b5ebba4521 | |||
| 4fe8e273e4 | |||
| 12d8f5e69c | |||
| 8a1cf3080e | |||
|
|
b9bd0ed61c | ||
| 1f33ed8034 | |||
|
|
38f38cd2c4 | ||
| 71478a0262 | |||
|
|
f76f2cd94c | ||
| 183b134817 | |||
| 6a7d2012a5 |
21
.github/workflows/windows-build.yml
vendored
21
.github/workflows/windows-build.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-python@v6
|
- uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: '3.14.2'
|
python-version: '3.14.3'
|
||||||
architecture: ${{ matrix.arch }}
|
architecture: ${{ matrix.arch }}
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
@@ -62,19 +62,16 @@ jobs:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Download-WithRetry -Url https://files.jrsoftware.org/is/6/innosetup-6.7.0.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.17.0/idpsetup-1.5.1.exe -OutFile deps\idpsetup.exe
|
|
||||||
& deps\idpsetup.exe /VERYSILENT
|
|
||||||
|
|
||||||
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.0-pre1/GTK3_Gvsbuild_zoitechat-2.18.0-pre1_${{ matrix.platform }}.7z -OutFile deps\gtk-${{ matrix.arch }}.7z
|
||||||
& 7z.exe x deps\gtk-${{ matrix.arch }}.7z -oC:\gtk-build\gtk\x64\release
|
& 7z.exe x deps\gtk-${{ matrix.arch }}.7z -oC:\gtk-build\gtk\x64\release
|
||||||
|
|
||||||
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()"
|
||||||
|
|
||||||
Download-WithRetry -Url https://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-libarchive-3.8.1-1-any.pkg.tar.zst -OutFile deps\libarchive.pkg.tar.zst
|
Download-WithRetry -Url https://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-libarchive-3.8.6-1-any.pkg.tar.zst -OutFile deps\libarchive.pkg.tar.zst
|
||||||
python -c "import tarfile,zstandard,pathlib;archive=pathlib.Path(r'deps\\libarchive.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/include/archive','mingw64/lib/libarchive','mingw64/bin/libarchive'))];tf.close();reader.close();f.close()"
|
python -c "import tarfile,zstandard,pathlib;archive=pathlib.Path(r'deps\\libarchive.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/include/archive','mingw64/lib/libarchive','mingw64/bin/libarchive'))];tf.close();reader.close();f.close()"
|
||||||
|
|
||||||
if (Test-Path C:\gtk-build\gtk\x64\release\mingw64\share\icons\hicolor) {
|
if (Test-Path C:\gtk-build\gtk\x64\release\mingw64\share\icons\hicolor) {
|
||||||
@@ -97,19 +94,19 @@ jobs:
|
|||||||
Remove-Item -Path C:\gtk-build\gtk\x64\release\mingw64 -Recurse -Force
|
Remove-Item -Path C:\gtk-build\gtk\x64\release\mingw64 -Recurse -Force
|
||||||
}
|
}
|
||||||
|
|
||||||
Download-WithRetry -Url https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.17.0/gendef-20111031.7z -OutFile deps\gendef.7z
|
Download-WithRetry -Url https://github.com/ZoiteChat/gvsbuild/releases/download/zoitechat-2.18.0-pre4/gendef20260315.7z -OutFile deps\gendef.7z
|
||||||
& 7z.exe x deps\gendef.7z -oC:\gtk-build
|
& 7z.exe x deps\gendef.7z -oC:\gtk-build
|
||||||
|
|
||||||
Download-WithRetry -Url https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.17.0/WinSparkle-20151011.7z -OutFile deps\WinSparkle.7z
|
Download-WithRetry -Url https://github.com/ZoiteChat/gvsbuild/releases/download/zoitechat-2.18.0-pre4/WinSparkle-20260315.7z -OutFile deps\WinSparkle.7z
|
||||||
& 7z.exe x deps\WinSparkle.7z -oC:\gtk-build\WinSparkle
|
& 7z.exe x deps\WinSparkle.7z -oC:\gtk-build\WinSparkle
|
||||||
|
|
||||||
Download-WithRetry -Url https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.17.0/perl-5.20.0-${{ matrix.arch }}.7z -OutFile deps\perl-${{ matrix.arch }}.7z
|
Download-WithRetry -Url https://github.com/ZoiteChat/gvsbuild/releases/download/zoitechat-2.18.0-pre4/perl-5.42.0.1-${{ matrix.arch }}.7z -OutFile deps\perl-${{ matrix.arch }}.7z
|
||||||
& 7z.exe x deps\perl-${{ matrix.arch }}.7z -oC:\gtk-build\perl-5.20\${{ matrix.platform }}
|
& 7z.exe x deps\perl-${{ matrix.arch }}.7z -oC:\gtk-build\perl-5.42.0.1\${{ matrix.platform }}
|
||||||
|
|
||||||
$pyRoot = $env:pythonLocation
|
$pyRoot = $env:pythonLocation
|
||||||
if (-not $pyRoot) { $pyRoot = & python -c "import sys; print(sys.prefix)" }
|
if (-not $pyRoot) { $pyRoot = & python -c "import sys; print(sys.prefix)" }
|
||||||
|
|
||||||
foreach ($pyDir in @("C:\gtk-build\python-3.14.2", "C:\gtk-build\python-3.14")) {
|
foreach ($pyDir in @("C:\gtk-build\python-3.14.3", "C:\gtk-build\python-3.14")) {
|
||||||
New-Item -Path $pyDir -ItemType Directory -Force | Out-Null
|
New-Item -Path $pyDir -ItemType Directory -Force | Out-Null
|
||||||
$target = Join-Path $pyDir "${{ matrix.platform }}"
|
$target = Join-Path $pyDir "${{ matrix.platform }}"
|
||||||
if (Test-Path $target) { Remove-Item $target -Recurse -Force }
|
if (Test-Path $target) { Remove-Item $target -Recurse -Force }
|
||||||
@@ -120,7 +117,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat"
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat"
|
||||||
|
|
||||||
set "PYTHON_DIR=C:\gtk-build\python-3.14.2\${{ matrix.platform }}"
|
set "PYTHON_DIR=C:\gtk-build\python-3.14.3\${{ matrix.platform }}"
|
||||||
if not exist "%PYTHON_DIR%\libs\python314.lib" (
|
if not exist "%PYTHON_DIR%\libs\python314.lib" (
|
||||||
echo Missing %PYTHON_DIR%\libs\python314.lib
|
echo Missing %PYTHON_DIR%\libs\python314.lib
|
||||||
dir "%PYTHON_DIR%\libs"
|
dir "%PYTHON_DIR%\libs"
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
ZoiteChat ChangeLog
|
ZoiteChat ChangeLog
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
2.18.0~pre4 (2026-03-15)
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
- Fixed a regression where Ctrl+A could incorrectly mark you away instead of selecting all text.
|
||||||
|
- Fixed a crash when toggling the GUI with F9 or the menu toggle action.
|
||||||
|
- Fixed sidebar collapse behavior on fresh installs.
|
||||||
|
- Added multiline topic bar support with clickable URLs.
|
||||||
|
- Improved GTK selection styling so text selection is shown visually on topic and chat text box.
|
||||||
|
|
||||||
2.18.0~pre3 (2026-03-13)
|
2.18.0~pre3 (2026-03-13)
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,18 @@
|
|||||||
<id>zoitechat.desktop</id>
|
<id>zoitechat.desktop</id>
|
||||||
</provides>
|
</provides>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release date="2026-03-14" version="2.18.0~pre4">
|
||||||
|
<description>
|
||||||
|
<p>UI fixes, topic bar improvements, and selection styling updates:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Fixed a regression where <code>Ctrl+A</code> could incorrectly mark you away instead of selecting all text.</li>
|
||||||
|
<li>Fixed a crash when toggling the GUI with <code>F9</code> or the menu toggle action.</li>
|
||||||
|
<li>Fixed sidebar collapse behavior on fresh installs.</li>
|
||||||
|
<li>Added multiline topic bar support with clickable URLs.</li>
|
||||||
|
<li>Improved GTK selection styling so text selection is shown visually in the topic bar and chat input box.</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release date="2026-03-13" version="2.18.0~pre3">
|
<release date="2026-03-13" version="2.18.0~pre3">
|
||||||
<description>
|
<description>
|
||||||
<p>GTK3 theming, UI, and platform improvements:</p>
|
<p>GTK3 theming, UI, and platform improvements:</p>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
project('zoitechat', 'c',
|
project('zoitechat', 'c',
|
||||||
version: '2.18.0~pre3',
|
version: '2.18.0~pre4',
|
||||||
meson_version: '>= 0.55.0',
|
meson_version: '>= 0.55.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c17',
|
'c_std=c17',
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ depends=(
|
|||||||
'glib2'
|
'glib2'
|
||||||
'gtk3'
|
'gtk3'
|
||||||
'iso-codes'
|
'iso-codes'
|
||||||
|
'libayatana-appindicator'
|
||||||
'libcanberra'
|
'libcanberra'
|
||||||
'lua'
|
'lua'
|
||||||
'openssl'
|
'openssl'
|
||||||
@@ -26,7 +27,6 @@ makedepends=(
|
|||||||
'python'
|
'python'
|
||||||
)
|
)
|
||||||
optdepends=(
|
optdepends=(
|
||||||
'libayatana-appindicator: Ayatana/AppIndicator tray backend'
|
|
||||||
'pciutils: sysinfo plugin hardware detection details'
|
'pciutils: sysinfo plugin hardware detection details'
|
||||||
)
|
)
|
||||||
provides=('zoitechat')
|
provides=('zoitechat')
|
||||||
|
|||||||
@@ -45,6 +45,22 @@ endif
|
|||||||
perl_ldflags = []
|
perl_ldflags = []
|
||||||
perl_rpath = ''
|
perl_rpath = ''
|
||||||
foreach flag : ret.stdout().strip().split(' ')
|
foreach flag : ret.stdout().strip().split(' ')
|
||||||
|
if flag.startswith('/') and '/libperl.' in flag
|
||||||
|
split = flag.split('/')
|
||||||
|
libperl_dir = ''
|
||||||
|
foreach part : split
|
||||||
|
if part != '' and not part.startswith('libperl.')
|
||||||
|
if libperl_dir == ''
|
||||||
|
libperl_dir = '/' + part
|
||||||
|
else
|
||||||
|
libperl_dir += '/' + part
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
perl_ldflags += '-L' + libperl_dir
|
||||||
|
perl_ldflags += '-lperl'
|
||||||
|
continue
|
||||||
|
endif
|
||||||
if flag.startswith('-L') or flag.startswith('-l')
|
if flag.startswith('-L') or flag.startswith('-l')
|
||||||
perl_ldflags += flag
|
perl_ldflags += flag
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -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~pre3'
|
VERSION = b'2.18.0~pre4'
|
||||||
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)
|
||||||
|
|||||||
@@ -292,7 +292,13 @@ match_host (const char *word, int *start, int *end)
|
|||||||
static gboolean
|
static gboolean
|
||||||
match_host6 (const char *word, int *start, int *end)
|
match_host6 (const char *word, int *start, int *end)
|
||||||
{
|
{
|
||||||
return regex_match (re_host6 (), word, start, end);
|
if (!regex_match (re_host6 (), word, start, end))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (word[*start] != '[')
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -373,40 +379,64 @@ url_last (int *lstart, int *lend)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
regex_match (const GRegex *re, const char *word, int *start, int *end)
|
match_has_valid_context (const char *word, int start, int end)
|
||||||
{
|
{
|
||||||
GMatchInfo *gmi;
|
if (start > 0)
|
||||||
|
|
||||||
g_regex_match (re, word, 0, &gmi);
|
|
||||||
|
|
||||||
if (!g_match_info_matches (gmi))
|
|
||||||
{
|
{
|
||||||
g_match_info_free (gmi);
|
char prev = word[start - 1];
|
||||||
|
if (g_ascii_isalnum ((guchar)prev) || prev == '_' || prev == '-')
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (word[end] != '\0')
|
||||||
|
{
|
||||||
|
char next = word[end];
|
||||||
|
if (g_ascii_isalnum ((guchar)next) || next == '_')
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
regex_match (const GRegex *re, const char *word, int *start, int *end)
|
||||||
|
{
|
||||||
|
GMatchInfo *gmi;
|
||||||
|
gboolean found = FALSE;
|
||||||
|
int mstart;
|
||||||
|
int mend;
|
||||||
|
|
||||||
|
g_regex_match (re, word, 0, &gmi);
|
||||||
|
|
||||||
while (g_match_info_matches (gmi))
|
while (g_match_info_matches (gmi))
|
||||||
{
|
{
|
||||||
g_match_info_fetch_pos (gmi, 0, start, end);
|
g_match_info_fetch_pos (gmi, 0, &mstart, &mend);
|
||||||
|
if (match_has_valid_context (word, mstart, mend))
|
||||||
|
{
|
||||||
|
*start = mstart;
|
||||||
|
*end = mend;
|
||||||
|
found = TRUE;
|
||||||
|
}
|
||||||
g_match_info_next (gmi, NULL);
|
g_match_info_next (gmi, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_match_info_free (gmi);
|
g_match_info_free (gmi);
|
||||||
|
|
||||||
return TRUE;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Miscellaneous description --- */
|
/* Miscellaneous description --- */
|
||||||
#define DOMAIN "[_\\pL\\pN\\pS][-_\\pL\\pN\\pS]*(\\.[-_\\pL\\pN\\pS]+)*"
|
#define DOMAIN_LABEL "[\\pL\\pN](?:[-\\pL\\pN]{0,61}[\\pL\\pN])?"
|
||||||
#define TLD "\\.[\\pL][-\\pL\\pN]*[\\pL]"
|
#define DOMAIN DOMAIN_LABEL "(\\." DOMAIN_LABEL ")*"
|
||||||
#define IPADDR "[0-9]{1,3}(\\.[0-9]{1,3}){3}"
|
#define TLD "\\.[\\pL](?:[-\\pL\\pN]*[\\pL\\pN])?"
|
||||||
|
#define IPADDR "(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}"
|
||||||
#define IPV6GROUP "([0-9a-f]{0,4})"
|
#define IPV6GROUP "([0-9a-f]{0,4})"
|
||||||
#define IPV6ADDR "((" IPV6GROUP "(:" IPV6GROUP "){7})" \
|
#define IPV6ADDR "((" IPV6GROUP "(:" IPV6GROUP "){7})" \
|
||||||
"|(" IPV6GROUP "(:" IPV6GROUP ")*:(:" IPV6GROUP ")+))" /* with :: compression */
|
"|(" IPV6GROUP "(:" IPV6GROUP ")*:(:" IPV6GROUP ")+))" /* with :: compression */
|
||||||
#define HOST "(" DOMAIN TLD "|" IPADDR "|" IPV6ADDR ")"
|
#define HOST "(" DOMAIN TLD "|" IPADDR "|" IPV6ADDR ")"
|
||||||
/* In urls the IPv6 must be enclosed in square brackets */
|
/* In urls the IPv6 must be enclosed in square brackets */
|
||||||
#define HOST_URL "(" DOMAIN TLD "|" IPADDR "|" "\\[" IPV6ADDR "\\]" ")"
|
#define HOST_URL "(" DOMAIN TLD "|" IPADDR "|" "\\[" IPV6ADDR "\\]" ")"
|
||||||
#define HOST_URL_OPT_TLD "(" DOMAIN "|" HOST_URL ")"
|
#define HOST_URL_OPT_TLD HOST_URL
|
||||||
#define PORT "(:[1-9][0-9]{0,4})"
|
#define PORT "(:[1-9][0-9]{0,4})"
|
||||||
#define OPT_PORT "(" PORT ")?"
|
#define OPT_PORT "(" PORT ")?"
|
||||||
|
|
||||||
|
|||||||
@@ -508,38 +508,74 @@ chanlist_match_topic_button_toggled (GtkWidget * wid, server *serv)
|
|||||||
serv->gui->chanlist_match_wants_topic = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wid));
|
serv->gui->chanlist_match_wants_topic = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GSList *
|
||||||
|
chanlist_get_selection (server *serv, int column)
|
||||||
|
{
|
||||||
|
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (serv->gui->chanlist_list));
|
||||||
|
GtkTreeModel *model = GET_MODEL (serv);
|
||||||
|
GList *rows;
|
||||||
|
GList *cur;
|
||||||
|
GSList *result = NULL;
|
||||||
|
|
||||||
|
rows = gtk_tree_selection_get_selected_rows (sel, &model);
|
||||||
|
for (cur = rows; cur != NULL; cur = cur->next)
|
||||||
|
{
|
||||||
|
GtkTreeIter iter;
|
||||||
|
char *value;
|
||||||
|
|
||||||
|
if (gtk_tree_model_get_iter (model, &iter, (GtkTreePath *)cur->data))
|
||||||
|
{
|
||||||
|
gtk_tree_model_get (model, &iter, column, &value, -1);
|
||||||
|
result = g_slist_prepend (result, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free_full (rows, (GDestroyNotify) gtk_tree_path_free);
|
||||||
|
return g_slist_reverse (result);
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
chanlist_get_selected (server *serv, gboolean get_topic)
|
chanlist_get_selected (server *serv, gboolean get_topic)
|
||||||
{
|
{
|
||||||
char *chan;
|
GSList *selection = chanlist_get_selection (serv, get_topic ? COL_TOPIC : COL_CHANNEL);
|
||||||
GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (serv->gui->chanlist_list));
|
char *value;
|
||||||
GtkTreeModel *model;
|
|
||||||
GtkTreeIter iter;
|
|
||||||
|
|
||||||
if (!gtk_tree_selection_get_selected (sel, &model, &iter))
|
if (!selection)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
gtk_tree_model_get (model, &iter, get_topic ? COL_TOPIC : COL_CHANNEL, &chan, -1);
|
value = selection->data;
|
||||||
return chan;
|
selection->data = NULL;
|
||||||
|
g_slist_free_full (selection, g_free);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
chanlist_join (GtkWidget * wid, server *serv)
|
chanlist_join (GtkWidget * wid, server *serv)
|
||||||
{
|
{
|
||||||
char tbuf[CHANLEN + 6];
|
char tbuf[CHANLEN + 6];
|
||||||
char *chan = chanlist_get_selected (serv, FALSE);
|
GSList *selection;
|
||||||
if (chan)
|
GSList *item;
|
||||||
|
gboolean joined = FALSE;
|
||||||
|
|
||||||
|
selection = chanlist_get_selection (serv, COL_CHANNEL);
|
||||||
|
for (item = selection; item != NULL; item = item->next)
|
||||||
{
|
{
|
||||||
if (serv->connected && (strcmp (chan, "*") != 0))
|
char *chan = item->data;
|
||||||
|
|
||||||
|
if (serv->connected && strcmp (chan, "*") != 0)
|
||||||
{
|
{
|
||||||
g_snprintf (tbuf, sizeof (tbuf), "join %s", chan);
|
g_snprintf (tbuf, sizeof (tbuf), "join %s", chan);
|
||||||
handle_command (serv->server_session, tbuf, FALSE);
|
handle_command (serv->server_session, tbuf, FALSE);
|
||||||
} else
|
joined = TRUE;
|
||||||
gdk_display_beep (gdk_display_get_default ());
|
|
||||||
g_free (chan);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!joined && selection)
|
||||||
|
gdk_display_beep (gdk_display_get_default ());
|
||||||
|
|
||||||
|
g_slist_free_full (selection, g_free);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
chanlist_filereq_done (server *serv, char *file)
|
chanlist_filereq_done (server *serv, char *file)
|
||||||
{
|
{
|
||||||
@@ -656,23 +692,47 @@ chanlist_menu_destroy (GtkWidget *menu, gpointer userdata)
|
|||||||
static void
|
static void
|
||||||
chanlist_copychannel (GtkWidget *item, server *serv)
|
chanlist_copychannel (GtkWidget *item, server *serv)
|
||||||
{
|
{
|
||||||
char *chan = chanlist_get_selected (serv, FALSE);
|
GSList *selection = chanlist_get_selection (serv, COL_CHANNEL);
|
||||||
if (chan)
|
GSList *cur;
|
||||||
|
GString *text;
|
||||||
|
|
||||||
|
if (!selection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
text = g_string_new ("");
|
||||||
|
for (cur = selection; cur != NULL; cur = cur->next)
|
||||||
{
|
{
|
||||||
gtkutil_copy_to_clipboard (item, NULL, chan);
|
if (text->len)
|
||||||
g_free (chan);
|
g_string_append_c (text, '\n');
|
||||||
|
g_string_append (text, (char *)cur->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gtkutil_copy_to_clipboard (item, NULL, text->str);
|
||||||
|
g_string_free (text, TRUE);
|
||||||
|
g_slist_free_full (selection, g_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
chanlist_copytopic (GtkWidget *item, server *serv)
|
chanlist_copytopic (GtkWidget *item, server *serv)
|
||||||
{
|
{
|
||||||
char *topic = chanlist_get_selected (serv, TRUE);
|
GSList *selection = chanlist_get_selection (serv, COL_TOPIC);
|
||||||
if (topic)
|
GSList *cur;
|
||||||
|
GString *text;
|
||||||
|
|
||||||
|
if (!selection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
text = g_string_new ("");
|
||||||
|
for (cur = selection; cur != NULL; cur = cur->next)
|
||||||
{
|
{
|
||||||
gtkutil_copy_to_clipboard (item, NULL, topic);
|
if (text->len)
|
||||||
g_free (topic);
|
g_string_append_c (text, '\n');
|
||||||
|
g_string_append (text, (char *)cur->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gtkutil_copy_to_clipboard (item, NULL, text->str);
|
||||||
|
g_string_free (text, TRUE);
|
||||||
|
g_slist_free_full (selection, g_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -689,10 +749,12 @@ chanlist_button_cb (GtkTreeView *tree, GdkEventButton *event, server *serv)
|
|||||||
if (!gtk_tree_view_get_path_at_pos (tree, event->x, event->y, &path, 0, 0, 0))
|
if (!gtk_tree_view_get_path_at_pos (tree, event->x, event->y, &path, 0, 0, 0))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* select what they right-clicked on */
|
|
||||||
sel = gtk_tree_view_get_selection (tree);
|
sel = gtk_tree_view_get_selection (tree);
|
||||||
|
if (!gtk_tree_selection_path_is_selected (sel, path))
|
||||||
|
{
|
||||||
gtk_tree_selection_unselect_all (sel);
|
gtk_tree_selection_unselect_all (sel);
|
||||||
gtk_tree_selection_select_path (sel, path);
|
gtk_tree_selection_select_path (sel, path);
|
||||||
|
}
|
||||||
gtk_tree_path_free (path);
|
gtk_tree_path_free (path);
|
||||||
|
|
||||||
menu = gtk_menu_new ();
|
menu = gtk_menu_new ();
|
||||||
@@ -879,6 +941,7 @@ chanlist_opengui (server *serv, int do_refresh)
|
|||||||
chanlist_add_column (view, COL_USERS, 50, _("Users"), TRUE);
|
chanlist_add_column (view, COL_USERS, 50, _("Users"), TRUE);
|
||||||
chanlist_add_column (view, COL_TOPIC, 50, _("Topic"), FALSE);
|
chanlist_add_column (view, COL_TOPIC, 50, _("Topic"), FALSE);
|
||||||
gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_HORIZONTAL);
|
gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_HORIZONTAL);
|
||||||
|
gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), GTK_SELECTION_MULTIPLE);
|
||||||
/* this is a speed up, but no horizontal scrollbar :( */
|
/* this is a speed up, but no horizontal scrollbar :( */
|
||||||
/*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_widget_show (view);
|
gtk_widget_show (view);
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ cv_tree_init (chanview *cv)
|
|||||||
GTK_SHADOW_IN);
|
GTK_SHADOW_IN);
|
||||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (win),
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (win),
|
||||||
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||||
|
gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (win), 1);
|
||||||
gtk_container_add (GTK_CONTAINER (cv->box), win);
|
gtk_container_add (GTK_CONTAINER (cv->box), win);
|
||||||
gtk_widget_show (win);
|
gtk_widget_show (win);
|
||||||
|
|
||||||
@@ -165,7 +166,6 @@ cv_tree_init (chanview *cv)
|
|||||||
gtk_container_add (GTK_CONTAINER (win), view);
|
gtk_container_add (GTK_CONTAINER (win), view);
|
||||||
col = gtk_tree_view_column_new();
|
col = gtk_tree_view_column_new();
|
||||||
|
|
||||||
/* icon column */
|
|
||||||
if (cv->use_icons)
|
if (cv->use_icons)
|
||||||
{
|
{
|
||||||
renderer = gtk_cell_renderer_pixbuf_new ();
|
renderer = gtk_cell_renderer_pixbuf_new ();
|
||||||
@@ -176,10 +176,10 @@ cv_tree_init (chanview *cv)
|
|||||||
gtk_tree_view_column_set_attributes (col, renderer, "pixbuf", COL_PIXBUF, NULL);
|
gtk_tree_view_column_set_attributes (col, renderer, "pixbuf", COL_PIXBUF, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* main column */
|
|
||||||
renderer = gtk_cell_renderer_text_new ();
|
renderer = gtk_cell_renderer_text_new ();
|
||||||
if (prefs.hex_gui_compact)
|
if (prefs.hex_gui_compact)
|
||||||
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
||||||
|
g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
||||||
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
||||||
gtk_tree_view_column_pack_start (col, renderer, TRUE);
|
gtk_tree_view_column_pack_start (col, renderer, TRUE);
|
||||||
gtk_tree_view_column_set_attributes (col, renderer,
|
gtk_tree_view_column_set_attributes (col, renderer,
|
||||||
@@ -188,7 +188,10 @@ cv_tree_init (chanview *cv)
|
|||||||
"underline", COL_UNDERLINE,
|
"underline", COL_UNDERLINE,
|
||||||
NULL);
|
NULL);
|
||||||
gtk_tree_view_column_set_expand (col, TRUE);
|
gtk_tree_view_column_set_expand (col, TRUE);
|
||||||
|
gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
|
||||||
|
gtk_tree_view_column_set_min_width (col, 1);
|
||||||
gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
|
gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
|
||||||
|
gtk_tree_view_set_expander_column (GTK_TREE_VIEW (view), col);
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (view))),
|
g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (view))),
|
||||||
"changed", G_CALLBACK (cv_tree_sel_cb), cv);
|
"changed", G_CALLBACK (cv_tree_sel_cb), cv);
|
||||||
|
|||||||
@@ -758,11 +758,15 @@ fe_set_topic (session *sess, char *topic, char *stripped_topic)
|
|||||||
{
|
{
|
||||||
if (prefs.hex_text_stripcolor_topic)
|
if (prefs.hex_text_stripcolor_topic)
|
||||||
{
|
{
|
||||||
gtk_entry_set_text (GTK_ENTRY (sess->gui->topic_entry), stripped_topic);
|
gtk_text_buffer_set_text (
|
||||||
|
gtk_text_view_get_buffer (GTK_TEXT_VIEW (sess->gui->topic_entry)),
|
||||||
|
stripped_topic, -1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gtk_entry_set_text (GTK_ENTRY (sess->gui->topic_entry), topic);
|
gtk_text_buffer_set_text (
|
||||||
|
gtk_text_view_get_buffer (GTK_TEXT_VIEW (sess->gui->topic_entry)),
|
||||||
|
topic, -1);
|
||||||
}
|
}
|
||||||
mg_set_topic_tip (sess);
|
mg_set_topic_tip (sess);
|
||||||
}
|
}
|
||||||
@@ -1335,22 +1339,79 @@ fe_open_url_inner (const char *url)
|
|||||||
g_free (escaped_url);
|
g_free (escaped_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fe_open_url_is_local_path (const char *url)
|
||||||
|
{
|
||||||
|
if (g_path_is_absolute (url) || g_file_test (url, G_FILE_TEST_EXISTS))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (g_ascii_isalpha (url[0]) && url[1] == ':' &&
|
||||||
|
(url[2] == '\\' || url[2] == '/'))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (url[0] == '\\' && url[1] == '\\')
|
||||||
|
return TRUE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
fe_open_url_canonicalize_path (const char *path)
|
||||||
|
{
|
||||||
|
char *absolute_path;
|
||||||
|
char *cwd;
|
||||||
|
|
||||||
|
if (!path || path[0] == '\0')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (g_path_is_absolute (path))
|
||||||
|
return g_strdup (path);
|
||||||
|
|
||||||
|
cwd = g_get_current_dir ();
|
||||||
|
absolute_path = g_build_filename (cwd, path, NULL);
|
||||||
|
g_free (cwd);
|
||||||
|
return absolute_path;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fe_open_url (const char *url)
|
fe_open_url (const char *url)
|
||||||
{
|
{
|
||||||
int url_type = url_check_word (url);
|
int url_type = url_check_word (url);
|
||||||
char *uri;
|
char *uri;
|
||||||
|
char *path;
|
||||||
|
char *path_uri;
|
||||||
|
|
||||||
|
if (fe_open_url_is_local_path (url))
|
||||||
|
{
|
||||||
|
path = fe_open_url_canonicalize_path (url);
|
||||||
|
path_uri = g_filename_to_uri (path, NULL, NULL);
|
||||||
|
g_free (path);
|
||||||
|
|
||||||
|
if (path_uri)
|
||||||
|
{
|
||||||
|
fe_open_url_inner (path_uri);
|
||||||
|
g_free (path_uri);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* gvfs likes file:// */
|
/* gvfs likes file:// */
|
||||||
if (url_type == WORD_PATH)
|
if (url_type == WORD_PATH)
|
||||||
{
|
{
|
||||||
#ifndef WIN32
|
path = fe_open_url_canonicalize_path (url);
|
||||||
uri = g_strconcat ("file://", url, NULL);
|
path_uri = g_filename_to_uri (path, NULL, NULL);
|
||||||
fe_open_url_inner (uri);
|
g_free (path);
|
||||||
g_free (uri);
|
if (path_uri)
|
||||||
#else
|
{
|
||||||
|
fe_open_url_inner (path_uri);
|
||||||
|
g_free (path_uri);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
fe_open_url_inner (url);
|
fe_open_url_inner (url);
|
||||||
#endif
|
}
|
||||||
}
|
}
|
||||||
/* IPv6 addr. Add http:// */
|
/* IPv6 addr. Add http:// */
|
||||||
else if (url_type == WORD_HOST6)
|
else if (url_type == WORD_HOST6)
|
||||||
|
|||||||
@@ -670,7 +670,7 @@ mg_spellcheck_cb (SexySpellEntry *entry, gchar *word, gpointer data)
|
|||||||
{
|
{
|
||||||
/* This can cause freezes on long words, nicks arn't very long anyway. */
|
/* This can cause freezes on long words, nicks arn't very long anyway. */
|
||||||
if (strlen (word) > 20)
|
if (strlen (word) > 20)
|
||||||
return TRUE;
|
return FALSE;
|
||||||
|
|
||||||
/* Ignore anything we think is a valid url */
|
/* Ignore anything we think is a valid url */
|
||||||
if (url_check_word (word) != 0)
|
if (url_check_word (word) != 0)
|
||||||
@@ -920,13 +920,18 @@ mg_unpopulate (session *sess)
|
|||||||
{
|
{
|
||||||
restore_gui *res;
|
restore_gui *res;
|
||||||
session_gui *gui;
|
session_gui *gui;
|
||||||
|
GtkTextBuffer *topic_buffer;
|
||||||
|
GtkTextIter start;
|
||||||
|
GtkTextIter end;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
gui = sess->gui;
|
gui = sess->gui;
|
||||||
res = sess->res;
|
res = sess->res;
|
||||||
|
|
||||||
res->input_text = g_strdup (SPELL_ENTRY_GET_TEXT (gui->input_box));
|
res->input_text = g_strdup (SPELL_ENTRY_GET_TEXT (gui->input_box));
|
||||||
res->topic_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (gui->topic_entry)));
|
topic_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (gui->topic_entry));
|
||||||
|
gtk_text_buffer_get_bounds (topic_buffer, &start, &end);
|
||||||
|
res->topic_text = gtk_text_buffer_get_text (topic_buffer, &start, &end, FALSE);
|
||||||
res->limit_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (gui->limit_entry)));
|
res->limit_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (gui->limit_entry)));
|
||||||
res->key_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (gui->key_entry)));
|
res->key_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (gui->key_entry)));
|
||||||
if (gui->laginfo)
|
if (gui->laginfo)
|
||||||
@@ -1003,6 +1008,9 @@ void
|
|||||||
mg_set_topic_tip (session *sess)
|
mg_set_topic_tip (session *sess)
|
||||||
{
|
{
|
||||||
char *text;
|
char *text;
|
||||||
|
GtkTextBuffer *topic_buffer;
|
||||||
|
GtkTextIter start;
|
||||||
|
GtkTextIter end;
|
||||||
|
|
||||||
switch (sess->type)
|
switch (sess->type)
|
||||||
{
|
{
|
||||||
@@ -1017,11 +1025,14 @@ mg_set_topic_tip (session *sess)
|
|||||||
gtk_widget_set_tooltip_text (sess->gui->topic_entry, _("No topic is set"));
|
gtk_widget_set_tooltip_text (sess->gui->topic_entry, _("No topic is set"));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (gtk_entry_get_text (GTK_ENTRY (sess->gui->topic_entry)) &&
|
topic_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (sess->gui->topic_entry));
|
||||||
gtk_entry_get_text (GTK_ENTRY (sess->gui->topic_entry))[0])
|
gtk_text_buffer_get_bounds (topic_buffer, &start, &end);
|
||||||
gtk_widget_set_tooltip_text (sess->gui->topic_entry, (char *)gtk_entry_get_text (GTK_ENTRY (sess->gui->topic_entry)));
|
text = gtk_text_buffer_get_text (topic_buffer, &start, &end, FALSE);
|
||||||
|
if (text[0])
|
||||||
|
gtk_widget_set_tooltip_text (sess->gui->topic_entry, text);
|
||||||
else
|
else
|
||||||
gtk_widget_set_tooltip_text (sess->gui->topic_entry, NULL);
|
gtk_widget_set_tooltip_text (sess->gui->topic_entry, NULL);
|
||||||
|
g_free (text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1052,9 +1063,14 @@ mg_userlist_showhide (session *sess, int show)
|
|||||||
session_gui *gui = sess->gui;
|
session_gui *gui = sess->gui;
|
||||||
int handle_size;
|
int handle_size;
|
||||||
int right_size;
|
int right_size;
|
||||||
|
int min_right_size;
|
||||||
GtkAllocation allocation;
|
GtkAllocation allocation;
|
||||||
|
|
||||||
right_size = MAX (prefs.hex_gui_pane_right_size, prefs.hex_gui_pane_right_size_min);
|
gtk_widget_get_size_request (gui->user_box, &min_right_size, NULL);
|
||||||
|
if (min_right_size < 1)
|
||||||
|
min_right_size = 1;
|
||||||
|
|
||||||
|
right_size = MAX (prefs.hex_gui_pane_right_size, min_right_size);
|
||||||
|
|
||||||
if (show)
|
if (show)
|
||||||
{
|
{
|
||||||
@@ -1164,7 +1180,7 @@ mg_populate (session *sess)
|
|||||||
/* hide the userlist */
|
/* hide the userlist */
|
||||||
mg_decide_userlist (sess, FALSE);
|
mg_decide_userlist (sess, FALSE);
|
||||||
/* shouldn't edit the topic */
|
/* shouldn't edit the topic */
|
||||||
gtk_editable_set_editable (GTK_EDITABLE (gui->topic_entry), FALSE);
|
gtk_text_view_set_editable (GTK_TEXT_VIEW (gui->topic_entry), FALSE);
|
||||||
/* might be hidden from server tab */
|
/* might be hidden from server tab */
|
||||||
if (prefs.hex_gui_topicbar)
|
if (prefs.hex_gui_topicbar)
|
||||||
gtk_widget_show (gui->topic_bar);
|
gtk_widget_show (gui->topic_bar);
|
||||||
@@ -1186,8 +1202,8 @@ mg_populate (session *sess)
|
|||||||
gtk_widget_show (gui->topicbutton_box);
|
gtk_widget_show (gui->topicbutton_box);
|
||||||
/* show the userlist */
|
/* show the userlist */
|
||||||
mg_decide_userlist (sess, FALSE);
|
mg_decide_userlist (sess, FALSE);
|
||||||
/* let the topic be editted */
|
/* let the topic be edited */
|
||||||
gtk_editable_set_editable (GTK_EDITABLE (gui->topic_entry), TRUE);
|
gtk_text_view_set_editable (GTK_TEXT_VIEW (gui->topic_entry), TRUE);
|
||||||
if (prefs.hex_gui_topicbar)
|
if (prefs.hex_gui_topicbar)
|
||||||
gtk_widget_show (gui->topic_bar);
|
gtk_widget_show (gui->topic_bar);
|
||||||
}
|
}
|
||||||
@@ -1207,8 +1223,21 @@ mg_populate (session *sess)
|
|||||||
if (gui->is_tab)
|
if (gui->is_tab)
|
||||||
gtk_widget_set_sensitive (gui->menu, TRUE);
|
gtk_widget_set_sensitive (gui->menu, TRUE);
|
||||||
|
|
||||||
/* restore all the GtkEntry's */
|
if (res->topic_text)
|
||||||
mg_restore_entry (gui->topic_entry, &res->topic_text);
|
{
|
||||||
|
GtkTextBuffer *topic_buffer;
|
||||||
|
|
||||||
|
topic_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (gui->topic_entry));
|
||||||
|
gtk_text_buffer_set_text (topic_buffer, res->topic_text, -1);
|
||||||
|
g_free (res->topic_text);
|
||||||
|
res->topic_text = NULL;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
GtkTextBuffer *topic_buffer;
|
||||||
|
|
||||||
|
topic_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (gui->topic_entry));
|
||||||
|
gtk_text_buffer_set_text (topic_buffer, "", -1);
|
||||||
|
}
|
||||||
mg_restore_speller (gui->input_box, &res->input_text);
|
mg_restore_speller (gui->input_box, &res->input_text);
|
||||||
mg_restore_entry (gui->key_entry, &res->key_text);
|
mg_restore_entry (gui->key_entry, &res->key_text);
|
||||||
mg_restore_entry (gui->limit_entry, &res->limit_text);
|
mg_restore_entry (gui->limit_entry, &res->limit_text);
|
||||||
@@ -2114,24 +2143,196 @@ mg_create_userlistbuttons (GtkWidget *box)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mg_topic_cb (GtkWidget *entry, gpointer userdata)
|
mg_topic_cb (GtkWidget *entry)
|
||||||
{
|
{
|
||||||
session *sess = current_sess;
|
session *sess = current_sess;
|
||||||
|
GtkTextBuffer *topic_buffer;
|
||||||
|
GtkTextIter start;
|
||||||
|
GtkTextIter end;
|
||||||
char *text;
|
char *text;
|
||||||
|
|
||||||
if (sess->channel[0] && sess->server->connected && sess->type == SESS_CHANNEL)
|
if (sess->channel[0] && sess->server->connected && sess->type == SESS_CHANNEL)
|
||||||
{
|
{
|
||||||
text = (char *)gtk_entry_get_text (GTK_ENTRY (entry));
|
topic_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry));
|
||||||
|
gtk_text_buffer_get_bounds (topic_buffer, &start, &end);
|
||||||
|
text = gtk_text_buffer_get_text (topic_buffer, &start, &end, FALSE);
|
||||||
if (text[0] == 0)
|
if (text[0] == 0)
|
||||||
text = NULL;
|
sess->server->p_topic (sess->server, sess->channel, NULL);
|
||||||
|
else
|
||||||
sess->server->p_topic (sess->server, sess->channel, text);
|
sess->server->p_topic (sess->server, sess->channel, text);
|
||||||
|
g_free (text);
|
||||||
} else
|
} else
|
||||||
gtk_entry_set_text (GTK_ENTRY (entry), "");
|
{
|
||||||
|
topic_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry));
|
||||||
|
gtk_text_buffer_set_text (topic_buffer, "", -1);
|
||||||
|
}
|
||||||
/* restore focus to the input widget, where the next input will most
|
/* restore focus to the input widget, where the next input will most
|
||||||
likely be */
|
likely be */
|
||||||
gtk_widget_grab_focus (sess->gui->input_box);
|
gtk_widget_grab_focus (sess->gui->input_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
mg_topic_key_press_cb (GtkWidget *entry, GdkEventKey *event, gpointer userdata)
|
||||||
|
{
|
||||||
|
if (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter)
|
||||||
|
{
|
||||||
|
mg_topic_cb (entry);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
mg_topic_get_word_at_pos (GtkWidget *entry, gdouble event_x, gdouble event_y, int *word_pos)
|
||||||
|
{
|
||||||
|
GtkTextBuffer *buffer;
|
||||||
|
GtkTextIter iter;
|
||||||
|
GtkTextIter start;
|
||||||
|
GtkTextIter end;
|
||||||
|
GtkTextIter cursor;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
x = (int)event_x;
|
||||||
|
y = (int)event_y;
|
||||||
|
gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (entry), GTK_TEXT_WINDOW_TEXT,
|
||||||
|
x, y, &x, &y);
|
||||||
|
gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (entry), &iter, x, y);
|
||||||
|
|
||||||
|
cursor = iter;
|
||||||
|
start = iter;
|
||||||
|
while (!gtk_text_iter_starts_line (&start))
|
||||||
|
{
|
||||||
|
GtkTextIter prev = start;
|
||||||
|
gunichar ch;
|
||||||
|
|
||||||
|
gtk_text_iter_backward_char (&prev);
|
||||||
|
ch = gtk_text_iter_get_char (&prev);
|
||||||
|
if (g_unichar_isspace (ch))
|
||||||
|
break;
|
||||||
|
start = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
end = iter;
|
||||||
|
while (!gtk_text_iter_ends_line (&end))
|
||||||
|
{
|
||||||
|
gunichar ch;
|
||||||
|
|
||||||
|
ch = gtk_text_iter_get_char (&end);
|
||||||
|
if (ch == 0 || g_unichar_isspace (ch))
|
||||||
|
break;
|
||||||
|
gtk_text_iter_forward_char (&end);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gtk_text_iter_equal (&start, &end))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (word_pos)
|
||||||
|
{
|
||||||
|
char *prefix;
|
||||||
|
|
||||||
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry));
|
||||||
|
prefix = gtk_text_buffer_get_text (buffer, &start, &cursor, FALSE);
|
||||||
|
*word_pos = (int)strlen (prefix);
|
||||||
|
g_free (prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (entry));
|
||||||
|
return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mg_topic_set_cursor (GtkWidget *entry, GdkCursorType cursor_type)
|
||||||
|
{
|
||||||
|
GdkWindow *text_window;
|
||||||
|
GdkDisplay *display;
|
||||||
|
GdkCursor *cursor;
|
||||||
|
|
||||||
|
text_window = gtk_text_view_get_window (GTK_TEXT_VIEW (entry), GTK_TEXT_WINDOW_TEXT);
|
||||||
|
if (!text_window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
display = gdk_window_get_display (text_window);
|
||||||
|
cursor = gdk_cursor_new_for_display (display, cursor_type);
|
||||||
|
gdk_window_set_cursor (text_window, cursor);
|
||||||
|
g_object_unref (cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
mg_topic_word_is_clickable (const char *word, int word_pos)
|
||||||
|
{
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
|
||||||
|
if (!word || word[0] == 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (strcmp (word, "/") == 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (url_check_word (word) == 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
url_last (&start, &end);
|
||||||
|
return word_pos >= start && word_pos < end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
mg_topic_motion_cb (GtkWidget *entry, GdkEventMotion *event, gpointer userdata)
|
||||||
|
{
|
||||||
|
char *word;
|
||||||
|
int word_pos;
|
||||||
|
gboolean word_is_clickable;
|
||||||
|
|
||||||
|
word_pos = 0;
|
||||||
|
word = mg_topic_get_word_at_pos (entry, event->x, event->y, &word_pos);
|
||||||
|
word_is_clickable = mg_topic_word_is_clickable (word, word_pos);
|
||||||
|
if (word_is_clickable)
|
||||||
|
mg_topic_set_cursor (entry, GDK_HAND2);
|
||||||
|
else
|
||||||
|
mg_topic_set_cursor (entry, GDK_XTERM);
|
||||||
|
g_free (word);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
mg_topic_leave_cb (GtkWidget *entry, GdkEventCrossing *event, gpointer userdata)
|
||||||
|
{
|
||||||
|
mg_topic_set_cursor (entry, GDK_XTERM);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
mg_topic_button_release_cb (GtkWidget *entry, GdkEventButton *event, gpointer userdata)
|
||||||
|
{
|
||||||
|
char *word;
|
||||||
|
int word_pos;
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
|
||||||
|
if (event->button != 1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
word_pos = 0;
|
||||||
|
word = mg_topic_get_word_at_pos (entry, event->x, event->y, &word_pos);
|
||||||
|
if (!word)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (mg_topic_word_is_clickable (word, word_pos))
|
||||||
|
{
|
||||||
|
url_last (&start, &end);
|
||||||
|
word[end] = 0;
|
||||||
|
fe_open_url (word + start);
|
||||||
|
g_free (word);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (word);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mg_tabwindow_kill_cb (GtkWidget *win, gpointer userdata)
|
mg_tabwindow_kill_cb (GtkWidget *win, gpointer userdata)
|
||||||
{
|
{
|
||||||
@@ -2415,6 +2616,20 @@ mg_apply_entry_style (GtkWidget *entry)
|
|||||||
theme_manager_apply_entry_palette (entry, input_style->font_desc);
|
theme_manager_apply_entry_palette (entry, input_style->font_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
mg_entry_select_all (GtkWidget *entry, GdkEventKey *event, gpointer userdata)
|
||||||
|
{
|
||||||
|
if ((event->state & GDK_CONTROL_MASK) &&
|
||||||
|
!(event->state & (GDK_SHIFT_MASK | GDK_MOD1_MASK | GDK_META_MASK)) &&
|
||||||
|
(event->keyval == GDK_KEY_a || event->keyval == GDK_KEY_A))
|
||||||
|
{
|
||||||
|
gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mg_create_chanmodebuttons (session_gui *gui, GtkWidget *box)
|
mg_create_chanmodebuttons (session_gui *gui, GtkWidget *box)
|
||||||
{
|
{
|
||||||
@@ -2434,6 +2649,8 @@ mg_create_chanmodebuttons (session_gui *gui, GtkWidget *box)
|
|||||||
mg_apply_emoji_fallback_widget (gui->key_entry);
|
mg_apply_emoji_fallback_widget (gui->key_entry);
|
||||||
g_signal_connect (G_OBJECT (gui->key_entry), "activate",
|
g_signal_connect (G_OBJECT (gui->key_entry), "activate",
|
||||||
G_CALLBACK (mg_key_entry_cb), NULL);
|
G_CALLBACK (mg_key_entry_cb), NULL);
|
||||||
|
g_signal_connect (G_OBJECT (gui->key_entry), "key_press_event",
|
||||||
|
G_CALLBACK (mg_entry_select_all), NULL);
|
||||||
|
|
||||||
if (prefs.hex_gui_input_style)
|
if (prefs.hex_gui_input_style)
|
||||||
mg_apply_entry_style (gui->key_entry);
|
mg_apply_entry_style (gui->key_entry);
|
||||||
@@ -2447,6 +2664,8 @@ mg_create_chanmodebuttons (session_gui *gui, GtkWidget *box)
|
|||||||
mg_apply_emoji_fallback_widget (gui->limit_entry);
|
mg_apply_emoji_fallback_widget (gui->limit_entry);
|
||||||
g_signal_connect (G_OBJECT (gui->limit_entry), "activate",
|
g_signal_connect (G_OBJECT (gui->limit_entry), "activate",
|
||||||
G_CALLBACK (mg_limit_entry_cb), NULL);
|
G_CALLBACK (mg_limit_entry_cb), NULL);
|
||||||
|
g_signal_connect (G_OBJECT (gui->limit_entry), "key_press_event",
|
||||||
|
G_CALLBACK (mg_entry_select_all), NULL);
|
||||||
|
|
||||||
if (prefs.hex_gui_input_style)
|
if (prefs.hex_gui_input_style)
|
||||||
mg_apply_entry_style (gui->limit_entry);
|
mg_apply_entry_style (gui->limit_entry);
|
||||||
@@ -2470,12 +2689,18 @@ mg_dialog_button_cb (GtkWidget *wid, char *cmd)
|
|||||||
char buf[128];
|
char buf[128];
|
||||||
char *host = "";
|
char *host = "";
|
||||||
char *topic;
|
char *topic;
|
||||||
|
char *topic_text;
|
||||||
|
GtkTextBuffer *topic_buffer;
|
||||||
|
GtkTextIter start;
|
||||||
|
GtkTextIter end;
|
||||||
|
|
||||||
if (!current_sess)
|
if (!current_sess)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
topic = (char *)(gtk_entry_get_text (GTK_ENTRY (current_sess->gui->topic_entry)));
|
topic_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (current_sess->gui->topic_entry));
|
||||||
topic = strrchr (topic, '@');
|
gtk_text_buffer_get_bounds (topic_buffer, &start, &end);
|
||||||
|
topic_text = gtk_text_buffer_get_text (topic_buffer, &start, &end, FALSE);
|
||||||
|
topic = strrchr (topic_text, '@');
|
||||||
if (topic)
|
if (topic)
|
||||||
host = topic + 1;
|
host = topic + 1;
|
||||||
|
|
||||||
@@ -2484,6 +2709,7 @@ mg_dialog_button_cb (GtkWidget *wid, char *cmd)
|
|||||||
current_sess->channel, "");
|
current_sess->channel, "");
|
||||||
|
|
||||||
handle_command (current_sess, buf, TRUE);
|
handle_command (current_sess, buf, TRUE);
|
||||||
|
g_free (topic_text);
|
||||||
|
|
||||||
/* dirty trick to avoid auto-selection */
|
/* dirty trick to avoid auto-selection */
|
||||||
SPELL_ENTRY_SET_EDITABLE (current_sess->gui->input_box, FALSE);
|
SPELL_ENTRY_SET_EDITABLE (current_sess->gui->input_box, FALSE);
|
||||||
@@ -2530,16 +2756,23 @@ mg_create_topicbar (session *sess, GtkWidget *box)
|
|||||||
if (!gui->is_tab)
|
if (!gui->is_tab)
|
||||||
sess->res->tab = NULL;
|
sess->res->tab = NULL;
|
||||||
|
|
||||||
gui->topic_entry = topic = sexy_spell_entry_new ();
|
gui->topic_entry = topic = gtk_text_view_new ();
|
||||||
gtk_widget_set_name (topic, "zoitechat-inputbox");
|
gtk_widget_set_name (topic, "zoitechat-inputbox");
|
||||||
sexy_spell_entry_set_checked (SEXY_SPELL_ENTRY (topic), FALSE);
|
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (topic), GTK_WRAP_WORD_CHAR);
|
||||||
|
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (topic), 4);
|
||||||
|
gtk_text_view_set_right_margin (GTK_TEXT_VIEW (topic), 4);
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), topic, TRUE, TRUE, 0);
|
gtk_box_pack_start (GTK_BOX (hbox), topic, TRUE, TRUE, 0);
|
||||||
mg_apply_emoji_fallback_widget (topic);
|
mg_apply_emoji_fallback_widget (topic);
|
||||||
g_signal_connect (G_OBJECT (topic), "activate",
|
gtk_widget_add_events (topic, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
||||||
G_CALLBACK (mg_topic_cb), 0);
|
GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
|
||||||
|
g_signal_connect (G_OBJECT (topic), "key-press-event",
|
||||||
if (prefs.hex_gui_input_style)
|
G_CALLBACK (mg_topic_key_press_cb), NULL);
|
||||||
mg_apply_entry_style (topic);
|
g_signal_connect (G_OBJECT (topic), "button-release-event",
|
||||||
|
G_CALLBACK (mg_topic_button_release_cb), NULL);
|
||||||
|
g_signal_connect (G_OBJECT (topic), "motion-notify-event",
|
||||||
|
G_CALLBACK (mg_topic_motion_cb), NULL);
|
||||||
|
g_signal_connect (G_OBJECT (topic), "leave-notify-event",
|
||||||
|
G_CALLBACK (mg_topic_leave_cb), NULL);
|
||||||
|
|
||||||
gui->topicbutton_box = bbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
|
gui->topicbutton_box = bbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
|
||||||
gtk_box_pack_start (GTK_BOX (hbox), bbox, 0, 0, 0);
|
gtk_box_pack_start (GTK_BOX (hbox), bbox, 0, 0, 0);
|
||||||
@@ -2910,6 +3143,8 @@ mg_create_userlist (session_gui *gui, GtkWidget *box)
|
|||||||
gtk_box_pack_start (GTK_BOX (vbox), frame, 0, 0, GUI_SPACING);
|
gtk_box_pack_start (GTK_BOX (vbox), frame, 0, 0, GUI_SPACING);
|
||||||
|
|
||||||
gui->namelistinfo = gtk_label_new (NULL);
|
gui->namelistinfo = gtk_label_new (NULL);
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (gui->namelistinfo), 0.0f);
|
||||||
|
gtk_widget_set_halign (gui->namelistinfo, GTK_ALIGN_START);
|
||||||
gtk_container_add (GTK_CONTAINER (frame), gui->namelistinfo);
|
gtk_container_add (GTK_CONTAINER (frame), gui->namelistinfo);
|
||||||
|
|
||||||
gui->user_tree = ulist = userlist_create (vbox);
|
gui->user_tree = ulist = userlist_create (vbox);
|
||||||
@@ -2984,12 +3219,12 @@ mg_create_center (session *sess, session_gui *gui, GtkWidget *box)
|
|||||||
|
|
||||||
if (prefs.hex_gui_win_swap)
|
if (prefs.hex_gui_win_swap)
|
||||||
{
|
{
|
||||||
gtk_paned_pack2 (GTK_PANED (gui->hpane_left), gui->vpane_left, FALSE, TRUE);
|
gtk_paned_pack2 (GTK_PANED (gui->hpane_left), gui->vpane_left, FALSE, FALSE);
|
||||||
gtk_paned_pack1 (GTK_PANED (gui->hpane_left), gui->hpane_right, TRUE, TRUE);
|
gtk_paned_pack1 (GTK_PANED (gui->hpane_left), gui->hpane_right, TRUE, TRUE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gtk_paned_pack1 (GTK_PANED (gui->hpane_left), gui->vpane_left, FALSE, TRUE);
|
gtk_paned_pack1 (GTK_PANED (gui->hpane_left), gui->vpane_left, FALSE, FALSE);
|
||||||
gtk_paned_pack2 (GTK_PANED (gui->hpane_left), gui->hpane_right, TRUE, TRUE);
|
gtk_paned_pack2 (GTK_PANED (gui->hpane_left), gui->hpane_right, TRUE, TRUE);
|
||||||
}
|
}
|
||||||
gtk_paned_pack2 (GTK_PANED (gui->hpane_right), gui->vpane_right, FALSE, TRUE);
|
gtk_paned_pack2 (GTK_PANED (gui->hpane_right), gui->vpane_right, FALSE, TRUE);
|
||||||
@@ -4088,7 +4323,8 @@ fe_clear_channel (session *sess)
|
|||||||
|
|
||||||
if (!sess->gui->is_tab || sess == current_tab)
|
if (!sess->gui->is_tab || sess == current_tab)
|
||||||
{
|
{
|
||||||
gtk_entry_set_text (GTK_ENTRY (gui->topic_entry), "");
|
gtk_text_buffer_set_text (
|
||||||
|
gtk_text_view_get_buffer (GTK_TEXT_VIEW (gui->topic_entry)), "", -1);
|
||||||
|
|
||||||
if (gui->op_xpm)
|
if (gui->op_xpm)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -869,6 +869,9 @@ menu_nickmenu (session *sess, GdkEventButton *event, char *nick, int num_sel)
|
|||||||
static void
|
static void
|
||||||
menu_showhide_cb (session *sess)
|
menu_showhide_cb (session *sess)
|
||||||
{
|
{
|
||||||
|
if (!sess->gui->menu || !GTK_IS_WIDGET (sess->gui->menu))
|
||||||
|
return;
|
||||||
|
|
||||||
if (prefs.hex_gui_hide_menu)
|
if (prefs.hex_gui_hide_menu)
|
||||||
gtk_widget_hide (sess->gui->menu);
|
gtk_widget_hide (sess->gui->menu);
|
||||||
else
|
else
|
||||||
@@ -926,6 +929,11 @@ menu_setting_foreach (void (*callback) (session *), int id, guint state)
|
|||||||
while (list)
|
while (list)
|
||||||
{
|
{
|
||||||
sess = list->data;
|
sess = list->data;
|
||||||
|
if (!sess || !sess->gui)
|
||||||
|
{
|
||||||
|
list = list->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!sess->gui->is_tab || !maindone)
|
if (!sess->gui->is_tab || !maindone)
|
||||||
{
|
{
|
||||||
@@ -935,11 +943,22 @@ menu_setting_foreach (void (*callback) (session *), int id, guint state)
|
|||||||
{
|
{
|
||||||
GtkWidget *menu_item = sess->gui->menu_item[id];
|
GtkWidget *menu_item = sess->gui->menu_item[id];
|
||||||
|
|
||||||
if (menu_item != NULL)
|
if (menu_item != NULL && GTK_IS_CHECK_MENU_ITEM (menu_item))
|
||||||
|
{
|
||||||
|
guint toggled_signal = g_signal_lookup ("toggled", G_OBJECT_TYPE (menu_item));
|
||||||
|
|
||||||
|
if (toggled_signal != 0)
|
||||||
|
{
|
||||||
|
g_signal_handlers_block_matched (menu_item, G_SIGNAL_MATCH_ID, toggled_signal, 0, NULL, NULL, NULL);
|
||||||
|
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), state);
|
||||||
|
g_signal_handlers_unblock_matched (menu_item, G_SIGNAL_MATCH_ID, toggled_signal, 0, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), state);
|
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (callback)
|
if (callback)
|
||||||
callback (sess);
|
callback (sess);
|
||||||
}
|
}
|
||||||
@@ -952,7 +971,7 @@ void
|
|||||||
menu_bar_toggle (void)
|
menu_bar_toggle (void)
|
||||||
{
|
{
|
||||||
prefs.hex_gui_hide_menu = !prefs.hex_gui_hide_menu;
|
prefs.hex_gui_hide_menu = !prefs.hex_gui_hide_menu;
|
||||||
menu_setting_foreach (menu_showhide_cb, MENU_ID_MENUBAR, !prefs.hex_gui_hide_menu);
|
menu_setting_foreach (menu_showhide_cb, -1, !prefs.hex_gui_hide_menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -2170,6 +2189,11 @@ menu_foreach_gui (menu_entry *me, void (*callback) (GtkWidget *, menu_entry *, c
|
|||||||
while (list)
|
while (list)
|
||||||
{
|
{
|
||||||
sess = list->data;
|
sess = list->data;
|
||||||
|
if (!sess || !sess->gui)
|
||||||
|
{
|
||||||
|
list = list->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
/* do it only once for tab sessions, since they share a GUI */
|
/* do it only once for tab sessions, since they share a GUI */
|
||||||
if (!sess->gui->is_tab || !tabdone)
|
if (!sess->gui->is_tab || !tabdone)
|
||||||
{
|
{
|
||||||
@@ -2598,6 +2622,7 @@ normalitem:
|
|||||||
mymenu[i].key,
|
mymenu[i].key,
|
||||||
mymenu[i].key == GDK_KEY_F1 ? 0 :
|
mymenu[i].key == GDK_KEY_F1 ? 0 :
|
||||||
mymenu[i].key == GDK_KEY_w ? close_mask :
|
mymenu[i].key == GDK_KEY_w ? close_mask :
|
||||||
|
mymenu[i].id == MENU_ID_AWAY ? away_mask :
|
||||||
(g_ascii_isupper (mymenu[i].key)) ?
|
(g_ascii_isupper (mymenu[i].key)) ?
|
||||||
STATE_SHIFT | STATE_CTRL :
|
STATE_SHIFT | STATE_CTRL :
|
||||||
STATE_CTRL,
|
STATE_CTRL,
|
||||||
|
|||||||
@@ -964,6 +964,9 @@ default_word_check(SexySpellEntry *entry, const gchar *word)
|
|||||||
/* We only want to check words */
|
/* We only want to check words */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_utf8_strlen (word, -1) > 20)
|
||||||
|
return FALSE;
|
||||||
for (li = entry->priv->dict_list; li; li = g_slist_next (li)) {
|
for (li = entry->priv->dict_list; li; li = g_slist_next (li)) {
|
||||||
struct EnchantDict *dict = (struct EnchantDict *) li->data;
|
struct EnchantDict *dict = (struct EnchantDict *) li->data;
|
||||||
if (enchant_dict_check(dict, word, strlen(word)) == 0) {
|
if (enchant_dict_check(dict, word, strlen(word)) == 0) {
|
||||||
@@ -1161,13 +1164,34 @@ check_color:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
attr_list_has_attrs (PangoAttrList *attrs)
|
||||||
|
{
|
||||||
|
PangoAttrIterator *it;
|
||||||
|
GSList *list;
|
||||||
|
gboolean has = FALSE;
|
||||||
|
|
||||||
|
if (!attrs)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
it = pango_attr_list_get_iterator (attrs);
|
||||||
|
if (!it)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
list = pango_attr_iterator_get_attrs (it);
|
||||||
|
has = (list != NULL);
|
||||||
|
g_slist_free_full (list, (GDestroyNotify) pango_attribute_destroy);
|
||||||
|
pango_attr_iterator_destroy (it);
|
||||||
|
|
||||||
|
return has;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sexy_spell_entry_recheck_all(SexySpellEntry *entry)
|
sexy_spell_entry_recheck_all(SexySpellEntry *entry)
|
||||||
{
|
{
|
||||||
GdkRectangle rect;
|
GdkRectangle rect;
|
||||||
GtkAllocation allocation;
|
GtkAllocation allocation;
|
||||||
GtkWidget *widget = GTK_WIDGET(entry);
|
GtkWidget *widget = GTK_WIDGET(entry);
|
||||||
PangoLayout *layout;
|
|
||||||
int length, i, text_len;
|
int length, i, text_len;
|
||||||
const char *text;
|
const char *text;
|
||||||
|
|
||||||
@@ -1196,8 +1220,7 @@ sexy_spell_entry_recheck_all(SexySpellEntry *entry)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
layout = gtk_entry_get_layout(GTK_ENTRY(entry));
|
gtk_entry_set_attributes (GTK_ENTRY (entry), attr_list_has_attrs (entry->priv->attr_list) ? entry->priv->attr_list : NULL);
|
||||||
pango_layout_set_attributes(layout, entry->priv->attr_list);
|
|
||||||
|
|
||||||
if (gtk_widget_get_realized (GTK_WIDGET(entry)))
|
if (gtk_widget_get_realized (GTK_WIDGET(entry)))
|
||||||
{
|
{
|
||||||
@@ -1213,13 +1236,6 @@ sexy_spell_entry_recheck_all(SexySpellEntry *entry)
|
|||||||
static gboolean
|
static gboolean
|
||||||
sexy_spell_entry_draw(GtkWidget *widget, cairo_t *cr)
|
sexy_spell_entry_draw(GtkWidget *widget, cairo_t *cr)
|
||||||
{
|
{
|
||||||
SexySpellEntry *entry = SEXY_SPELL_ENTRY(widget);
|
|
||||||
GtkEntry *gtk_entry = GTK_ENTRY(widget);
|
|
||||||
PangoLayout *layout;
|
|
||||||
|
|
||||||
layout = gtk_entry_get_layout(gtk_entry);
|
|
||||||
pango_layout_set_attributes(layout, entry->priv->attr_list);
|
|
||||||
|
|
||||||
return GTK_WIDGET_CLASS(parent_class)->draw (widget, cr);
|
return GTK_WIDGET_CLASS(parent_class)->draw (widget, cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ typedef struct
|
|||||||
guint16 bg_red;
|
guint16 bg_red;
|
||||||
guint16 bg_green;
|
guint16 bg_green;
|
||||||
guint16 bg_blue;
|
guint16 bg_blue;
|
||||||
|
guint16 sel_fg_red;
|
||||||
|
guint16 sel_fg_green;
|
||||||
|
guint16 sel_fg_blue;
|
||||||
|
guint16 sel_bg_red;
|
||||||
|
guint16 sel_bg_green;
|
||||||
|
guint16 sel_bg_blue;
|
||||||
} ThemeCssInputFingerprint;
|
} ThemeCssInputFingerprint;
|
||||||
|
|
||||||
static GtkCssProvider *theme_css_input_provider;
|
static GtkCssProvider *theme_css_input_provider;
|
||||||
@@ -92,6 +98,12 @@ theme_css_input_fingerprint_matches (const ThemeCssInputFingerprint *next)
|
|||||||
if (theme_css_input_fp.bg_red != next->bg_red || theme_css_input_fp.bg_green != next->bg_green
|
if (theme_css_input_fp.bg_red != next->bg_red || theme_css_input_fp.bg_green != next->bg_green
|
||||||
|| theme_css_input_fp.bg_blue != next->bg_blue)
|
|| theme_css_input_fp.bg_blue != next->bg_blue)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
if (theme_css_input_fp.sel_fg_red != next->sel_fg_red || theme_css_input_fp.sel_fg_green != next->sel_fg_green
|
||||||
|
|| theme_css_input_fp.sel_fg_blue != next->sel_fg_blue)
|
||||||
|
return FALSE;
|
||||||
|
if (theme_css_input_fp.sel_bg_red != next->sel_bg_red || theme_css_input_fp.sel_bg_green != next->sel_bg_green
|
||||||
|
|| theme_css_input_fp.sel_bg_blue != next->sel_bg_blue)
|
||||||
|
return FALSE;
|
||||||
if (g_strcmp0 (theme_css_input_fp.theme_name, next->theme_name) != 0)
|
if (g_strcmp0 (theme_css_input_fp.theme_name, next->theme_name) != 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (g_strcmp0 (theme_css_input_fp.font, next->font) != 0)
|
if (g_strcmp0 (theme_css_input_fp.font, next->font) != 0)
|
||||||
@@ -119,7 +131,9 @@ theme_css_input_fingerprint_clear (void)
|
|||||||
|
|
||||||
static char *
|
static char *
|
||||||
theme_css_build_input (const char *theme_name, guint16 fg_red, guint16 fg_green, guint16 fg_blue,
|
theme_css_build_input (const char *theme_name, guint16 fg_red, guint16 fg_green, guint16 fg_blue,
|
||||||
guint16 bg_red, guint16 bg_green, guint16 bg_blue)
|
guint16 bg_red, guint16 bg_green, guint16 bg_blue,
|
||||||
|
guint16 sel_fg_red, guint16 sel_fg_green, guint16 sel_fg_blue,
|
||||||
|
guint16 sel_bg_red, guint16 sel_bg_green, guint16 sel_bg_blue)
|
||||||
{
|
{
|
||||||
GString *css = g_string_new ("");
|
GString *css = g_string_new ("");
|
||||||
|
|
||||||
@@ -137,6 +151,11 @@ theme_css_build_input (const char *theme_name, guint16 fg_red, guint16 fg_green,
|
|||||||
"%s {"
|
"%s {"
|
||||||
"color: #%02x%02x%02x;"
|
"color: #%02x%02x%02x;"
|
||||||
"caret-color: #%02x%02x%02x;"
|
"caret-color: #%02x%02x%02x;"
|
||||||
|
"}"
|
||||||
|
"%s selection, %s text selection, %s:focus selection, %s:focus text selection, %s *:selected, %s *:selected:focus {"
|
||||||
|
"background-color: #%02x%02x%02x;"
|
||||||
|
"color: #%02x%02x%02x;"
|
||||||
|
"text-shadow: none;"
|
||||||
"}",
|
"}",
|
||||||
theme_css_selector_input,
|
theme_css_selector_input,
|
||||||
(bg_red >> 8), (bg_green >> 8), (bg_blue >> 8),
|
(bg_red >> 8), (bg_green >> 8), (bg_blue >> 8),
|
||||||
@@ -144,7 +163,15 @@ theme_css_build_input (const char *theme_name, guint16 fg_red, guint16 fg_green,
|
|||||||
(fg_red >> 8), (fg_green >> 8), (fg_blue >> 8),
|
(fg_red >> 8), (fg_green >> 8), (fg_blue >> 8),
|
||||||
theme_css_selector_input_text,
|
theme_css_selector_input_text,
|
||||||
(fg_red >> 8), (fg_green >> 8), (fg_blue >> 8),
|
(fg_red >> 8), (fg_green >> 8), (fg_blue >> 8),
|
||||||
(fg_red >> 8), (fg_green >> 8), (fg_blue >> 8));
|
(fg_red >> 8), (fg_green >> 8), (fg_blue >> 8),
|
||||||
|
theme_css_selector_input,
|
||||||
|
theme_css_selector_input,
|
||||||
|
theme_css_selector_input,
|
||||||
|
theme_css_selector_input,
|
||||||
|
theme_css_selector_input,
|
||||||
|
theme_css_selector_input,
|
||||||
|
(sel_bg_red >> 8), (sel_bg_green >> 8), (sel_bg_blue >> 8),
|
||||||
|
(sel_fg_red >> 8), (sel_fg_green >> 8), (sel_fg_blue >> 8));
|
||||||
|
|
||||||
return g_string_free (css, FALSE);
|
return g_string_free (css, FALSE);
|
||||||
}
|
}
|
||||||
@@ -177,6 +204,10 @@ theme_css_reload_input_style (gboolean enabled, const PangoFontDescription *font
|
|||||||
&next.fg_red, &next.fg_green, &next.fg_blue);
|
&next.fg_red, &next.fg_green, &next.fg_blue);
|
||||||
theme_palette_color_get_rgb16 (&style_values.background,
|
theme_palette_color_get_rgb16 (&style_values.background,
|
||||||
&next.bg_red, &next.bg_green, &next.bg_blue);
|
&next.bg_red, &next.bg_green, &next.bg_blue);
|
||||||
|
theme_palette_color_get_rgb16 (&style_values.selection_foreground,
|
||||||
|
&next.sel_fg_red, &next.sel_fg_green, &next.sel_fg_blue);
|
||||||
|
theme_palette_color_get_rgb16 (&style_values.selection_background,
|
||||||
|
&next.sel_bg_red, &next.sel_bg_green, &next.sel_bg_blue);
|
||||||
next.colors_set = TRUE;
|
next.colors_set = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +224,9 @@ theme_css_reload_input_style (gboolean enabled, const PangoFontDescription *font
|
|||||||
|
|
||||||
css = theme_css_build_input (theme_name ? theme_name : "",
|
css = theme_css_build_input (theme_name ? theme_name : "",
|
||||||
next.fg_red, next.fg_green, next.fg_blue,
|
next.fg_red, next.fg_green, next.fg_blue,
|
||||||
next.bg_red, next.bg_green, next.bg_blue);
|
next.bg_red, next.bg_green, next.bg_blue,
|
||||||
|
next.sel_fg_red, next.sel_fg_green, next.sel_fg_blue,
|
||||||
|
next.sel_bg_red, next.sel_bg_green, next.sel_bg_blue);
|
||||||
gtk_css_provider_load_from_data (theme_css_input_provider, css, -1, NULL);
|
gtk_css_provider_load_from_data (theme_css_input_provider, css, -1, NULL);
|
||||||
g_free (css);
|
g_free (css);
|
||||||
theme_css_apply_app_provider (GTK_STYLE_PROVIDER (theme_css_input_provider));
|
theme_css_apply_app_provider (GTK_STYLE_PROVIDER (theme_css_input_provider));
|
||||||
@@ -276,7 +309,7 @@ theme_css_apply_palette_widget (GtkWidget *widget, const GdkRGBA *bg, const GdkR
|
|||||||
if (fg)
|
if (fg)
|
||||||
g_string_append_printf (css, " color: %s;", fg_color);
|
g_string_append_printf (css, " color: %s;", fg_color);
|
||||||
g_string_append (css, " }");
|
g_string_append (css, " }");
|
||||||
g_string_append_printf (css, ".%s *:selected, .%s *:selected:focus, .%s *:selected:hover, .%s treeview.view:selected, .%s treeview.view:selected:focus, .%s treeview.view:selected:hover, .%s row:selected, .%s row:selected:focus, .%s row:selected:hover {", theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class);
|
g_string_append_printf (css, ".%s *:selected, .%s *:selected:focus, .%s *:selected:hover, .%s treeview.view:selected, .%s treeview.view:selected:focus, .%s treeview.view:selected:hover, .%s row:selected, .%s row:selected:focus, .%s row:selected:hover, .%s selection, .%s text selection, .%s entry selection, .%s entry text selection, .%s:focus selection, .%s:focus text selection {", theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class, theme_css_selector_palette_class);
|
||||||
if (sel_bg_color)
|
if (sel_bg_color)
|
||||||
g_string_append_printf (css, " background-color: %s;", sel_bg_color);
|
g_string_append_printf (css, " background-color: %s;", sel_bg_color);
|
||||||
else if (bg)
|
else if (bg)
|
||||||
|
|||||||
@@ -1132,25 +1132,12 @@ theme_preferences_create_color_page (GtkWindow *parent,
|
|||||||
static void
|
static void
|
||||||
theme_preferences_open_gtk3_folder_cb (GtkWidget *button, gpointer user_data)
|
theme_preferences_open_gtk3_folder_cb (GtkWidget *button, gpointer user_data)
|
||||||
{
|
{
|
||||||
theme_preferences_ui *ui = user_data;
|
|
||||||
GAppInfo *handler;
|
|
||||||
char *themes_dir;
|
char *themes_dir;
|
||||||
|
|
||||||
|
(void)user_data;
|
||||||
(void)button;
|
(void)button;
|
||||||
themes_dir = zoitechat_gtk3_theme_service_get_user_themes_dir ();
|
themes_dir = zoitechat_gtk3_theme_service_get_user_themes_dir ();
|
||||||
g_mkdir_with_parents (themes_dir, 0700);
|
g_mkdir_with_parents (themes_dir, 0700);
|
||||||
|
|
||||||
handler = g_app_info_get_default_for_uri_scheme ("file");
|
|
||||||
if (!handler)
|
|
||||||
{
|
|
||||||
theme_preferences_show_message (ui,
|
|
||||||
GTK_MESSAGE_ERROR,
|
|
||||||
_("No application is configured to open folders."));
|
|
||||||
g_free (themes_dir);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_unref (handler);
|
|
||||||
fe_open_url (themes_dir);
|
fe_open_url (themes_dir);
|
||||||
g_free (themes_dir);
|
g_free (themes_dir);
|
||||||
}
|
}
|
||||||
@@ -1405,26 +1392,34 @@ theme_preferences_populate_gtk3 (theme_preferences_ui *ui)
|
|||||||
g_ptr_array_unref (themes);
|
g_ptr_array_unref (themes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
theme_preferences_gtk3_import_path (theme_preferences_ui *ui, char *path)
|
||||||
|
{
|
||||||
|
char *id = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!zoitechat_gtk3_theme_service_import (path, &id, &error))
|
||||||
|
theme_preferences_show_message (ui, GTK_MESSAGE_ERROR,
|
||||||
|
error ? error->message : _("Failed to import GTK3 theme."));
|
||||||
|
g_clear_error (&error);
|
||||||
|
g_free (id);
|
||||||
|
g_free (path);
|
||||||
|
theme_preferences_populate_gtk3 (ui);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
theme_preferences_gtk3_import_cb (GtkWidget *button, gpointer user_data)
|
theme_preferences_gtk3_import_cb (GtkWidget *button, gpointer user_data)
|
||||||
{
|
{
|
||||||
theme_preferences_ui *ui = user_data;
|
theme_preferences_ui *ui = user_data;
|
||||||
GtkWidget *dialog;
|
GtkFileChooserNative *dialog;
|
||||||
GtkFileFilter *filter;
|
GtkFileFilter *filter;
|
||||||
GtkWidget *folder_dialog;
|
|
||||||
char *path;
|
char *path;
|
||||||
char *id = NULL;
|
|
||||||
GError *error = NULL;
|
|
||||||
gint response;
|
|
||||||
|
|
||||||
(void)button;
|
(void)button;
|
||||||
dialog = gtk_file_chooser_dialog_new (_("Import GTK3 Theme"), ui->parent,
|
dialog = gtk_file_chooser_native_new (_("Import GTK3 Theme"), ui->parent,
|
||||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
_("Import _Folder"), 1,
|
_("_Import"),
|
||||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
_("_Cancel"));
|
||||||
_("_Import"), GTK_RESPONSE_ACCEPT,
|
|
||||||
NULL);
|
|
||||||
theme_manager_attach_window (dialog);
|
|
||||||
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), TRUE);
|
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), TRUE);
|
||||||
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), FALSE);
|
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dialog), FALSE);
|
||||||
filter = gtk_file_filter_new ();
|
filter = gtk_file_filter_new ();
|
||||||
@@ -1439,43 +1434,15 @@ theme_preferences_gtk3_import_cb (GtkWidget *button, gpointer user_data)
|
|||||||
gtk_file_filter_add_pattern (filter, "*.tbz");
|
gtk_file_filter_add_pattern (filter, "*.tbz");
|
||||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
|
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
|
||||||
|
|
||||||
response = gtk_dialog_run (GTK_DIALOG (dialog));
|
if (gtk_native_dialog_run (GTK_NATIVE_DIALOG (dialog)) != GTK_RESPONSE_ACCEPT)
|
||||||
if (response == 1)
|
|
||||||
{
|
{
|
||||||
gtk_widget_destroy (dialog);
|
g_object_unref (dialog);
|
||||||
folder_dialog = gtk_file_chooser_dialog_new (_("Import GTK3 Theme Folder"), ui->parent,
|
|
||||||
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
|
||||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
|
||||||
_("_Import"), GTK_RESPONSE_ACCEPT,
|
|
||||||
NULL);
|
|
||||||
theme_manager_attach_window (folder_dialog);
|
|
||||||
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (folder_dialog), TRUE);
|
|
||||||
if (gtk_dialog_run (GTK_DIALOG (folder_dialog)) != GTK_RESPONSE_ACCEPT)
|
|
||||||
{
|
|
||||||
gtk_widget_destroy (folder_dialog);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (folder_dialog));
|
|
||||||
gtk_widget_destroy (folder_dialog);
|
|
||||||
}
|
|
||||||
else if (response == GTK_RESPONSE_ACCEPT)
|
|
||||||
{
|
|
||||||
path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
||||||
gtk_widget_destroy (dialog);
|
g_object_unref (dialog);
|
||||||
}
|
theme_preferences_gtk3_import_path (ui, path);
|
||||||
else
|
|
||||||
{
|
|
||||||
gtk_widget_destroy (dialog);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!zoitechat_gtk3_theme_service_import (path, &id, &error))
|
|
||||||
theme_preferences_show_message (ui, GTK_MESSAGE_ERROR,
|
|
||||||
error ? error->message : _("Failed to import GTK3 theme."));
|
|
||||||
g_clear_error (&error);
|
|
||||||
g_free (path);
|
|
||||||
theme_preferences_populate_gtk3 (ui);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -52,6 +52,29 @@ enum
|
|||||||
|
|
||||||
static void userlist_store_color (GtkListStore *store, GtkTreeIter *iter, ThemeSemanticToken token, gboolean has_token);
|
static void userlist_store_color (GtkListStore *store, GtkTreeIter *iter, ThemeSemanticToken token, gboolean has_token);
|
||||||
|
|
||||||
|
static void
|
||||||
|
userlist_update_min_width (session *sess)
|
||||||
|
{
|
||||||
|
GtkRequisition minimum;
|
||||||
|
GtkRequisition natural;
|
||||||
|
GtkWidget *scrolled_window;
|
||||||
|
int width;
|
||||||
|
|
||||||
|
if (!sess || !sess->gui || !sess->gui->user_box || !sess->gui->namelistinfo || !sess->gui->user_tree)
|
||||||
|
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);
|
||||||
|
if (GTK_IS_SCROLLED_WINDOW (scrolled_window))
|
||||||
|
gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (scrolled_window), width);
|
||||||
|
gtk_widget_set_size_request (sess->gui->user_tree, width, -1);
|
||||||
|
gtk_widget_set_size_request (sess->gui->user_box, width, -1);
|
||||||
|
}
|
||||||
|
|
||||||
GdkPixbuf *
|
GdkPixbuf *
|
||||||
get_user_icon (server *serv, struct User *user)
|
get_user_icon (server *serv, struct User *user)
|
||||||
{
|
{
|
||||||
@@ -110,9 +133,11 @@ fe_userlist_numbers (session *sess)
|
|||||||
g_snprintf (tbuf, sizeof (tbuf), _("%d ops, %d total"), sess->ops, sess->total);
|
g_snprintf (tbuf, sizeof (tbuf), _("%d ops, %d total"), sess->ops, sess->total);
|
||||||
tbuf[sizeof (tbuf) - 1] = 0;
|
tbuf[sizeof (tbuf) - 1] = 0;
|
||||||
gtk_label_set_text (GTK_LABEL (sess->gui->namelistinfo), tbuf);
|
gtk_label_set_text (GTK_LABEL (sess->gui->namelistinfo), tbuf);
|
||||||
|
userlist_update_min_width (sess);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
gtk_label_set_text (GTK_LABEL (sess->gui->namelistinfo), NULL);
|
gtk_label_set_text (GTK_LABEL (sess->gui->namelistinfo), NULL);
|
||||||
|
userlist_update_min_width (sess);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sess->type == SESS_CHANNEL && prefs.hex_gui_win_ucount)
|
if (sess->type == SESS_CHANNEL && prefs.hex_gui_win_ucount)
|
||||||
@@ -662,6 +687,7 @@ static void
|
|||||||
userlist_add_columns (GtkTreeView * treeview)
|
userlist_add_columns (GtkTreeView * treeview)
|
||||||
{
|
{
|
||||||
GtkCellRenderer *renderer;
|
GtkCellRenderer *renderer;
|
||||||
|
GtkTreeViewColumn *column;
|
||||||
|
|
||||||
/* icon column */
|
/* icon column */
|
||||||
renderer = gtk_cell_renderer_pixbuf_new ();
|
renderer = gtk_cell_renderer_pixbuf_new ();
|
||||||
@@ -670,15 +696,22 @@ userlist_add_columns (GtkTreeView * treeview)
|
|||||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
||||||
-1, NULL, renderer,
|
-1, NULL, renderer,
|
||||||
"pixbuf", 0, NULL);
|
"pixbuf", 0, NULL);
|
||||||
|
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 0);
|
||||||
|
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
|
||||||
|
|
||||||
/* nick column */
|
/* nick column */
|
||||||
renderer = gtk_cell_renderer_text_new ();
|
renderer = gtk_cell_renderer_text_new ();
|
||||||
if (prefs.hex_gui_compact)
|
if (prefs.hex_gui_compact)
|
||||||
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
||||||
|
g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
||||||
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
||||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
||||||
-1, NULL, renderer,
|
-1, NULL, renderer,
|
||||||
"text", 1, THEME_GTK_FOREGROUND_PROPERTY, 4, NULL);
|
"text", 1, THEME_GTK_FOREGROUND_PROPERTY, 4, NULL);
|
||||||
|
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 1);
|
||||||
|
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
|
||||||
|
gtk_tree_view_column_set_expand (column, TRUE);
|
||||||
|
gtk_tree_view_column_set_min_width (column, 1);
|
||||||
|
|
||||||
if (prefs.hex_gui_ulist_show_hosts)
|
if (prefs.hex_gui_ulist_show_hosts)
|
||||||
{
|
{
|
||||||
@@ -686,10 +719,15 @@ userlist_add_columns (GtkTreeView * treeview)
|
|||||||
renderer = gtk_cell_renderer_text_new ();
|
renderer = gtk_cell_renderer_text_new ();
|
||||||
if (prefs.hex_gui_compact)
|
if (prefs.hex_gui_compact)
|
||||||
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
g_object_set (G_OBJECT (renderer), "ypad", 0, NULL);
|
||||||
|
g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
||||||
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
|
||||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
|
||||||
-1, NULL, renderer,
|
-1, NULL, renderer,
|
||||||
"text", 2, NULL);
|
"text", 2, NULL);
|
||||||
|
column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 2);
|
||||||
|
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
|
||||||
|
gtk_tree_view_column_set_expand (column, TRUE);
|
||||||
|
gtk_tree_view_column_set_min_width (column, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
;#define APPARCH "x64"
|
;#define APPARCH "x64"
|
||||||
;#define PROJECTDIR "C:\...\zoitechat\win32\installer\"
|
;#define PROJECTDIR "C:\...\zoitechat\win32\installer\"
|
||||||
|
|
||||||
;http://mitrich.net23.net/?/inno-download-plugin.html
|
|
||||||
#ifexist "idp.iss"
|
|
||||||
#define USE_INNO_DOWNLOAD_PLUGIN
|
|
||||||
#include <idp.iss>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppName=ZoiteChat
|
AppName=ZoiteChat
|
||||||
AppVersion={#APPVER}
|
AppVersion={#APPVER}
|
||||||
@@ -65,8 +59,8 @@ Name: "plugins\upd"; Description: "Update Checker"; Types: normal custom; Flags:
|
|||||||
Name: "plugins\winamp"; Description: "Winamp"; Types: custom; Flags: disablenouninstallwarning
|
Name: "plugins\winamp"; Description: "Winamp"; Types: custom; Flags: disablenouninstallwarning
|
||||||
Name: "langs"; Description: "Language Interfaces"; Types: custom; Flags: disablenouninstallwarning
|
Name: "langs"; Description: "Language Interfaces"; Types: custom; Flags: disablenouninstallwarning
|
||||||
Name: "langs\lua"; Description: "Lua"; Types: normal custom; Flags: disablenouninstallwarning
|
Name: "langs\lua"; Description: "Lua"; Types: normal custom; Flags: disablenouninstallwarning
|
||||||
Name: "langs\perl"; Description: "Perl (requires Perl 5.20)"; Types: custom; Flags: disablenouninstallwarning
|
Name: "langs\perl"; Description: "Perl (requires Perl 5.42)"; Types: custom; Flags: disablenouninstallwarning
|
||||||
Name: "langs\python"; Description: "Python (requires Python 3.14.2)"; Types: custom; Flags: disablenouninstallwarning
|
Name: "langs\python"; Description: "Python (requires Python 3.14.3)"; Types: custom; Flags: disablenouninstallwarning
|
||||||
|
|
||||||
[Tasks]
|
[Tasks]
|
||||||
Name: portable; Description: "Yes"; GroupDescription: "Portable Mode: Stores configuration files within install directory for portable drives."; Flags: unchecked
|
Name: portable; Description: "Yes"; GroupDescription: "Portable Mode: Stores configuration files within install directory for portable drives."; Flags: unchecked
|
||||||
@@ -282,8 +276,8 @@ begin
|
|||||||
begin
|
begin
|
||||||
|
|
||||||
REDIST := 'https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.16.2/vcredist_2015_x64.exe';
|
REDIST := 'https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.16.2/vcredist_2015_x64.exe';
|
||||||
PERL := 'https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.16.2/Perl.5.20.0.x64.msi';
|
PERL := 'https://github.com/StrawberryPerl/Perl-Dist-Strawberry/releases/download/SP_54201_64bit/strawberry-perl-5.42.0.1-64bit.msi';
|
||||||
PY3 := 'https://www.python.org/ftp/python/3.14.2/python-3.14.2-amd64.exe';
|
PY3 := 'https://www.python.org/ftp/python/3.14.3/python-3.14.3-amd64.exe';
|
||||||
SPELL := 'https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.16.2/ZoiteChat.Spelling.Dictionaries.r2.exe';
|
SPELL := 'https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.16.2/ZoiteChat.Spelling.Dictionaries.r2.exe';
|
||||||
|
|
||||||
if not CheckVCInstall() then
|
if not CheckVCInstall() then
|
||||||
@@ -294,7 +288,7 @@ begin
|
|||||||
|
|
||||||
if not WizardSilent() then
|
if not WizardSilent() then
|
||||||
begin
|
begin
|
||||||
if IsComponentSelected('langs\perl') and not CheckDLL('perl520.dll') then
|
if IsComponentSelected('langs\perl') and not CheckDLL('perl542.dll') then
|
||||||
begin
|
begin
|
||||||
idpAddFile(PERL, ExpandConstant('{tmp}\perl.msi'))
|
idpAddFile(PERL, ExpandConstant('{tmp}\perl.msi'))
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.18.0~pre3
|
2.18.0~pre4
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<YourDepsPath>c:\gtk-build\gtk</YourDepsPath>
|
<YourDepsPath>c:\gtk-build\gtk</YourDepsPath>
|
||||||
<YourGendefPath>c:\gtk-build\gendef</YourGendefPath>
|
<YourGendefPath>c:\gtk-build\gendef</YourGendefPath>
|
||||||
<YourPerlPath>c:\gtk-build\perl-5.20</YourPerlPath>
|
<YourPerlPath>c:\gtk-build\perl-5.42.0.1</YourPerlPath>
|
||||||
<YourPython3Path>c:\gtk-build\python-3.14</YourPython3Path>
|
<YourPython3Path>c:\gtk-build\python-3.14</YourPython3Path>
|
||||||
<YourWinSparklePath>c:\gtk-build\WinSparkle</YourWinSparklePath>
|
<YourWinSparklePath>c:\gtk-build\WinSparkle</YourWinSparklePath>
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<GendefPath>$(YourGendefPath)</GendefPath>
|
<GendefPath>$(YourGendefPath)</GendefPath>
|
||||||
<WinSparklePath>$(YourWinSparklePath)\$(ZoiteChatPlatform)</WinSparklePath>
|
<WinSparklePath>$(YourWinSparklePath)\$(ZoiteChatPlatform)</WinSparklePath>
|
||||||
<PerlPath>$(YourPerlPath)\$(ZoiteChatPlatform)</PerlPath>
|
<PerlPath>$(YourPerlPath)\$(ZoiteChatPlatform)</PerlPath>
|
||||||
<PerlLib>perl520</PerlLib>
|
<PerlLib>perl542</PerlLib>
|
||||||
|
|
||||||
<Python3Path>$(YourPython3Path)\$(ZoiteChatPlatform)</Python3Path>
|
<Python3Path>$(YourPython3Path)\$(ZoiteChatPlatform)</Python3Path>
|
||||||
<Python3Lib>python314</Python3Lib>
|
<Python3Lib>python314</Python3Lib>
|
||||||
|
|||||||
Reference in New Issue
Block a user