diff --git a/.github/workflows/appimage-build.yml b/.github/workflows/appimage-build.yml index d268669d..36e49518 100644 --- a/.github/workflows/appimage-build.yml +++ b/.github/workflows/appimage-build.yml @@ -29,9 +29,11 @@ jobs: build-essential pkg-config meson ninja-build cmake \ gettext \ libcanberra-dev libdbus-glib-1-dev libglib2.0-dev \ - libgtk2.0-dev libgtk-3-dev \ + libgtk-3-dev \ + libwayland-client0 libwayland-cursor0 libwayland-egl1 \ + libxkbcommon0 \ libgtk-3-bin libglib2.0-bin shared-mime-info gsettings-desktop-schemas \ - libluajit-5.1-dev libpci-dev libperl-dev libssl-dev \ + libluajit-5.1-dev libpci-dev libperl-dev libssl-dev libayatana-appindicator3-dev \ python3-dev python3-cffi mono-devel desktop-file-utils \ patchelf file curl @@ -41,6 +43,7 @@ jobs: rm -rf build meson setup build \ --prefix=/usr \ + -Dgtk3=true \ -Dtext-frontend=true \ -Dwith-perl=perl \ -Dwith-python=python3 \ @@ -74,11 +77,9 @@ jobs: chmod +x linuxdeploy-plugin-gtk export PATH="${PWD}:${PATH}" - # Bundle CA certificates into the AppDir install -Dm644 /etc/ssl/certs/ca-certificates.crt \ AppDir/etc/ssl/certs/ca-certificates.crt - # Custom AppRun: preserve typical AppDir runtime paths AND force CA bundle cat > AppRun <<'EOF' #!/bin/sh set -eu @@ -99,15 +100,26 @@ jobs: export GIO_EXTRA_MODULES="$APPDIR/usr/lib/gio/modules${GIO_EXTRA_MODULES:+:$GIO_EXTRA_MODULES}" fi - # OpenSSL trust store override (fixes “unable to get local issuer certificate (20)”) + # OpenSSL trust store override export SSL_CERT_FILE="${SSL_CERT_FILE:-$APPDIR/etc/ssl/certs/ca-certificates.crt}" export SSL_CERT_DIR="${SSL_CERT_DIR:-$APPDIR/etc/ssl/certs}" export CURL_CA_BUNDLE="${CURL_CA_BUNDLE:-$SSL_CERT_FILE}" + # Prefer Wayland if the session provides it, but keep X11 fallback. + # Don't override if the user already set GDK_BACKEND explicitly. + if [ -z "${GDK_BACKEND:-}" ]; then + if [ -n "${WAYLAND_DISPLAY:-}" ] || [ "${XDG_SESSION_TYPE:-}" = "wayland" ]; then + export GDK_BACKEND="wayland,x11" + else + export GDK_BACKEND="x11" + fi + fi + exec "$APPDIR/usr/bin/zoitechat" "$@" EOF chmod +x AppRun + VERSION="$(git describe --tags --always)" ./linuxdeploy-x86_64.AppImage \ diff --git a/.github/workflows/debian-build.yml b/.github/workflows/debian-build.yml index defdf7c5..dc8f312f 100644 --- a/.github/workflows/debian-build.yml +++ b/.github/workflows/debian-build.yml @@ -13,47 +13,36 @@ jobs: image: debian:bookworm steps: - - name: Install base tooling (git + deps) + - name: Install packaging tooling and build dependencies run: | set -eux export DEBIAN_FRONTEND=noninteractive apt-get update apt-get install -y --no-install-recommends \ git ca-certificates \ - build-essential pkg-config meson ninja-build cmake \ - gettext \ - libcanberra-dev libdbus-glib-1-dev libglib2.0-dev libgtk2.0-dev \ - libluajit-5.1-dev libpci-dev libperl-dev libssl-dev \ - python3-dev python3-cffi mono-devel desktop-file-utils + build-essential dpkg-dev debhelper fakeroot \ + pkg-config meson ninja-build \ + gettext iso-codes \ + libcanberra-dev libdbus-glib-1-dev libglib2.0-dev libgtk-3-dev libayatana-appindicator3-dev \ + liblua5.3-dev libpci-dev libperl-dev libssl-dev \ + python3-dev python3-cffi desktop-file-utils - uses: actions/checkout@v4 with: submodules: true - - name: Configure + - name: Build Debian packages run: | set -eux - rm -rf build - meson setup build \ - -Dtext-frontend=true \ - -Dauto_features=enabled - # If configure fails, show the project's actual option names in the log. - - name: Show Meson options (on failure) - if: failure() - run: | - set -eux - meson configure build || true + dpkg-buildpackage -us -uc -b - - name: Build + - name: Collect Debian artifacts run: | set -eux - ninja -C build + mkdir -p artifacts + cp -v ../*.deb ../*.changes ../*.buildinfo artifacts/ - - name: Test - run: | - set -eux - ninja -C build test - - - name: Install - run: | - set -eux - ninja -C build install + - name: Upload Debian artifacts + uses: actions/upload-artifact@v4 + with: + name: zoitechat-debian-packages + path: artifacts/* diff --git a/.github/workflows/openbsd-build.yml b/.github/workflows/openbsd-build.yml index 73f430a0..23238adc 100644 --- a/.github/workflows/openbsd-build.yml +++ b/.github/workflows/openbsd-build.yml @@ -32,7 +32,7 @@ jobs: git \ meson ninja pkgconf gmake \ gettext-tools \ - glib2 gtk+2 dbus-glib libcanberra \ + glib2 gtk+3 dbus-glib libcanberra \ luajit mono libgdiplus openssl work="$(mktemp -d /tmp/zoitechat.XXXXXX)" @@ -45,6 +45,7 @@ jobs: meson setup build \ --prefix=/usr/local \ -Dtext-frontend=true \ + -Dgtk3=true \ -Dplugin=false \ -Dauto_features=enabled diff --git a/.github/workflows/solus-eopkg-build.yml b/.github/workflows/solus-eopkg-build.yml new file mode 100644 index 00000000..d2cfc1b5 --- /dev/null +++ b/.github/workflows/solus-eopkg-build.yml @@ -0,0 +1,60 @@ +name: Solus eopkg build + +on: + workflow_dispatch: + inputs: + package_yml: + description: "Path to Solus package.yml for ypkg build" + required: false + default: "packaging/solus/package.yml" + solus_image: + description: "Solus container image" + required: false + default: "ghcr.io/getsolus/solus:latest" + push: + branches: + - main + - master + +jobs: + build-eopkg: + runs-on: ubuntu-latest + env: + SOLUS_IMAGE: ${{ inputs.solus_image || 'ghcr.io/getsolus/solus:latest' }} + PACKAGE_YML: ${{ inputs.package_yml || 'packaging/solus/package.yml' }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Build eopkg package in Solus container + run: | + if [ ! -f "$PACKAGE_YML" ]; then + echo "Expected Solus packaging file at $PACKAGE_YML" >&2 + echo "Available package.yml files:" >&2 + find . -name "package.yml" -print >&2 || true + echo "Add a package.yml (ypkg) file or update the workflow input PACKAGE_YML." >&2 + exit 1 + fi + + docker pull "$SOLUS_IMAGE" + + docker run --rm \ + -v "$PWD":/workspace \ + -w /workspace \ + -e PACKAGE_YML="$PACKAGE_YML" \ + "$SOLUS_IMAGE" \ + sh -lc ' + set -euo pipefail + eopkg update-repo -y + eopkg install -y ypkg git + ypkg build "$PACKAGE_YML" + mkdir -p /workspace/artifacts + find . -maxdepth 3 -name "*.eopkg" -type f -exec cp -v {} /workspace/artifacts/ \; + ' + + - name: Upload eopkg artifacts + uses: actions/upload-artifact@v4 + with: + name: solus-eopkg + path: artifacts/*.eopkg + if-no-files-found: error diff --git a/.github/workflows/windows-build.yml b/.github/workflows/windows-build.yml index 0e835b16..7ea8f67f 100644 --- a/.github/workflows/windows-build.yml +++ b/.github/workflows/windows-build.yml @@ -10,7 +10,7 @@ on: jobs: windows_build: - runs-on: windows-2019 + runs-on: windows-2022 permissions: contents: read @@ -20,13 +20,8 @@ jobs: strategy: matrix: - platform: [x64, win32] - arch: [x64, x86] - exclude: - - platform: x64 - arch: x86 - - platform: win32 - arch: x64 + platform: [x64] + arch: [x64] fail-fast: false steps: @@ -39,16 +34,16 @@ jobs: - name: Install Dependencies run: | - New-Item -Name "deps" -ItemType "Directory" + New-Item -Name "deps" -ItemType "Directory" -Force | Out-Null - Invoke-WebRequest http://files.jrsoftware.org/is/5/innosetup-5.5.9-unicode.exe -OutFile deps\innosetup-unicode.exe + Invoke-WebRequest https://files.jrsoftware.org/is/6/innosetup-6.7.0.exe -OutFile deps\innosetup-unicode.exe & deps\innosetup-unicode.exe /VERYSILENT | Out-Null Invoke-WebRequest https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.17.0/idpsetup-1.5.1.exe -OutFile deps\idpsetup.exe & deps\idpsetup.exe /VERYSILENT - Invoke-WebRequest https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.17.0/gtk-${{ matrix.platform }}-2018-08-29-openssl1.1.7z -OutFile deps\gtk-${{ matrix.arch }}.7z - & 7z.exe x deps\gtk-${{ matrix.arch }}.7z -oC:\gtk-build\gtk + Invoke-WebRequest 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 Invoke-WebRequest https://github.com/zoitechat/gvsbuild/releases/download/zoitechat-2.17.0/gendef-20111031.7z -OutFile deps\gendef.7z & 7z.exe x deps\gendef.7z -oC:\gtk-build @@ -76,7 +71,7 @@ jobs: - name: Build run: | - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\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 }}" if not exist "%PYTHON_DIR%\libs\python314.lib" ( @@ -93,7 +88,7 @@ jobs: - name: Preparing Artifacts run: | - move ..\zoitechat-build\${{ matrix.platform }}\ZoiteChat*.exe .\ + move ..\zoitechat-build\${{ matrix.platform }}\ZoiteChat-*.exe .\ move ..\zoitechat-build .\ shell: cmd @@ -102,7 +97,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: Installer ${{ matrix.arch }} - path: ZoiteChat*.exe + path: ZoiteChat-*.exe - name: Attest Installer (Artifact Attestation) if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} diff --git a/changelog.rst b/changelog.rst index 586cc8a5..ff58bd7f 100644 --- a/changelog.rst +++ b/changelog.rst @@ -1,6 +1,15 @@ ZoiteChat ChangeLog ================= +2.18.0-pre1 (2026-02-16) +------------------------ + +- Switched Debian packaging/builds to GTK 3 (Build-Depends, Meson flags, and package metadata). +- Added Debian package split install manifests so files are assigned to the correct binary packages. +- Fixed Debian packaging coverage for the man page and MIME XML to avoid unassigned-file (dh_missing) failures. +- Updated Debian CI packaging workflow and artifact upload paths for actions/upload-artifact@v4 compatibility. +- Improved GTK3 font consistency by applying the configured input font to channel tree and user list theming paths. + 2.17.4 (2026-02-03) ------------------- diff --git a/data/misc/net.zoite.Zoitechat.appdata.xml.in b/data/misc/net.zoite.Zoitechat.appdata.xml.in index c030cdd2..8c3280d6 100644 --- a/data/misc/net.zoite.Zoitechat.appdata.xml.in +++ b/data/misc/net.zoite.Zoitechat.appdata.xml.in @@ -25,6 +25,18 @@ zoitechat.desktop + + +

Packaging and GTK3 improvements:

+
    +
  • Switched Debian package builds to GTK 3.
  • +
  • Added split-package install manifests for Debian outputs.
  • +
  • Fixed unassigned Debian package files (man page and MIME XML).
  • +
  • Updated Debian CI artifact upload handling for GitHub Actions v4.
  • +
  • Improved GTK3 channel/user list font consistency when applying theme updates.
  • +
+
+

Fixes and minor features:

diff --git a/data/misc/net.zoite.Zoitechat.desktop.in.in b/data/misc/net.zoite.Zoitechat.desktop.in.in index 26efc8f6..ecbb1678 100644 --- a/data/misc/net.zoite.Zoitechat.desktop.in.in +++ b/data/misc/net.zoite.Zoitechat.desktop.in.in @@ -9,7 +9,7 @@ Terminal=false Type=Application Categories=GTK;Network;IRCClient; StartupNotify=true -StartupWMClass=Zoitechat +StartupWMClass=net.zoite.Zoitechat X-GNOME-UsesNotifications=true MimeType=x-scheme-handler/irc;x-scheme-handler/ircs;application/x-zoitechat-theme;application/x-hexchat-theme; Actions=SafeMode; diff --git a/debian/changelog b/debian/changelog index f20cafb0..6faf5f95 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,23 @@ +zoitechat (2.18.0~pre1-1) unstable; urgency=medium + + * New upstream pre-release 2.18.0~pre1. + * Debian packaging updates in this branch: + - switch package builds to GTK 3 and pass -Dgtk3=true to Meson. + - add/install split-package manifests for generated binary packages. + - include manpage and MIME package XML in package installs. + - adjust CI artifact staging/upload paths for actions/upload-artifact@v4. + + -- ZoiteChat Maintainers Sun, 16 Feb 2026 00:00:00 +0000 + +zoitechat (2.17.0-1) unstable; urgency=medium + + * Switch Debian build to GTK 3 packaging: + - replace libgtk2.0-dev with libgtk-3-dev in Build-Depends. + - pass -Dgtk3=true to Meson during package builds. + - update package description to explicitly reference GTK 3. + + -- ZoiteChat Maintainers Sun, 16 Feb 2026 00:00:00 +0000 + zoitechat (2.17.0-0) stable; urgency=medium * Initial ZoiteChat packaging (forked from HexChat's Debian packaging). diff --git a/debian/control b/debian/control index 9ebf28fc..8bbc1d49 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Build-Depends: libcanberra-dev, libdbus-glib-1-dev, libglib2.0-dev, - libgtk2.0-dev, + libgtk-3-dev, liblua5.3-dev, libpci-dev, libperl-dev, @@ -39,8 +39,8 @@ Suggests: zoitechat-python3, zoitechat-otr, unifont -Description: IRC client for GNOME (fork of HexChat 2.17.0 base) - ZoiteChat is a graphical IRC client with a GTK+ GUI. Features include Python, +Description: IRC client for GNOME (fork of HexChat 2.18.0-pre1 base) + ZoiteChat is a graphical IRC client with a GTK 3 GUI. Features include Python, Perl and Lua scripting support, a plugin API, multiple server/channel windows, spell checking, multiple authentication methods including SASL, and customizable notifications. For more information on IRC, see diff --git a/debian/rules b/debian/rules index 51fce4d1..32b15279 100755 --- a/debian/rules +++ b/debian/rules @@ -7,8 +7,17 @@ export DH_VERBOSE=1 override_dh_auto_configure: dh_auto_configure -- \ + -Dgtk3=true \ -Dinstall-plugin-metainfo=false \ -Dwith-lua=lua53 override_dh_installchangelogs: - dh_installchangelogs debian/changelog.txt + install -m0755 -d \ + debian/zoitechat/usr/share/doc/zoitechat \ + debian/zoitechat-common/usr/share/doc/zoitechat-common \ + debian/zoitechat-perl/usr/share/doc/zoitechat-perl \ + debian/zoitechat-python3/usr/share/doc/zoitechat-python3 \ + debian/zoitechat-lua/usr/share/doc/zoitechat-lua \ + debian/zoitechat-plugins/usr/share/doc/zoitechat-plugins \ + debian/zoitechat-dev/usr/share/doc/zoitechat-dev + dh_installchangelogs changelog.rst diff --git a/debian/zoitechat-common.install b/debian/zoitechat-common.install new file mode 100644 index 00000000..ead106bb --- /dev/null +++ b/debian/zoitechat-common.install @@ -0,0 +1,7 @@ +usr/share/applications/net.zoite.Zoitechat.desktop +usr/share/dbus-1/services/org.zoitechat.service.service +usr/share/icons/hicolor/48x48/apps/net.zoite.Zoitechat.png +usr/share/icons/hicolor/scalable/apps/net.zoite.Zoitechat.svg +usr/share/locale/*/LC_MESSAGES/zoitechat.mo +usr/share/metainfo/net.zoite.Zoitechat.appdata.xml +usr/share/mime/packages/net.zoite.Zoitechat.mime.xml diff --git a/debian/zoitechat-dev.install b/debian/zoitechat-dev.install new file mode 100644 index 00000000..241521a0 --- /dev/null +++ b/debian/zoitechat-dev.install @@ -0,0 +1,2 @@ +usr/include/zoitechat-plugin.h +usr/lib/*/pkgconfig/zoitechat-plugin.pc diff --git a/debian/zoitechat-lua.install b/debian/zoitechat-lua.install new file mode 100644 index 00000000..67f1a7a2 --- /dev/null +++ b/debian/zoitechat-lua.install @@ -0,0 +1 @@ +usr/lib/*/zoitechat/plugins/lua.so diff --git a/debian/zoitechat-perl.install b/debian/zoitechat-perl.install new file mode 100644 index 00000000..66ef1f87 --- /dev/null +++ b/debian/zoitechat-perl.install @@ -0,0 +1 @@ +usr/lib/*/zoitechat/plugins/perl.so diff --git a/debian/zoitechat-plugins.install b/debian/zoitechat-plugins.install new file mode 100644 index 00000000..23786ab0 --- /dev/null +++ b/debian/zoitechat-plugins.install @@ -0,0 +1,3 @@ +usr/lib/*/zoitechat/plugins/checksum.so +usr/lib/*/zoitechat/plugins/fishlim.so +usr/lib/*/zoitechat/plugins/sysinfo.so diff --git a/debian/zoitechat-python3.install b/debian/zoitechat-python3.install new file mode 100644 index 00000000..a82457d3 --- /dev/null +++ b/debian/zoitechat-python3.install @@ -0,0 +1,4 @@ +usr/lib/*/zoitechat/plugins/python.so +usr/lib/*/zoitechat/python/_zoitechat.py +usr/lib/*/zoitechat/python/xchat.py +usr/lib/*/zoitechat/python/zoitechat.py diff --git a/debian/zoitechat.install b/debian/zoitechat.install index 56bd72ef..32e2a8f6 100644 --- a/debian/zoitechat.install +++ b/debian/zoitechat.install @@ -1,3 +1,2 @@ usr/bin/zoitechat -usr/share/applications -usr/share/metainfo/net.zoite.Zoitechat.appdata.xml +usr/share/man/man1/zoitechat.1 diff --git a/flatpak/net.zoite.Zoitechat.json b/flatpak/net.zoite.Zoitechat.json index cc9e0631..154e4e16 100644 --- a/flatpak/net.zoite.Zoitechat.json +++ b/flatpak/net.zoite.Zoitechat.json @@ -7,7 +7,7 @@ "command": "zoitechat", "finish-args": [ "--share=ipc", - "--socket=x11", + "--socket=wayland", "--share=network", "--socket=pulseaudio", "--filesystem=xdg-download", @@ -28,11 +28,10 @@ } }, "modules": [ - "shared-modules/gtk2/gtk2.json", - "shared-modules/gtk2/gtk2-common-themes.json", "shared-modules/dbus-glib/dbus-glib.json", "shared-modules/lua5.3/lua-5.3.5.json", "shared-modules/libcanberra/libcanberra.json", + "shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json", "python3-cffi.json", { "name": "lgi", @@ -43,13 +42,14 @@ "url": "https://github.com/pavouk/lgi.git", "commit": "95418635aa8151a516d43166227ea2b9d4c4403f" } - ] + ] }, { "name": "zoitechat", "buildsystem": "meson", "config-opts": [ "--buildtype=release", + "-Dgtk3=true", "-Ddbus-service-use-appid=true", "-Dwith-perl=false", "-Dwith-python=false", diff --git a/meson.build b/meson.build index 8f35d056..ea3bea56 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('zoitechat', 'c', - version: '2.17.4', - meson_version: '>= 0.47.0', + version: '2.18.0-pre1', + meson_version: '>= 0.55.0', default_options: [ 'c_std=c17', 'buildtype=debugoptimized', @@ -145,7 +145,7 @@ if not (host_machine.system() == 'windows' and get_option('debug')) test_ldflags += '-Wl,--dynamicbase' endif foreach ldflag : test_ldflags - if meson.version().version_compare('>= 0.46.0') + if meson.version().version_compare('>= 0.55.0') has_arg = cc.has_link_argument(ldflag) else has_arg = cc.has_argument(ldflag) @@ -168,7 +168,7 @@ if cc.get_id() != 'msvc' meson.add_install_script('meson_post_install.py') endif -if meson.version().version_compare('>= 0.53.0') +if meson.version().version_compare('>= 0.55.0') summary({ 'prefix': get_option('prefix'), 'bindir': get_option('bindir'), diff --git a/meson_options.txt b/meson_options.txt index 8120c030..faa9f665 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,6 +2,9 @@ option('gtk-frontend', type: 'boolean', description: 'Main graphical interface' ) +option('gtk3', type: 'boolean', value: false, + description: 'Build GTK frontend against GTK 3' +) option('text-frontend', type: 'boolean', value: false, description: 'Text interface (not generally useful)' ) diff --git a/packaging/solus/package.yml b/packaging/solus/package.yml new file mode 100644 index 00000000..81aea384 --- /dev/null +++ b/packaging/solus/package.yml @@ -0,0 +1,34 @@ +name : zoitechat +version : 2.18.0-pre1 +release : 1 +source : + - https://github.com/ZoiteChat/zoitechat/archive/refs/tags/zoitechat-2.18.0-pre1.tar.gz : 77d787cf00abd533326440eab01ca077c21cdfd2eb56807fc21d6fb70f34ada6 +homepage : https://zoitechat.zoite.net/ +license : GPL-2.0-only +component : network.irc +summary : HexChat-based IRC client +description: | + ZoiteChat is a HexChat-based IRC client for Windows and UNIX-like systems. +builddeps : + - pkgconfig(glib-2.0) + - pkgconfig(gmodule-2.0) + - pkgconfig(gtk+-3.0) + - pkgconfig(ayatana-appindicator3-0.1) + - pkgconfig(dbus-glib-1) + - pkgconfig(libcanberra) + - pkgconfig(openssl) + - pkgconfig(iso-codes) + - meson + - ninja + - pkgconfig + - gcc + - gettext +setup : | + %meson_configure \ + -Dgtk-frontend=true \ + -Dgtk3=true \ + -Dinstall-appdata=true +build : | + %ninja_build +install : | + %ninja_install diff --git a/plugins/checksum/checksum.vcxproj b/plugins/checksum/checksum.vcxproj index 0c15d25f..78e39373 100644 --- a/plugins/checksum/checksum.vcxproj +++ b/plugins/checksum/checksum.vcxproj @@ -30,7 +30,7 @@ WIN32;NDEBUG;_WINDOWS;_USRDLL;CHECKSUM_EXPORTS;%(PreprocessorDefinitions) - $(DepsRoot)\include;$(Glib);..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories) + $(DepsRoot)\include;$(OpenSslInclude);$(Glib);..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories) checksum.def @@ -41,7 +41,7 @@ WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;CHECKSUM_EXPORTS;%(PreprocessorDefinitions) - $(DepsRoot)\include;$(Glib);..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories) + $(DepsRoot)\include;$(OpenSslInclude);$(Glib);..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories) checksum.def diff --git a/plugins/fishlim/fishlim.vcxproj b/plugins/fishlim/fishlim.vcxproj index a07fae08..a8ba0925 100644 --- a/plugins/fishlim/fishlim.vcxproj +++ b/plugins/fishlim/fishlim.vcxproj @@ -30,7 +30,7 @@ WIN32;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;HAVE_DH_SET0_PQG;HAVE_DH_GET0_KEY;HAVE_DH_SET0_KEY;%(PreprocessorDefinitions) - $(DepsRoot)\include;$(Glib);..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories) + $(DepsRoot)\include;$(OpenSslInclude);$(Glib);..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories) fishlim.def @@ -41,7 +41,7 @@ WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;FISHLIM_EXPORTS;HAVE_DH_SET0_PQG;HAVE_DH_GET0_KEY;HAVE_DH_SET0_KEY;%(PreprocessorDefinitions) - $(DepsRoot)\include;$(Glib);..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories) + $(DepsRoot)\include;$(OpenSslInclude);$(Glib);..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories) fishlim.def diff --git a/plugins/lua/lua.vcxproj b/plugins/lua/lua.vcxproj index a4f9d560..65fd483c 100644 --- a/plugins/lua/lua.vcxproj +++ b/plugins/lua/lua.vcxproj @@ -51,4 +51,4 @@ - \ No newline at end of file + diff --git a/plugins/python/python3.vcxproj b/plugins/python/python3.vcxproj index d43e15c9..27da912c 100644 --- a/plugins/python/python3.vcxproj +++ b/plugins/python/python3.vcxproj @@ -29,7 +29,10 @@ - WIN32;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;Py_NO_LINK_LIB;$(OwnFlags);%(PreprocessorDefinitions) + _DEBUG;Py_DEBUG;Py_REF_DEBUG;Py_TRACE_REFS;%(UndefinePreprocessorDefinitions) + /U_DEBUG /UPy_DEBUG /UPy_REF_DEBUG /UPy_TRACE_REFS %(AdditionalOptions) + MultiThreadedDLL $(Glib);$(Python3Path)\include;..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories) @@ -41,9 +44,12 @@ "$(Python3Path)\python.exe" generate_plugin.py ..\..\src\common\zoitechat-plugin.h python.py "$(IntDir)python.c" - + - WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;$(OwnFlags);%(PreprocessorDefinitions) + WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;PYTHON_EXPORTS;Py_NO_LINK_LIB;$(OwnFlags);%(PreprocessorDefinitions) + _DEBUG;Py_DEBUG;Py_REF_DEBUG;Py_TRACE_REFS;%(UndefinePreprocessorDefinitions) + /U_DEBUG /UPy_DEBUG /UPy_REF_DEBUG /UPy_TRACE_REFS %(AdditionalOptions) + MultiThreadedDLL $(Glib);$(Python3Path)\include;..\..\src\common;$(ZoiteChatLib);%(AdditionalIncludeDirectories) @@ -67,4 +73,8 @@ - \ No newline at end of file + + + + + diff --git a/plugins/sysinfo/osx/backend.m b/plugins/sysinfo/osx/backend.m index 133763c9..58001949 100644 --- a/plugins/sysinfo/osx/backend.m +++ b/plugins/sysinfo/osx/backend.m @@ -273,3 +273,25 @@ sysinfo_backend_get_network(void) { return NULL; } + +static const char *sysinfo_detect_toolkit(void) +{ +#if defined(HAVE_GTK3) + return "GTK3"; +#elif defined(HAVE_GTK2) + return "GTK2"; +#elif defined(HAVE_GTK) + return "GTK"; +#else + return NULL; +#endif +} + +char *sysinfo_backend_get_ui(void) +{ + const char *toolkit = sysinfo_detect_toolkit(); + if (toolkit) + return g_strdup_printf("%s / Quartz", toolkit); + + return g_strdup("Quartz"); +} diff --git a/plugins/sysinfo/sysinfo-backend.h b/plugins/sysinfo/sysinfo-backend.h index 57bbca04..3a8f2920 100644 --- a/plugins/sysinfo/sysinfo-backend.h +++ b/plugins/sysinfo/sysinfo-backend.h @@ -30,4 +30,10 @@ char *sysinfo_backend_get_sound(void); char *sysinfo_backend_get_uptime(void); char *sysinfo_backend_get_network(void); +/* + * Short description of the UI/toolkit + display backend. + * Examples: "GTK3 / Wayland", "GTK2 / X11", "Windows / GTK3". + */ +char *sysinfo_backend_get_ui(void); + #endif diff --git a/plugins/sysinfo/sysinfo.c b/plugins/sysinfo/sysinfo.c index c808eb00..2b901623 100644 --- a/plugins/sysinfo/sysinfo.c +++ b/plugins/sysinfo/sysinfo.c @@ -41,7 +41,7 @@ static zoitechat_plugin *ph; static char name[] = "Sysinfo"; static char desc[] = "Display info about your hardware and OS"; static char version[] = "1.0"; -static char sysinfo_help[] = "SysInfo Usage:\n /SYSINFO [-e|-o] [CLIENT|OS|CPU|RAM|DISK|VGA|SOUND|ETHERNET|UPTIME], print various details about your system or print a summary without arguments\n /SYSINFO SET \n"; +static char sysinfo_help[] = "SysInfo Usage:\n /SYSINFO [-e|-o] [CLIENT|UI|OS|CPU|RAM|DISK|VGA|SOUND|ETHERNET|UPTIME], print various details about your system or print a summary without arguments\n /SYSINFO SET \n"; typedef struct { @@ -54,11 +54,22 @@ typedef struct static char * get_client (void) { - return g_strdup_printf ("ZoiteChat %s", zoitechat_get_info(ph, "version")); + char *ui = sysinfo_backend_get_ui(); + const char *ver = zoitechat_get_info(ph, "version"); + char *out; + + if (ui != NULL && *ui != '\0') + out = g_strdup_printf ("ZoiteChat %s (%s)", ver, ui); + else + out = g_strdup_printf ("ZoiteChat %s", ver); + + g_free (ui); + return out; } static hwinfo hwinfos[] = { {"client", "Client", get_client}, + {"ui", "UI", sysinfo_backend_get_ui}, {"os", "OS", sysinfo_backend_get_os}, {"cpu", "CPU", sysinfo_backend_get_cpu}, {"memory", "Memory", sysinfo_backend_get_memory}, @@ -235,7 +246,8 @@ zoitechat_plugin_init (zoitechat_plugin *plugin_handle, char **plugin_name, char zoitechat_hook_command (ph, "SYSINFO", ZOITECHAT_PRI_NORM, sysinfo_cb, sysinfo_help, NULL); - zoitechat_command (ph, "MENU ADD \"Window/Send System Info\" \"SYSINFO\""); + /* Match the classic label from HexChat so people can actually find it. */ + zoitechat_command (ph, "MENU ADD \"Window/Display System Info\" \"SYSINFO\""); zoitechat_printf (ph, _("%s plugin loaded\n"), name); return 1; } @@ -243,6 +255,8 @@ zoitechat_plugin_init (zoitechat_plugin *plugin_handle, char **plugin_name, char int zoitechat_plugin_deinit (void) { + /* Keep both in case older builds used a different label. */ + zoitechat_command (ph, "MENU DEL \"Window/Send System Info\""); zoitechat_command (ph, "MENU DEL \"Window/Display System Info\""); zoitechat_printf (ph, _("%s plugin unloaded\n"), name); return 1; diff --git a/plugins/sysinfo/sysinfo.vcxproj b/plugins/sysinfo/sysinfo.vcxproj index 07dc9855..00d5dcb0 100644 --- a/plugins/sysinfo/sysinfo.vcxproj +++ b/plugins/sysinfo/sysinfo.vcxproj @@ -31,7 +31,7 @@ WIN32;NDEBUG;_WINDOWS;_USRDLL;SYSINFO_EXPORTS;%(PreprocessorDefinitions) - ..\..\src\common;$(DepsRoot)\include;$(Glib);$(ZoiteChatLib);%(AdditionalIncludeDirectories) + ..\..\src\common;$(DepsRoot)\include;$(OpenSslInclude);$(Glib);$(ZoiteChatLib);%(AdditionalIncludeDirectories) false @@ -44,7 +44,7 @@ WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;_USRDLL;SYSINFO_EXPORTS;%(PreprocessorDefinitions) - ..\..\src\common;$(DepsRoot)\include;$(Glib);$(ZoiteChatLib);%(AdditionalIncludeDirectories) + ..\..\src\common;$(DepsRoot)\include;$(OpenSslInclude);$(Glib);$(ZoiteChatLib);%(AdditionalIncludeDirectories) false @@ -68,4 +68,4 @@ - \ No newline at end of file + diff --git a/plugins/sysinfo/unix/backend.c b/plugins/sysinfo/unix/backend.c index 73b97650..b6069042 100644 --- a/plugins/sysinfo/unix/backend.c +++ b/plugins/sysinfo/unix/backend.c @@ -18,6 +18,10 @@ */ #include + +#if defined(HAVE_GTK3) || defined(HAVE_GTK2) || defined(HAVE_GTK) +#include +#endif #include "parse.h" #include "match.h" #include "sysinfo.h" @@ -168,3 +172,86 @@ char *sysinfo_backend_get_network(void) return g_strdup (ethernet_card); } + +static const char *sysinfo_detect_toolkit(void) +{ +#if defined(HAVE_GTK3) + return "GTK3"; +#elif defined(HAVE_GTK2) + return "GTK2"; +#elif defined(HAVE_GTK) + return "GTK"; +#else + return NULL; +#endif +} + +static const char *sysinfo_detect_display_backend(void) +{ + const char *backend = NULL; + const char *gdk_backend = g_getenv("GDK_BACKEND"); + const char *session = g_getenv("XDG_SESSION_TYPE"); + const gboolean session_wayland = session && g_ascii_strcasecmp(session, "wayland") == 0; + + /* Best-effort: ask GDK what it actually opened, if available. */ +#if defined(HAVE_GTK3) || defined(HAVE_GTK2) || defined(HAVE_GTK) + { + GdkDisplay *display = gdk_display_get_default(); + if (display) + { + const char *type_name = G_OBJECT_TYPE_NAME(display); + if (type_name) + { + if (g_strrstr(type_name, "Wayland")) + backend = "Wayland"; + else if (g_strrstr(type_name, "X11")) + backend = "X11"; + } + } + } +#endif + + /* Next best: honor explicit backend preference. */ + if (!backend && gdk_backend) + { + if (g_strrstr(gdk_backend, "wayland")) + backend = "Wayland"; + else if (g_strrstr(gdk_backend, "x11")) + backend = "X11"; + } + + /* Last resort: infer from common env vars. */ + if (!backend) + { + const gboolean has_wayland = g_getenv("WAYLAND_DISPLAY") != NULL; + const gboolean has_x11 = g_getenv("DISPLAY") != NULL; + if (has_wayland && !has_x11) + backend = "Wayland"; + else if (has_x11 && !has_wayland) + backend = "X11"; + else if (session_wayland) + backend = "Wayland"; + else + backend = NULL; + } + + /* If we're using X11 inside a Wayland session, call it what it is. */ + if (backend && g_strcmp0(backend, "X11") == 0 && session_wayland) + return "XWayland"; + + return backend; +} + +char *sysinfo_backend_get_ui(void) +{ + const char *toolkit = sysinfo_detect_toolkit(); + const char *display = sysinfo_detect_display_backend(); + + if (toolkit && display) + return g_strdup_printf("%s / %s", toolkit, display); + if (toolkit) + return g_strdup(toolkit); + if (display) + return g_strdup(display); + return NULL; +} diff --git a/plugins/sysinfo/win32/backend.c b/plugins/sysinfo/win32/backend.c index 961418c0..e6f9487f 100644 --- a/plugins/sysinfo/win32/backend.c +++ b/plugins/sysinfo/win32/backend.c @@ -103,3 +103,30 @@ static char *get_memory_info (void) return sysinfo_format_memory (meminfo.ullTotalPhys, meminfo.ullAvailPhys); } + +static const char *sysinfo_detect_toolkit(void) +{ +#if defined(HAVE_GTK3) + return "GTK3"; +#elif defined(HAVE_GTK2) + return "GTK2"; +#elif defined(HAVE_GTK) + return "GTK"; +#else + return NULL; +#endif +} + +char * +sysinfo_backend_get_ui (void) +{ + const char *toolkit = sysinfo_detect_toolkit(); + + /* On Windows we don't have X11/Wayland. Keep it simple. */ + if (toolkit) + { + return g_strdup_printf ("Windows / %s", toolkit); + } + + return g_strdup ("Windows"); +} diff --git a/plugins/winamp/winamp.vcxproj b/plugins/winamp/winamp.vcxproj index ac483a8d..655798eb 100644 --- a/plugins/winamp/winamp.vcxproj +++ b/plugins/winamp/winamp.vcxproj @@ -39,7 +39,7 @@ - $(DepsRoot)\include;$(Glib);..\..\src\common;%(AdditionalIncludeDirectories) + $(DepsRoot)\include;$(OpenSslInclude);$(Glib);..\..\src\common;%(AdditionalIncludeDirectories) winamp.def diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 4f4c6407..98e2b283 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -99,13 +99,13 @@ WIN32;NDEBUG;_LIB;$(OwnFlags);%(PreprocessorDefinitions) - $(ZoiteChatLib);$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories) + $(ZoiteChatLib);$(DepsRoot)\include;$(OpenSslInclude);$(Glib);$(Gtk);%(AdditionalIncludeDirectories) WIN32;_WIN64;_AMD64_;NDEBUG;_LIB;$(OwnFlags);%(PreprocessorDefinitions) - $(ZoiteChatLib);$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories) + $(ZoiteChatLib);$(DepsRoot)\include;$(OpenSslInclude);$(Glib);$(Gtk);%(AdditionalIncludeDirectories) 4267;%(DisableSpecificWarnings) @@ -116,8 +116,8 @@ SET SOLUTIONDIR=$(SolutionDir)..\ "$(Python3Path)\python.exe" $(ProjectDir)make-te.py "$(ProjectDir)textevents.in" "$(ZoiteChatLib)textevents.h" "$(ZoiteChatLib)textenums.h" powershell -File "$(SolutionDir)..\win32\version-template.ps1" "$(SolutionDir)..\win32\config.h.tt" "$(ZoiteChatLib)config.h" -"$(Python3Path)\python.exe" "$(DepsRoot)\bin\glib-genmarshal" --prefix=_zoitechat_marshal --header "$(ProjectDir)marshalers.list" --output "$(ZoiteChatLib)marshal.h" -"$(Python3Path)\python.exe" "$(DepsRoot)\bin\glib-genmarshal" --prefix=_zoitechat_marshal --body "$(ProjectDir)marshalers.list" --output "$(ZoiteChatLib)marshal.c" +$(GlibGenMarshal) --prefix=_zoitechat_marshal --header "$(ProjectDir)marshalers.list" --output "$(ZoiteChatLib)marshal.h" +$(GlibGenMarshal) --prefix=_zoitechat_marshal --body "$(ProjectDir)marshalers.list" --output "$(ZoiteChatLib)marshal.c" ]]> diff --git a/src/common/dbus/dbus-plugin.c b/src/common/dbus/dbus-plugin.c index 6942a048..1788f5cd 100644 --- a/src/common/dbus/dbus-plugin.c +++ b/src/common/dbus/dbus-plugin.c @@ -40,14 +40,11 @@ static GList *contexts = NULL; static GHashTable *clients = NULL; static DBusGConnection *connection; -typedef struct RemoteObject RemoteObject; -typedef struct RemoteObjectClass RemoteObjectClass; +G_DECLARE_FINAL_TYPE (RemoteObject, remote_object, REMOTE, OBJECT, GObject) -GType Remote_object_get_type (void); - -struct RemoteObject +struct _RemoteObject { - GObject parent; + GObject parent_instance; guint last_hook_id; guint last_list_id; @@ -59,11 +56,6 @@ struct RemoteObject void *handle; }; -struct RemoteObjectClass -{ - GObjectClass parent; -}; - typedef struct { guint id; @@ -89,12 +81,6 @@ enum static guint signals[LAST_SIGNAL] = { 0 }; -#define REMOTE_TYPE_OBJECT (remote_object_get_type ()) -#define REMOTE_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), REMOTE_TYPE_OBJECT, RemoteObject)) -#define REMOTE_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), REMOTE_TYPE_OBJECT, RemoteObjectClass)) -#define REMOTE_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), REMOTE_TYPE_OBJECT)) -#define REMOTE_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), REMOTE_TYPE_OBJECT)) -#define REMOTE_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), REMOTE_TYPE_OBJECT, RemoteObjectClass)) #define REMOTE_OBJECT_ERROR (remote_object_error_quark ()) #define REMOTE_TYPE_ERROR (remote_object_error_get_type ()) @@ -376,7 +362,7 @@ remote_object_connect (RemoteObject *obj, } g_snprintf(count_buffer, sizeof(count_buffer), "%u", count++); path = g_build_filename (DBUS_OBJECT_PATH, count_buffer, NULL); - remote_object = g_object_new (REMOTE_TYPE_OBJECT, NULL); + remote_object = g_object_new (remote_object_get_type (), NULL); remote_object->dbus_path = path; remote_object->filename = g_path_get_basename (filename); remote_object->handle = zoitechat_plugingui_add (ph, @@ -891,8 +877,8 @@ init_dbus (void) guint request_name_result; GError *error = NULL; - dbus_g_object_type_install_info (REMOTE_TYPE_OBJECT, - &dbus_glib_remote_object_object_info); + dbus_g_object_type_install_info (remote_object_get_type (), + &dbus_glib_remote_object_object_info); connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (connection == NULL) { @@ -930,7 +916,7 @@ init_dbus (void) G_CALLBACK (name_owner_changed), NULL, NULL); - remote = g_object_new (REMOTE_TYPE_OBJECT, NULL); + remote = g_object_new (remote_object_get_type (), NULL); dbus_g_connection_register_g_object (connection, DBUS_OBJECT_PATH"/Remote", G_OBJECT (remote)); diff --git a/src/common/sysinfo/win32/backend.c b/src/common/sysinfo/win32/backend.c index 0a80b1f8..b2ed3ab8 100644 --- a/src/common/sysinfo/win32/backend.c +++ b/src/common/sysinfo/win32/backend.c @@ -229,7 +229,15 @@ static char *query_wmi (QueryWmiType type) query = SysAllocString (L"SELECT Name FROM Win32_VideoController"); break; case QUERY_WMI_HDD: - query = SysAllocString (L"SELECT Name, Capacity, FreeSpace FROM Win32_Volume"); + /* + * Query local fixed logical disks only. + * + * Win32_Volume can cause Windows to probe additional network-backed + * providers (for example Plan9/WSL providers), which may trigger RPC + * failures in debugger sessions. Restricting this to fixed logical disks + * avoids those probes while still providing useful local disk stats. + */ + query = SysAllocString (L"SELECT Name, Size, FreeSpace FROM Win32_LogicalDisk WHERE DriveType = 3"); break; default: goto release_queryLanguageName; @@ -465,7 +473,7 @@ static char *read_hdd_info (IWbemClassObject *object) VariantClear (&name_variant); - hr = object->lpVtbl->Get (object, L"Capacity", 0, &capacity_variant, NULL, NULL); + hr = object->lpVtbl->Get (object, L"Size", 0, &capacity_variant, NULL, NULL); if (FAILED (hr)) { return NULL; @@ -580,7 +588,16 @@ static char *zoitechat_strdup_printf (const char *format, ...) va_start (args, format); va_copy (args_copy, args); + /* + * MSVC's debug CRT treats vsnprintf(NULL, 0, ...) as an invalid parameter, + * which triggers a fatal runtime exception via ucrtbased.dll. Use + * _vscprintf() to determine required output length on that toolchain. + */ +#ifdef _MSC_VER + length = _vscprintf (format, args_copy); +#else length = vsnprintf (NULL, 0, format, args_copy); +#endif va_end (args_copy); if (length < 0) diff --git a/src/common/util.c b/src/common/util.c index 4f1023d9..4ad5dedd 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -185,6 +185,14 @@ waitline (int sok, char *buf, int bufsize, int use_recv) { int i = 0; + if (bufsize <= 0) + return -1; + +#ifdef WIN32 + if (!use_recv && _get_osfhandle (sok) == -1) + return -1; +#endif + while (1) { if (use_recv) diff --git a/src/fe-gtk/ascii.c b/src/fe-gtk/ascii.c index d4511d98..9a622de8 100644 --- a/src/fe-gtk/ascii.c +++ b/src/fe-gtk/ascii.c @@ -137,7 +137,11 @@ ascii_open (void) if (table_pos[0] == '\n' || i == 0) { table_pos++; +#if HAVE_GTK3 + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); +#elif !HAVE_GTK3 hbox = gtk_hbox_new (0, 0); +#endif gtk_container_add (GTK_CONTAINER (vbox), hbox); gtk_widget_show (hbox); i++; diff --git a/src/fe-gtk/banlist.c b/src/fe-gtk/banlist.c index f54d001d..d4a6a14d 100644 --- a/src/fe-gtk/banlist.c +++ b/src/fe-gtk/banlist.c @@ -37,6 +37,17 @@ #include "maingui.h" #include "banlist.h" +#if HAVE_GTK3 +#define ICON_BANLIST_REMOVE "list-remove" +#define ICON_BANLIST_CLEAR "edit-clear" +#define ICON_BANLIST_REFRESH "view-refresh" +#endif +#if !HAVE_GTK3 +#define ICON_BANLIST_REMOVE GTK_STOCK_REMOVE +#define ICON_BANLIST_CLEAR GTK_STOCK_CLEAR +#define ICON_BANLIST_REFRESH GTK_STOCK_REFRESH +#endif + /* * These supports_* routines set capable, readable, writable bits */ static void supports_bans (banlist_info *, int); @@ -772,6 +783,19 @@ banlist_closegui (GtkWidget *wid, banlist_info *banl) } } +static GtkWidget * +banlist_table_new (void) +{ + GtkWidget *table = gtkutil_grid_new (1, MODE_CT, FALSE); + +#if HAVE_GTK3 + gtk_grid_set_column_spacing (GTK_GRID (table), 16); +#else + gtk_table_set_col_spacings (GTK_TABLE (table), 16); +#endif + return table; +} + void banlist_opengui (struct session *sess) { @@ -818,8 +842,7 @@ banlist_opengui (struct session *sess) /* create banlist view */ banl->treeview = banlist_treeview_new (vbox, banl); - table = gtk_table_new (1, MODE_CT, FALSE); - gtk_table_set_col_spacings (GTK_TABLE (table), 16); + table = banlist_table_new (); gtk_box_pack_start (GTK_BOX (vbox), table, 0, 0, 0); for (i = 0; i < MODE_CT; i++) @@ -830,23 +853,29 @@ banlist_opengui (struct session *sess) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (banl->checkboxes[i]), (banl->checked & 1<checkboxes[i]), "toggled", G_CALLBACK (banlist_toggle), banl); - gtk_table_attach (GTK_TABLE (table), banl->checkboxes[i], i+1, i+2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtkutil_grid_attach (table, banl->checkboxes[i], i + 1, i + 2, 0, 1, + GTKUTIL_ATTACH_FILL, GTKUTIL_ATTACH_FILL, 0, 0); } +#if HAVE_GTK3 + bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 bbox = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD); +#endif gtk_container_set_border_width (GTK_CONTAINER (bbox), 5); gtk_box_pack_end (GTK_BOX (vbox), bbox, 0, 0, 0); gtk_widget_show (bbox); - banl->but_remove = gtkutil_button (bbox, GTK_STOCK_REMOVE, 0, banlist_unban, banl, + banl->but_remove = gtkutil_button (bbox, ICON_BANLIST_REMOVE, 0, banlist_unban, banl, _("Remove")); - banl->but_crop = gtkutil_button (bbox, GTK_STOCK_REMOVE, 0, banlist_crop, banl, + banl->but_crop = gtkutil_button (bbox, ICON_BANLIST_REMOVE, 0, banlist_crop, banl, _("Crop")); - banl->but_clear = gtkutil_button (bbox, GTK_STOCK_CLEAR, 0, banlist_clear, banl, + banl->but_clear = gtkutil_button (bbox, ICON_BANLIST_CLEAR, 0, banlist_clear, banl, _("Clear")); - banl->but_refresh = gtkutil_button (bbox, GTK_STOCK_REFRESH, 0, banlist_refresh, banl, _("Refresh")); + banl->but_refresh = gtkutil_button (bbox, ICON_BANLIST_REFRESH, 0, banlist_refresh, banl, _("Refresh")); banlist_do_refresh (banl); diff --git a/src/fe-gtk/chanlist.c b/src/fe-gtk/chanlist.c index 7f7e1101..0957da7a 100644 --- a/src/fe-gtk/chanlist.c +++ b/src/fe-gtk/chanlist.c @@ -45,6 +45,21 @@ #include "custom-list.h" +#if HAVE_GTK3 +#define ICON_CHANLIST_JOIN "go-jump" +#define ICON_CHANLIST_COPY "edit-copy" +#define ICON_CHANLIST_FIND "edit-find" +#define ICON_CHANLIST_REFRESH "view-refresh" +#define ICON_CHANLIST_SAVE "document-save-as" +#endif +#if !HAVE_GTK3 +#define ICON_CHANLIST_JOIN GTK_STOCK_JUMP_TO +#define ICON_CHANLIST_COPY GTK_STOCK_COPY +#define ICON_CHANLIST_FIND GTK_STOCK_FIND +#define ICON_CHANLIST_REFRESH GTK_STOCK_REFRESH +#define ICON_CHANLIST_SAVE GTK_STOCK_SAVE_AS +#endif + enum { COL_CHANNEL, @@ -68,6 +83,102 @@ chanlistrow; #define GET_MODEL(xserv) (gtk_tree_view_get_model(GTK_TREE_VIEW(xserv->gui->chanlist_list))) +static void +chanlist_set_label_alignment (GtkWidget *widget) +{ +#if HAVE_GTK3 + gtk_widget_set_halign (widget, GTK_ALIGN_START); + gtk_widget_set_valign (widget, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 + gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5); +#endif +} + +#if HAVE_GTK3 +static void +chanlist_grid_attach (GtkWidget *grid, GtkWidget *child, + gint column, gint row, + gint width, gint height, + gboolean hexpand, gboolean vexpand, + GtkAlign halign, GtkAlign valign) +{ + gtk_widget_set_hexpand (child, hexpand); + gtk_widget_set_vexpand (child, vexpand); + gtk_widget_set_halign (child, halign); + gtk_widget_set_valign (child, valign); + gtk_grid_attach (GTK_GRID (grid), child, column, row, width, height); +} +#endif + +static GtkWidget * +chanlist_box_new (void) +{ +#if HAVE_GTK3 + GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + + gtk_box_set_homogeneous (GTK_BOX (box), FALSE); + return box; +#elif !HAVE_GTK3 + return gtk_hbox_new (FALSE, 0); +#endif +} + +static GtkWidget * +chanlist_icon_button (const char *label, const char *icon_name, + GCallback callback, gpointer userdata) +{ + GtkWidget *button; + GtkWidget *image; + + button = gtk_button_new_with_mnemonic (label); +#if HAVE_GTK3 + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); +#elif !HAVE_GTK3 + image = gtk_image_new_from_stock (icon_name, GTK_ICON_SIZE_MENU); +#endif + gtk_button_set_image (GTK_BUTTON (button), image); + gtk_button_set_use_underline (GTK_BUTTON (button), TRUE); + g_signal_connect (G_OBJECT (button), "clicked", callback, userdata); + gtk_widget_show (button); + + return button; +} + +static GtkWidget * +chanlist_icon_menu_item (const char *label, const char *icon_name, + GCallback callback, gpointer userdata) +{ + GtkWidget *item; +#if HAVE_GTK3 + GtkWidget *box; + GtkWidget *image = NULL; + GtkWidget *label_widget; + const char *icon_name_gtk3; + + item = gtk_menu_item_new (); + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + icon_name_gtk3 = gtkutil_icon_name_from_stock (icon_name); + if (!icon_name_gtk3) + icon_name_gtk3 = icon_name; + image = icon_name_gtk3 ? gtk_image_new_from_icon_name (icon_name_gtk3, GTK_ICON_SIZE_MENU) : NULL; + label_widget = gtk_label_new_with_mnemonic (label); + if (image) + gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), label_widget, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (item), box); +#else + GtkWidget *image; + + item = gtk_image_menu_item_new_with_mnemonic (label); + image = gtk_image_new_from_stock (icon_name, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); +#endif + g_signal_connect (G_OBJECT (item), "activate", callback, userdata); + gtk_widget_show_all (item); + + return item; +} + static gboolean chanlist_match (server *serv, const char *str) @@ -621,18 +732,42 @@ chanlist_button_cb (GtkTreeView *tree, GdkEventButton *event, server *serv) g_object_unref (menu); g_signal_connect (G_OBJECT (menu), "selection-done", G_CALLBACK (chanlist_menu_destroy), NULL); - mg_create_icon_item (_("_Join Channel"), GTK_STOCK_JUMP_TO, menu, - chanlist_join, serv); - mg_create_icon_item (_("_Copy Channel Name"), GTK_STOCK_COPY, menu, - chanlist_copychannel, serv); - mg_create_icon_item (_("Copy _Topic Text"), GTK_STOCK_COPY, menu, - chanlist_copytopic, serv); + { + GtkWidget *item; + + item = chanlist_icon_menu_item (_("_Join Channel"), ICON_CHANLIST_JOIN, + G_CALLBACK (chanlist_join), serv); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + item = chanlist_icon_menu_item (_("_Copy Channel Name"), ICON_CHANLIST_COPY, + G_CALLBACK (chanlist_copychannel), serv); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + item = chanlist_icon_menu_item (_("Copy _Topic Text"), ICON_CHANLIST_COPY, + G_CALLBACK (chanlist_copytopic), serv); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + } chan = chanlist_get_selected (serv, FALSE); menu_addfavoritemenu (serv, menu, chan, FALSE); g_free (chan); - gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, event->time); +#if HAVE_GTK3 + if (event) + { + gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *)event); + } + else + { + gtk_menu_popup_at_widget (GTK_MENU (menu), GTK_WIDGET (tree), + GDK_GRAVITY_SOUTH_WEST, + GDK_GRAVITY_NORTH_WEST, + NULL); + } +#endif +#if !HAVE_GTK3 + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, event ? event->time : 0); +#endif return TRUE; } @@ -784,48 +919,108 @@ chanlist_opengui (server *serv, int do_refresh) /* ============================================================= */ +#if HAVE_GTK3 + table = gtk_grid_new (); + gtk_grid_set_column_spacing (GTK_GRID (table), 12); + gtk_grid_set_row_spacing (GTK_GRID (table), 3); +#else table = gtk_table_new (4, 4, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 12); gtk_table_set_row_spacings (GTK_TABLE (table), 3); +#endif gtk_box_pack_start (GTK_BOX (vbox), table, 0, 1, 0); gtk_widget_show (table); - wid = gtkutil_button (NULL, GTK_STOCK_FIND, 0, chanlist_search_pressed, serv, +#if HAVE_GTK3 + wid = chanlist_icon_button (_("_Search"), ICON_CHANLIST_FIND, + G_CALLBACK (chanlist_search_pressed), serv); +#endif +#if !HAVE_GTK3 + wid = gtkutil_button (NULL, ICON_CHANLIST_FIND, 0, chanlist_search_pressed, serv, _("_Search")); +#endif serv->gui->chanlist_search = wid; +#if HAVE_GTK3 + chanlist_grid_attach (table, wid, 3, 3, 1, 1, FALSE, FALSE, + GTK_ALIGN_FILL, GTK_ALIGN_FILL); +#else gtk_table_attach (GTK_TABLE (table), wid, 3, 4, 3, 4, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#endif - wid = gtkutil_button (NULL, GTK_STOCK_REFRESH, 0, chanlist_refresh, serv, +#if HAVE_GTK3 + wid = chanlist_icon_button (_("_Download List"), ICON_CHANLIST_REFRESH, + G_CALLBACK (chanlist_refresh), serv); +#endif +#if !HAVE_GTK3 + wid = gtkutil_button (NULL, ICON_CHANLIST_REFRESH, 0, chanlist_refresh, serv, _("_Download List")); +#endif serv->gui->chanlist_refresh = wid; +#if HAVE_GTK3 + chanlist_grid_attach (table, wid, 3, 2, 1, 1, FALSE, FALSE, + GTK_ALIGN_FILL, GTK_ALIGN_FILL); +#else gtk_table_attach (GTK_TABLE (table), wid, 3, 4, 2, 3, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#endif - wid = gtkutil_button (NULL, GTK_STOCK_SAVE_AS, 0, chanlist_save, serv, +#if HAVE_GTK3 + wid = chanlist_icon_button (_("Save _List..."), ICON_CHANLIST_SAVE, + G_CALLBACK (chanlist_save), serv); +#endif +#if !HAVE_GTK3 + wid = gtkutil_button (NULL, ICON_CHANLIST_SAVE, 0, chanlist_save, serv, _("Save _List...")); +#endif serv->gui->chanlist_savelist = wid; +#if HAVE_GTK3 + chanlist_grid_attach (table, wid, 3, 1, 1, 1, FALSE, FALSE, + GTK_ALIGN_FILL, GTK_ALIGN_FILL); +#else gtk_table_attach (GTK_TABLE (table), wid, 3, 4, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#endif - wid = gtkutil_button (NULL, GTK_STOCK_JUMP_TO, 0, chanlist_join, serv, +#if HAVE_GTK3 + wid = chanlist_icon_button (_("_Join Channel"), ICON_CHANLIST_JOIN, + G_CALLBACK (chanlist_join), serv); +#endif +#if !HAVE_GTK3 + wid = gtkutil_button (NULL, ICON_CHANLIST_JOIN, 0, chanlist_join, serv, _("_Join Channel")); +#endif serv->gui->chanlist_join = wid; +#if HAVE_GTK3 + chanlist_grid_attach (table, wid, 3, 0, 1, 1, FALSE, FALSE, + GTK_ALIGN_FILL, GTK_ALIGN_FILL); +#else gtk_table_attach (GTK_TABLE (table), wid, 3, 4, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#endif /* ============================================================= */ wid = gtk_label_new (_("Show only:")); - gtk_misc_set_alignment (GTK_MISC (wid), 0, 0.5); + chanlist_set_label_alignment (wid); +#if HAVE_GTK3 + chanlist_grid_attach (table, wid, 0, 3, 1, 1, FALSE, FALSE, + GTK_ALIGN_START, GTK_ALIGN_CENTER); +#else gtk_table_attach (GTK_TABLE (table), wid, 0, 1, 3, 4, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#endif gtk_widget_show (wid); - hbox = gtk_hbox_new (0, 0); + hbox = chanlist_box_new (); gtk_box_set_spacing (GTK_BOX (hbox), 9); +#if HAVE_GTK3 + chanlist_grid_attach (table, hbox, 1, 3, 1, 1, FALSE, FALSE, + GTK_ALIGN_FILL, GTK_ALIGN_FILL); +#else gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0); +#endif gtk_widget_show (hbox); wid = gtk_label_new (_("channels with")); @@ -860,15 +1055,25 @@ chanlist_opengui (server *serv, int do_refresh) /* ============================================================= */ wid = gtk_label_new (_("Look in:")); - gtk_misc_set_alignment (GTK_MISC (wid), 0, 0.5); + chanlist_set_label_alignment (wid); +#if HAVE_GTK3 + chanlist_grid_attach (table, wid, 0, 2, 1, 1, FALSE, FALSE, + GTK_ALIGN_START, GTK_ALIGN_CENTER); +#else gtk_table_attach (GTK_TABLE (table), wid, 0, 1, 2, 3, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#endif gtk_widget_show (wid); - hbox = gtk_hbox_new (0, 0); + hbox = chanlist_box_new (); gtk_box_set_spacing (GTK_BOX (hbox), 12); +#if HAVE_GTK3 + chanlist_grid_attach (table, hbox, 1, 2, 1, 1, FALSE, FALSE, + GTK_ALIGN_FILL, GTK_ALIGN_FILL); +#else gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0); +#endif gtk_widget_show (hbox); wid = gtk_check_button_new_with_label (_("Channel name")); @@ -892,9 +1097,14 @@ chanlist_opengui (server *serv, int do_refresh) /* ============================================================= */ wid = gtk_label_new (_("Search type:")); - gtk_misc_set_alignment (GTK_MISC (wid), 0, 0.5); + chanlist_set_label_alignment (wid); +#if HAVE_GTK3 + chanlist_grid_attach (table, wid, 0, 1, 1, 1, FALSE, FALSE, + GTK_ALIGN_START, GTK_ALIGN_CENTER); +#else gtk_table_attach (GTK_TABLE (table), wid, 0, 1, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#endif gtk_widget_show (wid); wid = gtk_combo_box_text_new (); @@ -902,8 +1112,13 @@ chanlist_opengui (server *serv, int do_refresh) gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (wid), _("Pattern Match (Wildcards)")); gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (wid), _("Regular Expression")); gtk_combo_box_set_active (GTK_COMBO_BOX (wid), serv->gui->chanlist_search_type); +#if HAVE_GTK3 + chanlist_grid_attach (table, wid, 1, 1, 1, 1, FALSE, FALSE, + GTK_ALIGN_FILL, GTK_ALIGN_CENTER); +#else gtk_table_attach (GTK_TABLE (table), wid, 1, 2, 1, 2, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#endif g_signal_connect (G_OBJECT (wid), "changed", G_CALLBACK (chanlist_combo_cb), serv); gtk_widget_show (wid); @@ -911,9 +1126,14 @@ chanlist_opengui (server *serv, int do_refresh) /* ============================================================= */ wid = gtk_label_new (_("Find:")); - gtk_misc_set_alignment (GTK_MISC (wid), 0, 0.5); + chanlist_set_label_alignment (wid); +#if HAVE_GTK3 + chanlist_grid_attach (table, wid, 0, 0, 1, 1, FALSE, FALSE, + GTK_ALIGN_START, GTK_ALIGN_CENTER); +#else gtk_table_attach (GTK_TABLE (table), wid, 0, 1, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#endif gtk_widget_show (wid); wid = gtk_entry_new (); @@ -923,8 +1143,13 @@ chanlist_opengui (server *serv, int do_refresh) g_signal_connect (G_OBJECT (wid), "activate", G_CALLBACK (chanlist_search_pressed), (gpointer) serv); +#if HAVE_GTK3 + chanlist_grid_attach (table, wid, 1, 0, 1, 1, TRUE, FALSE, + GTK_ALIGN_FILL, GTK_ALIGN_CENTER); +#else gtk_table_attach (GTK_TABLE (table), wid, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0); +#endif gtk_widget_show (wid); serv->gui->chanlist_wild = wid; @@ -932,9 +1157,18 @@ chanlist_opengui (server *serv, int do_refresh) /* ============================================================= */ +#if HAVE_GTK3 + wid = gtk_separator_new (GTK_ORIENTATION_VERTICAL); +#else wid = gtk_vseparator_new (); +#endif +#if HAVE_GTK3 + chanlist_grid_attach (table, wid, 2, 0, 1, 5, FALSE, FALSE, + GTK_ALIGN_FILL, GTK_ALIGN_FILL); +#else gtk_table_attach (GTK_TABLE (table), wid, 2, 3, 0, 5, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#endif gtk_widget_show (wid); g_signal_connect (G_OBJECT (serv->gui->chanlist_window), "destroy", diff --git a/src/fe-gtk/chanview-tabs.c b/src/fe-gtk/chanview-tabs.c index 92c974b8..c4d6b3c9 100644 --- a/src/fe-gtk/chanview-tabs.c +++ b/src/fe-gtk/chanview-tabs.c @@ -27,6 +27,13 @@ typedef struct GtkWidget *b2; /* button2 */ } tabview; +#if HAVE_GTK3 +#define ICON_CHANVIEW_CLOSE "window-close" +#endif +#if !HAVE_GTK3 +#define ICON_CHANVIEW_CLOSE GTK_STOCK_CLOSE +#endif + static void chanview_populate (chanview *cv); /* ignore "toggled" signal? */ @@ -45,6 +52,26 @@ static int tab_right_is_moving = 0; * */ +static inline gint +cv_tabs_get_viewport_size (GdkWindow *parent_win, gboolean vertical) +{ + gint viewport_size = 0; + +#if HAVE_GTK3 + if (vertical) + viewport_size = gdk_window_get_height (parent_win); + else + viewport_size = gdk_window_get_width (parent_win); +#else + if (vertical) + gdk_window_get_geometry (parent_win, 0, 0, 0, &viewport_size, 0); + else + gdk_window_get_geometry (parent_win, 0, 0, &viewport_size, 0, 0); +#endif + + return viewport_size; +} + /* * GtkViewports request at least as much space as their children do. * If we don't intervene here, the GtkViewport will be granted its @@ -73,13 +100,13 @@ cv_tabs_sizealloc (GtkWidget *widget, GtkAllocation *allocation, chanview *cv) if (cv->vertical) { adj = gtk_viewport_get_vadjustment (GTK_VIEWPORT (gtk_widget_get_parent (inner))); - gdk_window_get_geometry (parent_win, 0, 0, 0, &viewport_size, 0); } else { adj = gtk_viewport_get_hadjustment (GTK_VIEWPORT (gtk_widget_get_parent (inner))); - gdk_window_get_geometry (parent_win, 0, 0, &viewport_size, 0, 0); } + viewport_size = cv_tabs_get_viewport_size (parent_win, cv->vertical); + if (gtk_adjustment_get_upper (adj) <= viewport_size) { gtk_widget_hide (((tabview *)cv)->b1); @@ -150,13 +177,13 @@ tab_scroll_left_up_clicked (GtkWidget *widget, chanview *cv) if (cv->vertical) { adj = gtk_viewport_get_vadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner))); - gdk_window_get_geometry (parent_win, 0, 0, 0, &viewport_size, 0); } else { adj = gtk_viewport_get_hadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner))); - gdk_window_get_geometry (parent_win, 0, 0, &viewport_size, 0, 0); } + viewport_size = cv_tabs_get_viewport_size (parent_win, cv->vertical); + new_value = tab_search_offset (inner, gtk_adjustment_get_value (adj), 0, cv->vertical); if (new_value + viewport_size > gtk_adjustment_get_upper (adj)) @@ -199,13 +226,13 @@ tab_scroll_right_down_clicked (GtkWidget *widget, chanview *cv) if (cv->vertical) { adj = gtk_viewport_get_vadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner))); - gdk_window_get_geometry (parent_win, 0, 0, 0, &viewport_size, 0); } else { adj = gtk_viewport_get_hadjustment (GTK_VIEWPORT (gtk_widget_get_parent(inner))); - gdk_window_get_geometry (parent_win, 0, 0, &viewport_size, 0, 0); } + viewport_size = cv_tabs_get_viewport_size (parent_win, cv->vertical); + new_value = tab_search_offset (inner, gtk_adjustment_get_value (adj), 1, cv->vertical); if (new_value == 0 || new_value + viewport_size > gtk_adjustment_get_upper (adj)) @@ -266,9 +293,33 @@ static GtkWidget * make_sbutton (GtkArrowType type, void *click_cb, void *userdata) { GtkWidget *button, *arrow; +#if HAVE_GTK3 + const char *icon_name = "pan-end-symbolic"; +#endif button = gtk_button_new (); +#if HAVE_GTK3 + switch (type) + { + case GTK_ARROW_UP: + icon_name = "pan-up-symbolic"; + break; + case GTK_ARROW_DOWN: + icon_name = "pan-down-symbolic"; + break; + case GTK_ARROW_LEFT: + icon_name = "pan-start-symbolic"; + break; + case GTK_ARROW_RIGHT: + default: + icon_name = "pan-end-symbolic"; + break; + } + + arrow = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON); +#elif !HAVE_GTK3 arrow = gtk_arrow_new (type, GTK_SHADOW_NONE); +#endif gtk_container_add (GTK_CONTAINER (button), arrow); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); g_signal_connect (G_OBJECT (button), "clicked", @@ -289,9 +340,13 @@ cv_tabs_init (chanview *cv) GtkWidget *button; if (cv->vertical) - outer = gtk_vbox_new (0, 0); + { + outer = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); + } else - outer = gtk_hbox_new (0, 0); + { + outer = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); + } ((tabview *)cv)->outer = outer; g_signal_connect (G_OBJECT (outer), "size_allocate", G_CALLBACK (cv_tabs_sizealloc), cv); @@ -308,9 +363,13 @@ cv_tabs_init (chanview *cv) gtk_widget_show (viewport); if (cv->vertical) - box = gtk_vbox_new (FALSE, 0); + { + box = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); + } else - box = gtk_hbox_new (FALSE, 0); + { + box = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); + } ((tabview *)cv)->inner = box; gtk_container_add (GTK_CONTAINER (viewport), box); gtk_widget_show (box); @@ -318,7 +377,7 @@ cv_tabs_init (chanview *cv) /* if vertical, the buttons can be side by side */ if (cv->vertical) { - hbox = gtk_hbox_new (FALSE, 0); + hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_box_pack_start (GTK_BOX (outer), hbox, 0, 0, 0); gtk_widget_show (hbox); } @@ -344,7 +403,7 @@ cv_tabs_init (chanview *cv) gtk_box_pack_start (GTK_BOX (outer), ((tabview *)cv)->b1, 0, 0, 0); } - button = gtkutil_button (outer, GTK_STOCK_CLOSE, NULL, cv_tabs_xclick_cb, + button = gtkutil_button (outer, ICON_CHANVIEW_CLOSE, NULL, cv_tabs_xclick_cb, cv, 0); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_widget_set_can_focus (button, FALSE); @@ -486,13 +545,21 @@ tab_add_real (chanview *cv, GtkWidget *tab, chan *ch) if (cv->vertical) { /* vertical */ - box = gtk_vbox_new (FALSE, 0); + box = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); +#if HAVE_GTK3 + sep = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); +#elif !HAVE_GTK3 sep = gtk_hseparator_new (); +#endif } else { /* horiz */ - box = gtk_hbox_new (FALSE, 0); + box = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); +#if HAVE_GTK3 + sep = gtk_separator_new (GTK_ORIENTATION_VERTICAL); +#elif !HAVE_GTK3 sep = gtk_vseparator_new (); +#endif } gtk_box_pack_end (GTK_BOX (box), sep, 0, 0, 4); diff --git a/src/fe-gtk/chanview-tree.c b/src/fe-gtk/chanview-tree.c index a4117b62..7d3c351c 100644 --- a/src/fe-gtk/chanview-tree.c +++ b/src/fe-gtk/chanview-tree.c @@ -106,21 +106,37 @@ cv_tree_init (chanview *cv) }; win = gtk_scrolled_window_new (0, 0); + gtk_widget_set_hexpand (win, TRUE); + gtk_widget_set_vexpand (win, TRUE); + /*gtk_container_set_border_width (GTK_CONTAINER (win), 1);*/ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (win), - GTK_SHADOW_IN); + GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (win), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_container_add (GTK_CONTAINER (cv->box), win); gtk_widget_show (win); view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (cv->store)); + gtk_widget_set_hexpand (view, TRUE); + gtk_widget_set_vexpand (view, TRUE); gtk_widget_set_name (view, "zoitechat-tree"); - if (cv->style) + if ( +#if HAVE_GTK3 + cv->font_desc +#else + cv->style +#endif + ) { - gtk_widget_modify_base (view, GTK_STATE_NORMAL, &cv->style->base[GTK_STATE_NORMAL]); - gtk_widget_modify_text (view, GTK_STATE_NORMAL, &cv->style->text[GTK_STATE_NORMAL]); - gtk_widget_modify_font (view, cv->style->font_desc); +#if HAVE_GTK3 + gtkutil_apply_palette (view, &colors[COL_BG], &colors[COL_FG], + cv->font_desc); +#else + gtkutil_apply_palette (view, &cv->style->base[GTK_STATE_NORMAL], + &cv->style->text[GTK_STATE_NORMAL], + cv->style->font_desc); +#endif } /*gtk_widget_modify_base (view, GTK_STATE_NORMAL, &colors[COL_BG]);*/ gtk_widget_set_can_focus (view, FALSE); @@ -160,6 +176,7 @@ cv_tree_init (chanview *cv) 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_set_attributes (col, renderer, "text", COL_NAME, "attributes", COL_ATTR, NULL); + gtk_tree_view_column_set_expand (col, TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (view))), diff --git a/src/fe-gtk/chanview.c b/src/fe-gtk/chanview.c index c4520df3..f4055d54 100644 --- a/src/fe-gtk/chanview.c +++ b/src/fe-gtk/chanview.c @@ -45,7 +45,11 @@ struct _chanview int size; /* number of channels in view */ GtkWidget *box; /* the box we destroy when changing implementations */ - GtkStyle *style; /* style used for tree */ +#if HAVE_GTK3 + PangoFontDescription *font_desc; /* font used for tree */ +#else + InputStyle *style; /* style used for tree */ +#endif chan *focused; /* currently focused channel */ int trunc_len; @@ -109,6 +113,7 @@ chanview_apply_theme (chanview *cv) { GtkWidget *w; treeview *tv; + const PangoFontDescription *font = NULL; if (cv == NULL) return; @@ -122,16 +127,17 @@ chanview_apply_theme (chanview *cv) return; w = GTK_WIDGET (tv->tree); + if (input_style) + font = input_style->font_desc; + if (fe_dark_mode_is_enabled () || prefs.hex_gui_dark_mode == ZOITECHAT_DARK_MODE_LIGHT) { - gtk_widget_modify_base (w, GTK_STATE_NORMAL, &colors[COL_BG]); - gtk_widget_modify_text (w, GTK_STATE_NORMAL, &colors[COL_FG]); + gtkutil_apply_palette (w, &colors[COL_BG], &colors[COL_FG], font); } else { - /* Revert back to theme defaults. */ - gtk_widget_modify_base (w, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_text (w, GTK_STATE_NORMAL, NULL); + /* Keep list font in sync while reverting colors to theme defaults. */ + gtkutil_apply_palette (w, NULL, NULL, font); } } @@ -294,15 +300,28 @@ chanview_box_destroy_cb (GtkWidget *box, chanview *cv) chanview * chanview_new (int type, int trunc_len, gboolean sort, gboolean use_icons, - GtkStyle *style) +#if HAVE_GTK3 + PangoFontDescription *font_desc +#else + InputStyle *style +#endif +) { chanview *cv; cv = g_new0 (chanview, 1); cv->store = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, PANGO_TYPE_ATTR_LIST, GDK_TYPE_PIXBUF); +#if HAVE_GTK3 + cv->font_desc = font_desc; +#else cv->style = style; +#endif +#if HAVE_GTK3 + cv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); +#elif !HAVE_GTK3 cv->box = gtk_hbox_new (0, 0); +#endif cv->trunc_len = trunc_len; cv->sorted = sort; cv->use_icons = use_icons; diff --git a/src/fe-gtk/chanview.h b/src/fe-gtk/chanview.h index ae77d6b1..9b597a1a 100644 --- a/src/fe-gtk/chanview.h +++ b/src/fe-gtk/chanview.h @@ -20,10 +20,18 @@ #ifndef ZOITECHAT_CHANVIEW_H #define ZOITECHAT_CHANVIEW_H +#include "fe-gtk.h" + typedef struct _chanview chanview; typedef struct _chan chan; -chanview *chanview_new (int type, int trunc_len, gboolean sort, gboolean use_icons, GtkStyle *style); +chanview *chanview_new (int type, int trunc_len, gboolean sort, gboolean use_icons, +#if HAVE_GTK3 + PangoFontDescription *font_desc +#else + InputStyle *style +#endif +); void chanview_set_callbacks (chanview *cv, void (*cb_focus) (chanview *, chan *, int tag, void *userdata), void (*cb_xbutton) (chanview *, chan *, int tag, void *userdata), diff --git a/src/fe-gtk/custom-list.c b/src/fe-gtk/custom-list.c index 0e66ce2f..58e218b4 100644 --- a/src/fe-gtk/custom-list.c +++ b/src/fe-gtk/custom-list.c @@ -101,9 +101,13 @@ static void custom_list_sortable_set_default_sort_func (GtkTreeSortable * static gboolean custom_list_sortable_has_default_sort_func (GtkTreeSortable * sortable); +static void custom_list_sortable_init (GtkTreeSortableIface * iface); -static GObjectClass *parent_class = NULL; /* GObject stuff - nothing to worry about */ + +G_DEFINE_TYPE_WITH_CODE (CustomList, custom_list, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, custom_list_tree_model_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE, custom_list_sortable_init)) static void @@ -116,70 +120,6 @@ custom_list_sortable_init (GtkTreeSortableIface * iface) iface->has_default_sort_func = custom_list_sortable_has_default_sort_func; /* NOT SUPPORTED */ } -/***************************************************************************** - * - * custom_list_get_type: here we register our new type and its interfaces - * with the type system. If you want to implement - * additional interfaces like GtkTreeSortable, you - * will need to do it here. - * - *****************************************************************************/ - -GType -custom_list_get_type (void) -{ - static GType custom_list_type = 0; - - if (custom_list_type) - return custom_list_type; - - /* Some boilerplate type registration stuff */ - { - static const GTypeInfo custom_list_info = { - sizeof (CustomListClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) custom_list_class_init, - NULL, /* class finalize */ - NULL, /* class_data */ - sizeof (CustomList), - 0, /* n_preallocs */ - (GInstanceInitFunc) custom_list_init - }; - - custom_list_type = - g_type_register_static (G_TYPE_OBJECT, "CustomList", - &custom_list_info, (GTypeFlags) 0); - } - - /* Here we register our GtkTreeModel interface with the type system */ - { - static const GInterfaceInfo tree_model_info = { - (GInterfaceInitFunc) custom_list_tree_model_init, - NULL, - NULL - }; - - g_type_add_interface_static (custom_list_type, GTK_TYPE_TREE_MODEL, - &tree_model_info); - } - - /* Add GtkTreeSortable interface */ - { - static const GInterfaceInfo tree_sortable_info = { - (GInterfaceInitFunc) custom_list_sortable_init, - NULL, - NULL - }; - - g_type_add_interface_static (custom_list_type, - GTK_TYPE_TREE_SORTABLE, - &tree_sortable_info); - } - - return custom_list_type; -} - /***************************************************************************** * * custom_list_class_init: more boilerplate GObject/GType stuff. @@ -193,7 +133,6 @@ custom_list_class_init (CustomListClass * klass) { GObjectClass *object_class; - parent_class = (GObjectClass *) g_type_class_peek_parent (klass); object_class = (GObjectClass *) klass; object_class->finalize = custom_list_finalize; @@ -265,7 +204,7 @@ custom_list_finalize (GObject * object) custom_list_clear (CUSTOM_LIST (object)); /* must chain up - finalize parent */ - (*parent_class->finalize) (object); + G_OBJECT_CLASS (custom_list_parent_class)->finalize (object); } diff --git a/src/fe-gtk/custom-list.h b/src/fe-gtk/custom-list.h index 96aa75cf..29bbfa51 100644 --- a/src/fe-gtk/custom-list.h +++ b/src/fe-gtk/custom-list.h @@ -22,6 +22,9 @@ #include +typedef struct _CustomList CustomList; +typedef struct _CustomListClass CustomListClass; + GType custom_list_get_type (void); /* Some boilerplate GObject defines. 'klass' is used @@ -62,20 +65,19 @@ typedef struct } chanlistrow; -typedef struct _CustomList CustomList; -typedef struct _CustomListClass CustomListClass; - - - /* CustomList: this structure contains everything we need for our * model implementation. You can add extra fields to * this structure, e.g. hashtables to quickly lookup * rows or whatever else you might need, but it is - * crucial that 'parent' is the first member of the + * crucial that 'parent_instance' is the first member of the * structure. */ struct _CustomList { +#if HAVE_GTK3 + GObject parent_instance; +#else GObject parent; +#endif guint num_rows; /* number of rows that we have used */ guint num_alloc; /* number of rows allocated */ diff --git a/src/fe-gtk/dccgui.c b/src/fe-gtk/dccgui.c index fc199d7d..97959fbb 100644 --- a/src/fe-gtk/dccgui.c +++ b/src/fe-gtk/dccgui.c @@ -37,6 +37,19 @@ #include "palette.h" #include "maingui.h" +#if HAVE_GTK3 +#define ICON_DCC_CANCEL "dialog-cancel" +#define ICON_DCC_ACCEPT "dialog-apply" +#define ICON_DCC_RESUME "view-refresh" +#define ICON_DCC_CLEAR "edit-clear" +#endif +#if !HAVE_GTK3 +#define ICON_DCC_CANCEL GTK_STOCK_CANCEL +#define ICON_DCC_ACCEPT GTK_STOCK_APPLY +#define ICON_DCC_RESUME GTK_STOCK_REFRESH +#define ICON_DCC_CLEAR GTK_STOCK_CLEAR +#endif + enum /* DCC SEND/RECV */ { @@ -50,7 +63,7 @@ enum /* DCC SEND/RECV */ COL_ETA, COL_NICK, COL_DCC, /* struct DCC * */ - COL_COLOR, /* GdkColor */ + COL_COLOR, /* PaletteColor */ N_COLUMNS }; @@ -62,7 +75,7 @@ enum /* DCC CHAT */ CCOL_SENT, CCOL_START, CCOL_DCC, /* struct DCC * */ - CCOL_COLOR, /* GdkColor * */ + CCOL_COLOR, /* PaletteColor * */ CN_COLUMNS }; @@ -103,6 +116,26 @@ static short view_mode; /* 1=download 2=upload 3=both */ #define VIEW_UPLOAD 2 #define VIEW_BOTH 3 +#if HAVE_GTK3 +static GdkPixbuf * +dcc_load_icon (const char *stock_name) +{ + GtkIconTheme *theme = gtk_icon_theme_get_default (); + const char *icon_name = gtkutil_icon_name_from_stock (stock_name); + int width = 16; + int height = 16; + + if (g_strcmp0 (stock_name, "gtk-go-up") == 0) + icon_name = "go-up"; + else if (g_strcmp0 (stock_name, "gtk-go-down") == 0) + icon_name = "go-down"; + + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height); + + return gtk_icon_theme_load_icon (theme, icon_name, width, 0, NULL); +} +#endif + static void proper_unit (guint64 size, char *buf, size_t buf_len) @@ -151,6 +184,29 @@ fe_dcc_send_filereq (struct session *sess, char *nick, int maxcps, int passive) g_free (tbuf); } +static void +dcc_store_color (GtkListStore *store, GtkTreeIter *iter, int column, int color_index) +{ + const PaletteColor *color = NULL; + + if (color_index != 1) + color = &colors[color_index]; + +#if HAVE_GTK3 + if (color) + { + GdkRGBA rgba = *color; + gtk_list_store_set (store, iter, column, &rgba, -1); + } + else + { + gtk_list_store_set (store, iter, column, NULL, -1); + } +#else + gtk_list_store_set (store, iter, column, color, -1); +#endif +} + static void dcc_prepare_row_chat (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, gboolean update_only) @@ -171,11 +227,8 @@ dcc_prepare_row_chat (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, CCOL_SENT, size, CCOL_START, date, CCOL_DCC, dcc, - CCOL_COLOR, - dccstat[dcc->dccstat].color == 1 ? - NULL : - colors + dccstat[dcc->dccstat].color, -1); + dcc_store_color (store, iter, CCOL_COLOR, dccstat[dcc->dccstat].color); } static void @@ -187,8 +240,12 @@ dcc_prepare_row_send (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, float per; if (!pix_up) +#if HAVE_GTK3 + pix_up = dcc_load_icon ("gtk-go-up"); +#elif !HAVE_GTK3 pix_up = gtk_widget_render_icon (dccfwin.window, "gtk-go-up", GTK_ICON_SIZE_MENU, NULL); +#endif /* percentage ack'ed */ per = (float) ((dcc->ack * 100.00) / dcc->size); @@ -211,10 +268,6 @@ dcc_prepare_row_send (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, COL_PERC, perc, COL_SPEED, kbs, COL_ETA, eta, - COL_COLOR, - dccstat[dcc->dccstat].color == 1 ? - NULL : - colors + dccstat[dcc->dccstat].color, -1); else gtk_list_store_set (store, iter, @@ -228,11 +281,8 @@ dcc_prepare_row_send (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, COL_ETA, eta, COL_NICK, dcc->nick, COL_DCC, dcc, - COL_COLOR, - dccstat[dcc->dccstat].color == 1 ? - NULL : - colors + dccstat[dcc->dccstat].color, -1); + dcc_store_color (store, iter, COL_COLOR, dccstat[dcc->dccstat].color); } static void @@ -244,8 +294,12 @@ dcc_prepare_row_recv (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, int to_go; if (!pix_dn) +#if HAVE_GTK3 + pix_dn = dcc_load_icon ("gtk-go-down"); +#elif !HAVE_GTK3 pix_dn = gtk_widget_render_icon (dccfwin.window, "gtk-go-down", GTK_ICON_SIZE_MENU, NULL); +#endif proper_unit (dcc->size, size, sizeof (size)); if (dcc->dccstat == STAT_QUEUED) @@ -271,10 +325,6 @@ dcc_prepare_row_recv (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, COL_PERC, perc, COL_SPEED, kbs, COL_ETA, eta, - COL_COLOR, - dccstat[dcc->dccstat].color == 1 ? - NULL : - colors + dccstat[dcc->dccstat].color, -1); else gtk_list_store_set (store, iter, @@ -288,11 +338,8 @@ dcc_prepare_row_recv (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, COL_ETA, eta, COL_NICK, dcc->nick, COL_DCC, dcc, - COL_COLOR, - dccstat[dcc->dccstat].color == 1 ? - NULL : - colors + dccstat[dcc->dccstat].color, -1); + dcc_store_color (store, iter, COL_COLOR, dccstat[dcc->dccstat].color); } static gboolean @@ -730,7 +777,7 @@ dcc_add_column (GtkWidget *tree, int textcol, int colorcol, char *title, gboolea if (right_justified) g_object_set (G_OBJECT (renderer), "xalign", (float) 1.0, NULL); gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree), -1, title, renderer, - "text", textcol, "foreground-gdk", colorcol, + "text", textcol, PALETTE_FOREGROUND_PROPERTY, colorcol, NULL); gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1); } @@ -744,13 +791,31 @@ dcc_detail_label (char *text, GtkWidget *box, int num) label = gtk_label_new (NULL); g_snprintf (buf, sizeof (buf), "%s", text); gtk_label_set_markup (GTK_LABEL (label), buf); +#if HAVE_GTK3 + gtk_widget_set_hexpand (label, FALSE); + gtk_widget_set_vexpand (label, FALSE); + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_START); + gtk_grid_attach (GTK_GRID (box), label, 0, 0 + num, 1, 1); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (box), label, 0, 1, 0 + num, 1 + num, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach (GTK_TABLE (box), label, 0, 1, 0 + num, 1 + num, + GTK_FILL, GTK_FILL, 0, 0); +#endif label = gtk_label_new (NULL); gtk_label_set_selectable (GTK_LABEL (label), TRUE); +#if HAVE_GTK3 + gtk_widget_set_hexpand (label, FALSE); + gtk_widget_set_vexpand (label, FALSE); + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_START); + gtk_grid_attach (GTK_GRID (box), label, 1, 0 + num, 1, 1); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - gtk_table_attach (GTK_TABLE (box), label, 1, 2, 0 + num, 1 + num, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach (GTK_TABLE (box), label, 1, 2, 0 + num, 1 + num, + GTK_FILL, GTK_FILL, 0, 0); +#endif return label; } @@ -789,7 +854,7 @@ dcc_configure_cb (GtkWindow *win, GdkEventConfigure *event, gpointer data) int fe_dcc_open_recv_win (int passive) { - GtkWidget *radio, *table, *vbox, *bbox, *view, *exp, *detailbox; + GtkWidget *radio, *table, *vbox, *bbox, *view, *view_scrolled, *exp, *detailbox; GtkListStore *store; GSList *group; char buf[128]; @@ -810,8 +875,13 @@ fe_dcc_open_recv_win (int passive) store = gtk_list_store_new (N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_COLOR); + G_TYPE_STRING, G_TYPE_POINTER, PALETTE_GDK_TYPE); view = gtkutil_treeview_new (vbox, GTK_TREE_MODEL (store), NULL, -1); + view_scrolled = gtk_widget_get_parent (view); + gtk_widget_set_hexpand (view_scrolled, TRUE); + gtk_widget_set_vexpand (view_scrolled, TRUE); + gtk_widget_set_hexpand (view, TRUE); + gtk_widget_set_vexpand (view, TRUE); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE); /* Up/Down Icon column */ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), -1, NULL, @@ -844,49 +914,106 @@ fe_dcc_open_recv_win (int passive) g_signal_connect (G_OBJECT (view), "row-activated", G_CALLBACK (dcc_dclick_cb), NULL); +#if HAVE_GTK3 + table = gtk_grid_new (); + gtk_grid_set_column_spacing (GTK_GRID (table), 16); +#else table = gtk_table_new (1, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (table), 16); +#endif gtk_box_pack_start (GTK_BOX (vbox), table, 0, 0, 0); radio = gtk_radio_button_new_with_mnemonic (NULL, _("Both")); g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (dcc_toggle), GINT_TO_POINTER (VIEW_BOTH)); +#if HAVE_GTK3 + gtk_widget_set_hexpand (radio, FALSE); + gtk_widget_set_vexpand (radio, FALSE); + gtk_widget_set_halign (radio, GTK_ALIGN_FILL); + gtk_widget_set_valign (radio, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (table), radio, 3, 0, 1, 1); +#else gtk_table_attach (GTK_TABLE (table), radio, 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 0); +#endif group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)); radio = gtk_radio_button_new_with_mnemonic (group, _("Uploads")); g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (dcc_toggle), GINT_TO_POINTER (VIEW_UPLOAD)); +#if HAVE_GTK3 + gtk_widget_set_hexpand (radio, FALSE); + gtk_widget_set_vexpand (radio, FALSE); + gtk_widget_set_halign (radio, GTK_ALIGN_FILL); + gtk_widget_set_valign (radio, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (table), radio, 1, 0, 1, 1); +#else gtk_table_attach (GTK_TABLE (table), radio, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); +#endif group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)); radio = gtk_radio_button_new_with_mnemonic (group, _("Downloads")); g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (dcc_toggle), GINT_TO_POINTER (VIEW_DOWNLOAD)); +#if HAVE_GTK3 + gtk_widget_set_hexpand (radio, FALSE); + gtk_widget_set_vexpand (radio, FALSE); + gtk_widget_set_halign (radio, GTK_ALIGN_FILL); + gtk_widget_set_valign (radio, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (table), radio, 2, 0, 1, 1); +#else gtk_table_attach (GTK_TABLE (table), radio, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0); +#endif exp = gtk_expander_new (_("Details")); +#if HAVE_GTK3 + gtk_widget_set_hexpand (exp, TRUE); + gtk_widget_set_vexpand (exp, FALSE); + gtk_widget_set_halign (exp, GTK_ALIGN_FILL); + gtk_widget_set_valign (exp, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (table), exp, 0, 0, 1, 1); +#else gtk_table_attach (GTK_TABLE (table), exp, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); +#endif +#if HAVE_GTK3 + detailbox = gtk_grid_new (); + gtk_grid_set_column_spacing (GTK_GRID (detailbox), 6); + gtk_grid_set_row_spacing (GTK_GRID (detailbox), 2); + gtk_container_set_border_width (GTK_CONTAINER (detailbox), 6); +#else detailbox = gtk_table_new (3, 3, FALSE); gtk_table_set_col_spacings (GTK_TABLE (detailbox), 6); gtk_table_set_row_spacings (GTK_TABLE (detailbox), 2); gtk_container_set_border_width (GTK_CONTAINER (detailbox), 6); +#endif g_signal_connect (G_OBJECT (exp), "activate", G_CALLBACK (dcc_exp_cb), detailbox); +#if HAVE_GTK3 + gtk_widget_set_hexpand (detailbox, TRUE); + gtk_widget_set_vexpand (detailbox, FALSE); + gtk_widget_set_halign (detailbox, GTK_ALIGN_FILL); + gtk_widget_set_valign (detailbox, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (table), detailbox, 0, 1, 4, 1); +#else gtk_table_attach (GTK_TABLE (table), detailbox, 0, 4, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); +#endif dccfwin.file_label = dcc_detail_label (_("File:"), detailbox, 0); dccfwin.address_label = dcc_detail_label (_("Address:"), detailbox, 1); +#if HAVE_GTK3 + bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 bbox = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD); +#endif gtk_box_pack_end (GTK_BOX (vbox), bbox, FALSE, FALSE, 2); - dccfwin.abort_button = gtkutil_button (bbox, GTK_STOCK_CANCEL, 0, abort_clicked, 0, _("Abort")); - dccfwin.accept_button = gtkutil_button (bbox, GTK_STOCK_APPLY, 0, accept_clicked, 0, _("Accept")); - dccfwin.resume_button = gtkutil_button (bbox, GTK_STOCK_REFRESH, 0, resume_clicked, 0, _("Resume")); - dccfwin.clear_button = gtkutil_button (bbox, GTK_STOCK_CLEAR, 0, clear_completed, 0, _("Clear")); + dccfwin.abort_button = gtkutil_button (bbox, ICON_DCC_CANCEL, 0, abort_clicked, 0, _("Abort")); + dccfwin.accept_button = gtkutil_button (bbox, ICON_DCC_ACCEPT, 0, accept_clicked, 0, _("Accept")); + dccfwin.resume_button = gtkutil_button (bbox, ICON_DCC_RESUME, 0, resume_clicked, 0, _("Resume")); + dccfwin.clear_button = gtkutil_button (bbox, ICON_DCC_CLEAR, 0, clear_completed, 0, _("Clear")); dccfwin.open_button = gtkutil_button (bbox, 0, 0, browse_dcc_folder, 0, _("Open Folder...")); gtk_widget_set_sensitive (dccfwin.accept_button, FALSE); gtk_widget_set_sensitive (dccfwin.resume_button, FALSE); @@ -1036,7 +1163,7 @@ dcc_chat_dclick_cb (GtkTreeView *view, GtkTreePath *path, int fe_dcc_open_chat_win (int passive) { - GtkWidget *view, *vbox, *bbox; + GtkWidget *view, *vbox, *bbox, *scroll; GtkListStore *store; char buf[128]; @@ -1056,9 +1183,11 @@ fe_dcc_open_chat_win (int passive) gtk_box_set_spacing (GTK_BOX (vbox), 3); store = gtk_list_store_new (CN_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_POINTER, GDK_TYPE_COLOR); + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_POINTER, PALETTE_GDK_TYPE); view = gtkutil_treeview_new (vbox, GTK_TREE_MODEL (store), NULL, -1); + scroll = gtk_widget_get_parent (view); + gtk_box_set_child_packing (GTK_BOX (vbox), scroll, TRUE, TRUE, 0, GTK_PACK_START); dcc_add_column (view, CCOL_STATUS, CCOL_COLOR, _("Status"), FALSE); dcc_add_column (view, CCOL_NICK, CCOL_COLOR, _("Nick"), FALSE); @@ -1080,12 +1209,17 @@ fe_dcc_open_chat_win (int passive) g_signal_connect (G_OBJECT (view), "row-activated", G_CALLBACK (dcc_chat_dclick_cb), NULL); +#if HAVE_GTK3 + bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 bbox = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD); +#endif gtk_box_pack_end (GTK_BOX (vbox), bbox, FALSE, FALSE, 2); - dcccwin.abort_button = gtkutil_button (bbox, GTK_STOCK_CANCEL, 0, abort_chat_clicked, 0, _("Abort")); - dcccwin.accept_button = gtkutil_button (bbox, GTK_STOCK_APPLY, 0, accept_chat_clicked, 0, _("Accept")); + dcccwin.abort_button = gtkutil_button (bbox, ICON_DCC_CANCEL, 0, abort_chat_clicked, 0, _("Abort")); + dcccwin.accept_button = gtkutil_button (bbox, ICON_DCC_ACCEPT, 0, accept_chat_clicked, 0, _("Accept")); gtk_widget_set_sensitive (dcccwin.accept_button, FALSE); gtk_widget_set_sensitive (dcccwin.abort_button, FALSE); diff --git a/src/fe-gtk/editlist.c b/src/fe-gtk/editlist.c index f1ac1a81..c8ed9d5e 100644 --- a/src/fe-gtk/editlist.c +++ b/src/fe-gtk/editlist.c @@ -42,6 +42,19 @@ #include "maingui.h" #include "editlist.h" +#if HAVE_GTK3 +#define ICON_EDITLIST_NEW "document-new" +#define ICON_EDITLIST_DELETE "edit-delete" +#define ICON_EDITLIST_CANCEL "dialog-cancel" +#define ICON_EDITLIST_SAVE "document-save" +#endif +#if !HAVE_GTK3 +#define ICON_EDITLIST_NEW GTK_STOCK_NEW +#define ICON_EDITLIST_DELETE GTK_STOCK_DELETE +#define ICON_EDITLIST_CANCEL GTK_STOCK_CANCEL +#define ICON_EDITLIST_SAVE GTK_STOCK_SAVE +#endif + enum { NAME_COLUMN, @@ -316,7 +329,7 @@ editlist_treeview_new (GtkWidget *box, char *title1, char *title2) gtk_tree_view_column_set_min_width (col, 100); gtk_container_add (GTK_CONTAINER (scroll), view); - gtk_container_add (GTK_CONTAINER (box), scroll); + gtk_box_pack_start (GTK_BOX (box), scroll, TRUE, TRUE, 0); gtk_widget_show_all (box); return view; @@ -348,19 +361,24 @@ editlist_gui_open (char *title1, char *title2, GSList *list, char *title, char * if (help) gtk_widget_set_tooltip_text (view, help); +#if HAVE_GTK3 + box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (box), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 box = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (box), GTK_BUTTONBOX_SPREAD); +#endif gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (box), 5); gtk_widget_show (box); - gtkutil_button (box, GTK_STOCK_NEW, 0, editlist_add, + gtkutil_button (box, ICON_EDITLIST_NEW, 0, editlist_add, NULL, _("Add")); - gtkutil_button (box, GTK_STOCK_DELETE, 0, editlist_delete, + gtkutil_button (box, ICON_EDITLIST_DELETE, 0, editlist_delete, NULL, _("Delete")); - gtkutil_button (box, GTK_STOCK_CANCEL, 0, editlist_close, + gtkutil_button (box, ICON_EDITLIST_CANCEL, 0, editlist_close, NULL, _("Cancel")); - gtkutil_button (box, GTK_STOCK_SAVE, 0, editlist_save, + gtkutil_button (box, ICON_EDITLIST_SAVE, 0, editlist_save, file, _("Save")); store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view))); diff --git a/src/fe-gtk/fe-gtk.c b/src/fe-gtk/fe-gtk.c index aa99f0ce..5345ab5f 100644 --- a/src/fe-gtk/fe-gtk.c +++ b/src/fe-gtk/fe-gtk.c @@ -22,8 +22,11 @@ #include "fe-gtk.h" -#ifdef WIN32 +#ifdef GDK_WINDOWING_WIN32 #include +#endif + +#ifdef WIN32 #include #else #include @@ -112,6 +115,27 @@ create_msg_dialog (gchar *title, gchar *message) gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } + +static void +win32_set_gsettings_schema_dir (void) +{ + char *base_path; + char *schema_path; + + if (g_getenv ("GSETTINGS_SCHEMA_DIR") != NULL) + return; + + base_path = g_win32_get_package_installation_directory_of_module (NULL); + if (base_path == NULL) + return; + + schema_path = g_build_filename (base_path, "share", "glib-2.0", "schemas", NULL); + if (g_file_test (schema_path, G_FILE_TEST_IS_DIR)) + g_setenv ("GSETTINGS_SCHEMA_DIR", schema_path, FALSE); + + g_free (schema_path); + g_free (base_path); +} #endif int @@ -120,6 +144,7 @@ fe_args (int argc, char *argv[]) GError *error = NULL; GOptionContext *context; char *buffer; + const char *desktop_id = "net.zoite.Zoitechat"; #ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); @@ -220,6 +245,8 @@ fe_args (int argc, char *argv[]) } #ifdef WIN32 + win32_set_gsettings_schema_dir (); + /* this is mainly for irc:// URL handling. When windows calls us from */ /* I.E, it doesn't give an option of "Start in" directory, like short */ /* cuts can. So we have to set the current dir manually, to the path */ @@ -238,6 +265,10 @@ fe_args (int argc, char *argv[]) } #endif + g_set_prgname (desktop_id); +#ifndef WIN32 + gdk_set_program_class (desktop_id); +#endif gtk_init (&argc, &argv); #ifdef HAVE_GTK_MAC @@ -394,13 +425,32 @@ fe_dark_mode_is_enabled (void) return fe_dark_mode_is_enabled_for (prefs.hex_gui_dark_mode); } -GtkStyle * -create_input_style (GtkStyle *style) +InputStyle * +create_input_style (InputStyle *style) { char buf[256]; static int done_rc = FALSE; +#if HAVE_GTK3 + static GtkCssProvider *input_css_provider = NULL; + static char *last_theme_name = NULL; + static gboolean last_dark_mode = FALSE; + static gboolean last_input_style = FALSE; + static gboolean last_colors_set = FALSE; + static guint16 last_fg_red; + static guint16 last_fg_green; + static guint16 last_fg_blue; + static guint16 last_bg_red; + static guint16 last_bg_green; + static guint16 last_bg_blue; +#endif - pango_font_description_free (style->font_desc); +#if HAVE_GTK3 + if (!style) + style = g_new0 (InputStyle, 1); +#endif + + if (style->font_desc) + pango_font_description_free (style->font_desc); style->font_desc = pango_font_description_from_string (prefs.hex_text_font); /* fall back */ @@ -412,27 +462,159 @@ create_input_style (GtkStyle *style) style->font_desc = pango_font_description_from_string ("sans 11"); } - if (prefs.hex_gui_input_style && !done_rc) + if (prefs.hex_gui_input_style) { +#if !HAVE_GTK3 + if (!done_rc) + { + GtkSettings *settings = gtk_settings_get_default (); + char *theme_name; + + /* gnome-themes-standard 3.20+ relies on images to do theming + * so we have to override that. */ + g_object_get (settings, "gtk-theme-name", &theme_name, NULL); + if (g_str_has_prefix (theme_name, "Adwaita") || g_str_has_prefix (theme_name, "Yaru")) + gtk_rc_parse_string (adwaita_workaround_rc); + g_free (theme_name); + + { + guint16 red; + guint16 green; + guint16 blue; + + palette_color_get_rgb16 (&colors[COL_FG], &red, &green, &blue); + sprintf (buf, cursor_color_rc, (red >> 8), (green >> 8), (blue >> 8)); + } + gtk_rc_parse_string (buf); + done_rc = TRUE; + } +#else GtkSettings *settings = gtk_settings_get_default (); + GdkScreen *screen = gdk_screen_get_default (); char *theme_name; + char cursor_rc[sizeof (cursor_color_rc)]; + char cursor_color[8]; + const char *cursor_color_start = NULL; + guint16 fg_red; + guint16 fg_green; + guint16 fg_blue; + guint16 bg_red; + guint16 bg_green; + guint16 bg_blue; + gboolean dark_mode = fe_dark_mode_is_enabled (); + gboolean needs_reload; - /* gnome-themes-standard 3.20+ relies on images to do theming - * so we have to override that. */ g_object_get (settings, "gtk-theme-name", &theme_name, NULL); - if (g_str_has_prefix (theme_name, "Adwaita") || g_str_has_prefix (theme_name, "Yaru")) - gtk_rc_parse_string (adwaita_workaround_rc); + + palette_color_get_rgb16 (&colors[COL_FG], &fg_red, &fg_green, &fg_blue); + palette_color_get_rgb16 (&colors[COL_BG], &bg_red, &bg_green, &bg_blue); + needs_reload = !done_rc + || !last_input_style + || last_dark_mode != dark_mode + || g_strcmp0 (last_theme_name, theme_name) != 0 + || !last_colors_set + || last_fg_red != fg_red + || last_fg_green != fg_green + || last_fg_blue != fg_blue + || last_bg_red != bg_red + || last_bg_green != bg_green + || last_bg_blue != bg_blue; + + if (needs_reload) + { + if (!input_css_provider) + input_css_provider = gtk_css_provider_new (); + + g_snprintf (buf, sizeof (buf), "#%02x%02x%02x", + (fg_red >> 8), (fg_green >> 8), (fg_blue >> 8)); + g_snprintf (cursor_rc, sizeof (cursor_rc), cursor_color_rc, + (fg_red >> 8), (fg_green >> 8), (fg_blue >> 8)); + cursor_color_start = g_strstr_len (cursor_rc, -1, "cursor-color=\""); + if (cursor_color_start) + { + cursor_color_start += strlen ("cursor-color=\""); + g_strlcpy (cursor_color, cursor_color_start, sizeof (cursor_color)); + cursor_color[7] = '\0'; + } + else + { + g_strlcpy (cursor_color, buf, sizeof (cursor_color)); + } + { + GString *css = g_string_new ("#zoitechat-inputbox {"); + + /* GTK3 equivalents for adwaita_workaround_rc/cursor_color_rc. */ + if (adwaita_workaround_rc[0] != '\0' + && (g_str_has_prefix (theme_name, "Adwaita") + || g_str_has_prefix (theme_name, "Yaru"))) + g_string_append (css, "background-image: none;"); + + g_string_append_printf ( + css, + "background-color: #%02x%02x%02x;" + "color: #%02x%02x%02x;" + "caret-color: %s;" + "}" + "#zoitechat-inputbox text {" + "color: #%02x%02x%02x;" + "caret-color: %s;" + "}", + (bg_red >> 8), (bg_green >> 8), (bg_blue >> 8), + (fg_red >> 8), (fg_green >> 8), (fg_blue >> 8), + cursor_color, + (fg_red >> 8), (fg_green >> 8), (fg_blue >> 8), + cursor_color); + gtk_css_provider_load_from_data (input_css_provider, css->str, -1, NULL); + g_string_free (css, TRUE); + } + + if (screen) + gtk_style_context_add_provider_for_screen ( + screen, + GTK_STYLE_PROVIDER (input_css_provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + done_rc = TRUE; + last_input_style = TRUE; + last_dark_mode = dark_mode; + last_colors_set = TRUE; + last_fg_red = fg_red; + last_fg_green = fg_green; + last_fg_blue = fg_blue; + last_bg_red = bg_red; + last_bg_green = bg_green; + last_bg_blue = bg_blue; + g_free (last_theme_name); + last_theme_name = g_strdup (theme_name); + } + g_free (theme_name); - - done_rc = TRUE; - sprintf (buf, cursor_color_rc, (colors[COL_FG].red >> 8), - (colors[COL_FG].green >> 8), (colors[COL_FG].blue >> 8)); - gtk_rc_parse_string (buf); +#endif } +#if HAVE_GTK3 + else + { + GdkScreen *screen = gdk_screen_get_default (); + if (input_css_provider && screen) + { + gtk_style_context_remove_provider_for_screen ( + screen, + GTK_STYLE_PROVIDER (input_css_provider)); + } + g_clear_object (&input_css_provider); + g_clear_pointer (&last_theme_name, g_free); + done_rc = FALSE; + last_input_style = FALSE; + last_colors_set = FALSE; + } +#endif + +#if !HAVE_GTK3 style->bg[GTK_STATE_NORMAL] = colors[COL_FG]; style->base[GTK_STATE_NORMAL] = colors[COL_BG]; style->text[GTK_STATE_NORMAL] = colors[COL_FG]; +#endif return style; } @@ -451,7 +633,11 @@ fe_init (void) gtkosx_application_set_dock_icon_pixbuf (osx_app, pix_zoitechat); #endif channelwin_pix = pixmap_load_from_file (prefs.hex_text_background); +#if HAVE_GTK3 + input_style = create_input_style (input_style); +#else input_style = create_input_style (gtk_style_new ()); +#endif settings = gtk_settings_get_default (); if (settings) @@ -1074,8 +1260,8 @@ fe_gui_info_ptr (session *sess, int info_type) switch (info_type) { case 0: /* native window pointer (for plugins) */ -#ifdef WIN32 - return gdk_win32_window_get_impl_hwnd (gtk_widget_get_window (sess->gui->window)); +#ifdef GDK_WINDOWING_WIN32 + return gdk_win32_window_get_handle (gtk_widget_get_window (sess->gui->window)); #else return sess->gui->window; #endif diff --git a/src/fe-gtk/fe-gtk.h b/src/fe-gtk/fe-gtk.h index 6d9ca0b1..03e55508 100644 --- a/src/fe-gtk/fe-gtk.h +++ b/src/fe-gtk/fe-gtk.h @@ -32,6 +32,22 @@ #include #include +#ifndef HAVE_GTK3 +#if GTK_MAJOR_VERSION >= 3 +#define HAVE_GTK3 1 +#else +#define HAVE_GTK3 0 +#endif +#endif + +#if !HAVE_GTK3 +/* GtkWidget expansion APIs were introduced in GTK3. Keep GTK2 builds + * source-compatible by accepting the calls as no-ops. + */ +#define gtk_widget_set_hexpand(widget, expand) G_STMT_START { (void) (widget); (void) (expand); } G_STMT_END +#define gtk_widget_set_vexpand(widget, expand) G_STMT_START { (void) (widget); (void) (expand); } G_STMT_END +#endif + #ifdef HAVE_GTK_MAC #include #endif @@ -48,6 +64,15 @@ #define flag_b flag_wid[7] #define NUM_FLAG_WIDS 8 +#if HAVE_GTK3 +typedef struct _input_style +{ + PangoFontDescription *font_desc; +} InputStyle; +#else +typedef GtkStyle InputStyle; +#endif + #ifdef HAVE_GTK_MAC extern GtkosxApplication *osx_app; #endif diff --git a/src/fe-gtk/fe-gtk.vcxproj b/src/fe-gtk/fe-gtk.vcxproj index 94277696..aa9bd954 100644 --- a/src/fe-gtk/fe-gtk.vcxproj +++ b/src/fe-gtk/fe-gtk.vcxproj @@ -30,7 +30,7 @@ WIN32;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions) - ..\common;$(ZoiteChatLib);$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories) + ..\common;$(ZoiteChatLib);$(DepsRoot)\include;$(OpenSslInclude);$(Glib);$(Gtk);%(AdditionalIncludeDirectories) 4244;%(DisableSpecificWarnings) @@ -42,7 +42,7 @@ WIN32;_WIN64;_AMD64_;NDEBUG;_WINDOWS;$(OwnFlags);%(PreprocessorDefinitions) - ..\common;$(ZoiteChatLib);$(DepsRoot)\include;$(Glib);$(Gtk);%(AdditionalIncludeDirectories) + ..\common;$(ZoiteChatLib);$(DepsRoot)\include;$(OpenSslInclude);$(Glib);$(Gtk);%(AdditionalIncludeDirectories) 4244;4267;%(DisableSpecificWarnings) diff --git a/src/fe-gtk/fkeys.c b/src/fe-gtk/fkeys.c index 914c0283..4ed4a64a 100644 --- a/src/fe-gtk/fkeys.c +++ b/src/fe-gtk/fkeys.c @@ -53,6 +53,19 @@ #include "textgui.h" #include "fkeys.h" +#if HAVE_GTK3 +#define ICON_FKEYS_NEW "document-new" +#define ICON_FKEYS_DELETE "edit-delete" +#define ICON_FKEYS_CANCEL "dialog-cancel" +#define ICON_FKEYS_SAVE "document-save" +#endif +#if !HAVE_GTK3 +#define ICON_FKEYS_NEW GTK_STOCK_NEW +#define ICON_FKEYS_DELETE GTK_STOCK_DELETE +#define ICON_FKEYS_CANCEL GTK_STOCK_CANCEL +#define ICON_FKEYS_SAVE GTK_STOCK_SAVE +#endif + static void replace_handle (GtkWidget * wid); void key_check_replace_on_change (GtkEditable *editable, gpointer data); void key_action_tab_clean (void); @@ -137,14 +150,77 @@ static int key_action_put_history (GtkWidget * wid, GdkEventKey * evt, static GSList *keybind_list = NULL; +static gsize +key_action_decode_escapes (const char *input, char *output) +{ + gsize ii; + gsize oi = 0; + gsize len = strlen (input); + + for (ii = 0; ii < len; ii++) + { + if (input[ii] != '\\') + { + output[oi++] = input[ii]; + continue; + } + + if (ii + 1 >= len) + { + output[oi++] = '\\'; + break; + } + + ii++; + + switch (input[ii]) + { + case 'n': + output[oi++] = '\n'; + break; + case 'r': + output[oi++] = '\r'; + break; + case 't': + output[oi++] = '\t'; + break; + case '\\': + output[oi++] = '\\'; + break; + case 'x': + if (ii + 2 < len && g_ascii_isxdigit (input[ii + 1]) && + g_ascii_isxdigit (input[ii + 2])) + { + output[oi++] = + (g_ascii_xdigit_value (input[ii + 1]) << 4) | + g_ascii_xdigit_value (input[ii + 2]); + ii += 2; + } + else + { + output[oi++] = '\\'; + output[oi++] = 'x'; + } + break; + default: + output[oi++] = '\\'; + output[oi++] = input[ii]; + break; + } + } + + output[oi] = 0; + return oi; +} + static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = { {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. When run all \002\\n\002 characters in Data 1 are used to deliminate separate commands so it is possible to run more than one command. If you want a \002\\\002 in the actual text run then enter \002\\\\\002")}, + 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", 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)")}, {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")}, + 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", N_("The \002Scroll Page\002 command scrolls the text widget up or down one page or one line. Set Data 1 to either Top, Bottom, Up, Down, +1 or -1.")}, {key_action_set_buffer, "Set Buffer", @@ -189,6 +265,7 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = { "ACCEL=k\nInsert in Buffer\nD1:\003\nD2!\n\n"\ "ACCEL=i\nInsert in Buffer\nD1:\035\nD2!\n\n"\ "ACCEL=u\nInsert in Buffer\nD1:\037\nD2!\n\n"\ + "ACCEL=s\nInsert in Buffer\nD1:\036\nD2!\n\n"\ "ACCEL=r\nInsert in Buffer\nD1:\026\nD2!\n\n"\ "ACCEL=Page_Down\nChange Selected Nick\nD1!\nD2!\n\n"\ "ACCEL=Page_Up\nChange Selected Nick\nD1:Up\nD2!\n\n"\ @@ -676,7 +753,30 @@ key_dialog_treeview_new (GtkWidget *box) g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW(view))), "changed", G_CALLBACK (key_dialog_selection_changed), NULL); +#if HAVE_GTK3 + gtk_widget_set_name (view, "fkeys-treeview"); + { + GtkCssProvider *provider = gtk_css_provider_new (); + GtkStyleContext *context = gtk_widget_get_style_context (view); + + gtk_css_provider_load_from_data ( + provider, + "treeview#fkeys-treeview row:nth-child(odd) {" + " background-color: @theme_base_color;" + "}" + "treeview#fkeys-treeview row:nth-child(even) {" + " background-color: shade(@theme_base_color, 0.96);" + "}", + -1, + NULL); + gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref (provider); + } +#endif +#if !HAVE_GTK3 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE); +#endif render = gtk_cell_renderer_accel_new (); g_object_set (render, "editable", TRUE, @@ -762,7 +862,7 @@ key_dialog_treeview_new (GtkWidget *box) gtk_tree_view_column_set_resizable (col, TRUE); gtk_container_add (GTK_CONTAINER (scroll), view); - gtk_container_add (GTK_CONTAINER (box), scroll); + gtk_box_pack_start (GTK_BOX (box), scroll, TRUE, TRUE, 0); return view; } @@ -825,18 +925,23 @@ key_dialog_show () g_object_set_data (G_OBJECT (key_dialog), "view", view); g_object_set_data (G_OBJECT (key_dialog), "xtext", xtext); +#if HAVE_GTK3 + box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (box), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 box = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (box), GTK_BUTTONBOX_SPREAD); +#endif gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (box), 5); - gtkutil_button (box, GTK_STOCK_NEW, NULL, key_dialog_add, + gtkutil_button (box, ICON_FKEYS_NEW, NULL, key_dialog_add, NULL, _("Add")); - gtkutil_button (box, GTK_STOCK_DELETE, NULL, key_dialog_delete, + gtkutil_button (box, ICON_FKEYS_DELETE, NULL, key_dialog_delete, NULL, _("Delete")); - gtkutil_button (box, GTK_STOCK_CANCEL, NULL, key_dialog_close, + gtkutil_button (box, ICON_FKEYS_CANCEL, NULL, key_dialog_close, NULL, _("Cancel")); - gtkutil_button (box, GTK_STOCK_SAVE, NULL, key_dialog_save, + gtkutil_button (box, ICON_FKEYS_SAVE, NULL, key_dialog_save, NULL, _("Save")); store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view))); @@ -1121,38 +1226,16 @@ static int key_action_handle_command (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess) { - int ii, oi, len; - char out[2048], d = 0; + char *out; if (!d1) return 0; - len = strlen (d1); - - /* Replace each "\n" substring with '\n' */ - for (ii = oi = 0; ii < len; ii++) - { - d = d1[ii]; - if (d == '\\') - { - ii++; - d = d1[ii]; - if (d == 'n') - out[oi++] = '\n'; - else if (d == '\\') - out[oi++] = '\\'; - else - { - out[oi++] = '\\'; - out[oi++] = d; - } - continue; - } - out[oi++] = d; - } - out[oi] = 0; + out = g_malloc (strlen (d1) + 1); + key_action_decode_escapes (d1, out); handle_multiline (sess, out, 0, 0); + g_free (out); return 0; } @@ -1234,13 +1317,19 @@ key_action_insert (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2, struct session *sess) { int tmp_pos; + char *decoded; + gsize decoded_len; if (!d1) return 1; + decoded = g_malloc (strlen (d1) + 1); + decoded_len = key_action_decode_escapes (d1, decoded); + tmp_pos = SPELL_ENTRY_GET_POS (wid); - SPELL_ENTRY_INSERT (wid, d1, strlen (d1), &tmp_pos); + SPELL_ENTRY_INSERT (wid, decoded, decoded_len, &tmp_pos); SPELL_ENTRY_SET_POS (wid, tmp_pos); + g_free (decoded); return 2; } diff --git a/src/fe-gtk/gtkutil.c b/src/fe-gtk/gtkutil.c index 22463555..9aa64ec1 100644 --- a/src/fe-gtk/gtkutil.c +++ b/src/fe-gtk/gtkutil.c @@ -62,6 +62,294 @@ struct file_req int flags; /* FRF_* flags */ }; +#if HAVE_GTK3 +const char * +gtkutil_icon_name_from_stock (const char *stock_name) +{ + static const struct + { + const char *stock; + const char *icon; + } icon_map[] = { + { "gtk-new", "document-new" }, + { "gtk-open", "document-open" }, + { "gtk-revert-to-saved", "document-open" }, + { "gtk-save", "document-save" }, + { "gtk-save-as", "document-save-as" }, + { "gtk-add", "list-add" }, + { "gtk-cancel", "dialog-cancel" }, + { "gtk-ok", "dialog-ok" }, + { "gtk-no", "dialog-cancel" }, + { "gtk-yes", "dialog-ok" }, + { "gtk-apply", "dialog-apply" }, + { "gtk-dialog-error", "dialog-error" }, + { "gtk-copy", "edit-copy" }, + { "gtk-delete", "edit-delete" }, + { "gtk-remove", "list-remove" }, + { "gtk-clear", "edit-clear" }, + { "gtk-redo", "edit-redo" }, + { "gtk-find", "edit-find" }, + { "gtk-justify-left", "edit-find" }, + { "gtk-refresh", "view-refresh" }, + { "gtk-go-back", "go-previous" }, + { "gtk-go-forward", "go-next" }, + { "gtk-index", "view-list" }, + { "gtk-jump-to", "go-jump" }, + { "gtk-media-play", "media-playback-start" }, + { "gtk-preferences", "preferences-system" }, + { "gtk-help", "help-browser" }, + { "gtk-about", "help-about" }, + { "gtk-close", "window-close" }, + { "gtk-quit", "application-exit" }, + { "gtk-connect", "network-connect" }, + { "gtk-disconnect", "network-disconnect" }, + { "gtk-network", "network-workgroup" }, + { "gtk-spell-check", "tools-check-spelling" }, + }; + size_t i; + + if (!stock_name) + return NULL; + + for (i = 0; i < G_N_ELEMENTS (icon_map); i++) + { + if (strcmp (stock_name, icon_map[i].stock) == 0) + return icon_map[i].icon; + } + + return stock_name; +} +#endif + +GtkWidget * +gtkutil_image_new_from_stock (const char *stock, GtkIconSize size) +{ +#if HAVE_GTK3 + const char *icon_name = gtkutil_icon_name_from_stock (stock); + + return gtk_image_new_from_icon_name (icon_name, size); +#elif !HAVE_GTK3 + return gtk_image_new_from_stock (stock, size); +#endif +} + +GtkWidget * +gtkutil_button_new_from_stock (const char *stock, const char *label) +{ +#if HAVE_GTK3 + GtkWidget *button = label ? gtk_button_new_with_mnemonic (label) : gtk_button_new (); + + if (stock) + { + GtkWidget *image = gtkutil_image_new_from_stock (stock, GTK_ICON_SIZE_BUTTON); + + if (image) + { + gtk_button_set_image (GTK_BUTTON (button), image); + gtk_button_set_always_show_image (GTK_BUTTON (button), TRUE); + } + } + + return button; +#elif !HAVE_GTK3 + if (stock) + return gtk_button_new_from_stock (stock); + if (label) + return gtk_button_new_with_mnemonic (label); + return gtk_button_new (); +#endif +} + +#if HAVE_GTK3 +void +gtkutil_append_font_css (GString *css, const PangoFontDescription *font_desc) +{ + PangoFontMask mask; + + if (!font_desc) + return; + + mask = pango_font_description_get_set_fields (font_desc); + + if (mask & PANGO_FONT_MASK_FAMILY) + { + const char *family = pango_font_description_get_family (font_desc); + + if (family && *family) + g_string_append_printf (css, " font-family: \"%s\";", family); + } + + if (mask & PANGO_FONT_MASK_STYLE) + { + const char *style = "normal"; + + switch (pango_font_description_get_style (font_desc)) + { + case PANGO_STYLE_ITALIC: + style = "italic"; + break; + case PANGO_STYLE_OBLIQUE: + style = "oblique"; + break; + default: + style = "normal"; + break; + } + + g_string_append_printf (css, " font-style: %s;", style); + } + + if (mask & PANGO_FONT_MASK_VARIANT) + { + const char *variant = "normal"; + + if (pango_font_description_get_variant (font_desc) == PANGO_VARIANT_SMALL_CAPS) + variant = "small-caps"; + + g_string_append_printf (css, " font-variant: %s;", variant); + } + + if (mask & PANGO_FONT_MASK_WEIGHT) + { + int weight = (int) pango_font_description_get_weight (font_desc); + + if (weight < 100) + weight = 100; + if (weight > 900) + weight = 900; + + g_string_append_printf (css, " font-weight: %d;", weight); + } + + if (mask & PANGO_FONT_MASK_STRETCH) + { + const char *stretch = "normal"; + + switch (pango_font_description_get_stretch (font_desc)) + { + case PANGO_STRETCH_ULTRA_CONDENSED: + stretch = "ultra-condensed"; + break; + case PANGO_STRETCH_EXTRA_CONDENSED: + stretch = "extra-condensed"; + break; + case PANGO_STRETCH_CONDENSED: + stretch = "condensed"; + break; + case PANGO_STRETCH_SEMI_CONDENSED: + stretch = "semi-condensed"; + break; + case PANGO_STRETCH_SEMI_EXPANDED: + stretch = "semi-expanded"; + break; + case PANGO_STRETCH_EXPANDED: + stretch = "expanded"; + break; + case PANGO_STRETCH_EXTRA_EXPANDED: + stretch = "extra-expanded"; + break; + case PANGO_STRETCH_ULTRA_EXPANDED: + stretch = "ultra-expanded"; + break; + default: + stretch = "normal"; + break; + } + + g_string_append_printf (css, " font-stretch: %s;", stretch); + } + + if (mask & PANGO_FONT_MASK_SIZE) + { + double size = (double) pango_font_description_get_size (font_desc) / PANGO_SCALE; + char size_buf[G_ASCII_DTOSTR_BUF_SIZE]; + const char *unit = "pt"; + + if (pango_font_description_get_size_is_absolute (font_desc)) + unit = "px"; + + g_ascii_formatd (size_buf, sizeof (size_buf), "%.2f", size); + g_string_append_printf (css, " font-size: %s%s;", size_buf, unit); + } +} + +void +gtkutil_apply_palette (GtkWidget *widget, const GdkRGBA *bg, const GdkRGBA *fg, + const PangoFontDescription *font_desc) +#else +void +gtkutil_apply_palette (GtkWidget *widget, const GdkColor *bg, const GdkColor *fg, + const PangoFontDescription *font_desc) +#endif +{ + if (!widget) + return; + +#if HAVE_GTK3 + { + static const char *class_name = "zoitechat-palette"; + GtkStyleContext *context = gtk_widget_get_style_context (widget); + GtkCssProvider *provider = g_object_get_data (G_OBJECT (widget), + "zoitechat-palette-provider"); + gboolean new_provider = FALSE; + GString *css; + gchar *bg_color = NULL; + gchar *fg_color = NULL; + + if (!bg && !fg && !font_desc) + { + gtk_style_context_remove_class (context, class_name); + if (provider) + { + gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider)); + g_object_set_data (G_OBJECT (widget), "zoitechat-palette-provider", NULL); + } + return; + } + + if (!provider) + { + provider = gtk_css_provider_new (); + g_object_set_data_full (G_OBJECT (widget), "zoitechat-palette-provider", + provider, g_object_unref); + new_provider = TRUE; + } + + css = g_string_new ("."); + g_string_append (css, class_name); + g_string_append (css, " {"); + if (bg) + { + bg_color = gdk_rgba_to_string (bg); + g_string_append_printf (css, " background-color: %s;", bg_color); + } + if (fg) + { + fg_color = gdk_rgba_to_string (fg); + g_string_append_printf (css, " color: %s;", fg_color); + } + gtkutil_append_font_css (css, font_desc); + g_string_append (css, " }"); + + gtk_css_provider_load_from_data (provider, css->str, -1, NULL); + if (new_provider) + { + gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + } + gtk_style_context_add_class (context, class_name); + + g_string_free (css, TRUE); + g_free (bg_color); + g_free (fg_color); + } +#else + gtk_widget_modify_base (widget, GTK_STATE_NORMAL, bg); + gtk_widget_modify_text (widget, GTK_STATE_NORMAL, fg); + gtk_widget_modify_font (widget, (PangoFontDescription *) font_desc); +#endif +} + static void gtkutil_file_req_destroy (GtkWidget * wid, struct file_req *freq) { @@ -74,6 +362,12 @@ gtkutil_check_file (char *filename, struct file_req *freq) { int axs = FALSE; + if (filename == NULL || filename[0] == '\0') + { + fe_message (_("No file selected."), FE_MSG_ERROR); + return; + } + GFile *file = g_file_new_for_path (filename); if (freq->flags & FRF_WRITE) @@ -137,10 +431,9 @@ gtkutil_check_file (char *filename, struct file_req *freq) } static void -gtkutil_file_req_done (GtkWidget * wid, struct file_req *freq) +gtkutil_file_req_done_chooser (GtkFileChooser *fs, struct file_req *freq) { GSList *files, *cur; - GtkFileChooser *fs = GTK_FILE_CHOOSER (freq->dialog); if (freq->flags & FRF_MULTIPLE) { @@ -165,11 +458,21 @@ gtkutil_file_req_done (GtkWidget * wid, struct file_req *freq) else { gchar *filename = gtk_file_chooser_get_filename (fs); - gtkutil_check_file (gtk_file_chooser_get_filename (fs), freq); - g_free (filename); + if (filename != NULL) + { + gtkutil_check_file (filename, freq); + g_free (filename); + } } } +} + +static void +gtkutil_file_req_done (GtkWidget * wid, struct file_req *freq) +{ + gtkutil_file_req_done_chooser (GTK_FILE_CHOOSER (freq->dialog), freq); + /* this should call the "destroy" cb, where we free(freq) */ gtk_widget_destroy (freq->dialog); } @@ -177,18 +480,42 @@ gtkutil_file_req_done (GtkWidget * wid, struct file_req *freq) static void gtkutil_file_req_response (GtkWidget *dialog, gint res, struct file_req *freq) { - switch (res) + if (res == GTK_RESPONSE_ACCEPT) { - case GTK_RESPONSE_ACCEPT: gtkutil_file_req_done (dialog, freq); - break; - - case GTK_RESPONSE_CANCEL: - /* this should call the "destroy" cb, where we free(freq) */ - gtk_widget_destroy (freq->dialog); + return; } + + /* this should call the "destroy" cb, where we free(freq) */ + gtk_widget_destroy (dialog); } +#if defined (WIN32) && HAVE_GTK3 +static gboolean +gtkutil_native_dialog_unref_idle (gpointer native) +{ + g_object_unref (native); + return G_SOURCE_REMOVE; +} + +static void +gtkutil_native_file_req_response (GtkNativeDialog *dialog, gint res, struct file_req *freq) +{ + if (res == GTK_RESPONSE_ACCEPT) + 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); + 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); +} +#endif + void gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *userdata, char *filter, char *extensions, int flags) @@ -196,27 +523,124 @@ gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *us struct file_req *freq; GtkWidget *dialog; GtkFileFilter *filefilter; - extern char *get_xdir_fs (void); char *token; char *tokenbuffer; + const char *xdir; + GtkWindow *effective_parent = parent; + + extern GtkWidget *parent_window; + if (effective_parent == NULL && parent_window != NULL) + effective_parent = GTK_WINDOW (parent_window); + + xdir = get_xdir (); + +#if defined (WIN32) && HAVE_GTK3 + { + GtkFileChooserNative *native = gtk_file_chooser_native_new ( + title, + effective_parent, + (flags & FRF_CHOOSEFOLDER) ? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER : + ((flags & FRF_WRITE) ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_OPEN), + (flags & FRF_WRITE) ? _("_Save") : _("_Open"), + _("_Cancel")); + GtkFileChooser *native_chooser = GTK_FILE_CHOOSER (native); + + if (flags & FRF_MULTIPLE) + gtk_file_chooser_set_select_multiple (native_chooser, TRUE); + if (flags & FRF_WRITE && !(flags & FRF_NOASKOVERWRITE)) + gtk_file_chooser_set_do_overwrite_confirmation (native_chooser, TRUE); + + if ((flags & FRF_EXTENSIONS || flags & FRF_MIMETYPES) && extensions != NULL) + { + GtkFileFilter *native_filter = gtk_file_filter_new (); + char *native_tokenbuffer = g_strdup (extensions); + char *native_token = strtok (native_tokenbuffer, ";"); + + while (native_token != NULL) + { + if (flags & FRF_EXTENSIONS) + gtk_file_filter_add_pattern (native_filter, native_token); + else + gtk_file_filter_add_mime_type (native_filter, native_token); + native_token = strtok (NULL, ";"); + } + + g_free (native_tokenbuffer); + gtk_file_chooser_set_filter (native_chooser, native_filter); + } + + 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 (native_chooser, temp); + else if (xdir && xdir[0] && g_file_test (xdir, G_FILE_TEST_IS_DIR)) + gtk_file_chooser_set_current_folder (native_chooser, xdir); + gtk_file_chooser_set_current_name (native_chooser, file_part (filter)); + } + else + { + if (g_file_test (filter, G_FILE_TEST_IS_DIR)) + gtk_file_chooser_set_current_folder (native_chooser, filter); + else if (xdir && xdir[0] && g_file_test (xdir, G_FILE_TEST_IS_DIR)) + gtk_file_chooser_set_current_folder (native_chooser, 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 (native_chooser, xdir); + } + + freq = g_new (struct file_req, 1); + freq->dialog = NULL; + freq->flags = flags; + freq->callback = callback; + freq->userdata = userdata; + + g_signal_connect (native, "response", + G_CALLBACK (gtkutil_native_file_req_response), freq); + gtk_native_dialog_show (GTK_NATIVE_DIALOG (native)); + return; + } +#endif if (flags & FRF_WRITE) { +#if HAVE_GTK3 + dialog = gtk_file_chooser_dialog_new (title, NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Save"), GTK_RESPONSE_ACCEPT, + NULL); +#elif !HAVE_GTK3 dialog = gtk_file_chooser_dialog_new (title, NULL, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); +#endif if (!(flags & FRF_NOASKOVERWRITE)) gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); } else +#if HAVE_GTK3 + dialog = gtk_file_chooser_dialog_new (title, NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Open"), GTK_RESPONSE_ACCEPT, + NULL); +#elif !HAVE_GTK3 dialog = gtk_file_chooser_dialog_new (title, NULL, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); +#endif if (filter && filter[0] && (flags & FRF_FILTERISINITIAL)) { @@ -224,14 +648,25 @@ gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *us { char temp[1024]; path_part (filter, temp, sizeof (temp)); - gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), 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 - gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), filter); + { + 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)) - gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), get_xdir ()); + { + 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); @@ -257,8 +692,14 @@ gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *us gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filefilter); } - gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog), get_xdir (), NULL); + 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; @@ -270,12 +711,12 @@ gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *us g_signal_connect (G_OBJECT (dialog), "destroy", G_CALLBACK (gtkutil_file_req_destroy), (gpointer) freq); - if (parent) - gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); + if (effective_parent) + gtk_window_set_transient_for (GTK_WINDOW (dialog), effective_parent); if (flags & FRF_MODAL) { - g_assert (parent); + g_assert (effective_parent); gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); } @@ -355,10 +796,17 @@ fe_get_str (char *msg, char *def, void *callback, void *userdata) GtkWidget *label; extern GtkWidget *parent_window; +#if HAVE_GTK3 + dialog = gtk_dialog_new_with_buttons (msg, NULL, 0, + _("_Cancel"), GTK_RESPONSE_REJECT, + _("_OK"), GTK_RESPONSE_ACCEPT, + NULL); +#elif !HAVE_GTK3 dialog = gtk_dialog_new_with_buttons (msg, NULL, 0, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); +#endif gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent_window)); gtk_box_set_homogeneous (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), TRUE); @@ -372,7 +820,7 @@ fe_get_str (char *msg, char *def, void *callback, void *userdata) gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); } - hbox = gtk_hbox_new (TRUE, 0); + hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, TRUE, 0); g_object_set_data (G_OBJECT (dialog), "cb", callback); g_object_set_data (G_OBJECT (dialog), "ud", userdata); @@ -450,15 +898,22 @@ fe_get_int (char *msg, int def, void *callback, void *userdata) GtkAdjustment *adj; extern GtkWidget *parent_window; +#if HAVE_GTK3 + dialog = gtk_dialog_new_with_buttons (msg, NULL, 0, + _("_Cancel"), GTK_RESPONSE_REJECT, + _("_OK"), GTK_RESPONSE_ACCEPT, + NULL); +#elif !HAVE_GTK3 dialog = gtk_dialog_new_with_buttons (msg, NULL, 0, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); +#endif gtk_box_set_homogeneous (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), TRUE); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent_window)); - hbox = gtk_hbox_new (TRUE, 0); + hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, TRUE, 0); g_object_set_data (G_OBJECT (dialog), "cb", callback); g_object_set_data (G_OBJECT (dialog), "ud", userdata); @@ -490,10 +945,17 @@ fe_get_bool (char *title, char *prompt, void *callback, void *userdata) GtkWidget *prompt_label; extern GtkWidget *parent_window; +#if HAVE_GTK3 + dialog = gtk_dialog_new_with_buttons (title, NULL, 0, + _("_No"), GTK_RESPONSE_REJECT, + _("_Yes"), GTK_RESPONSE_ACCEPT, + NULL); +#elif !HAVE_GTK3 dialog = gtk_dialog_new_with_buttons (title, NULL, 0, GTK_STOCK_NO, GTK_RESPONSE_REJECT, GTK_STOCK_YES, GTK_RESPONSE_ACCEPT, NULL); +#endif gtk_box_set_homogeneous (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), TRUE); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent_window)); @@ -523,20 +985,49 @@ gtkutil_button (GtkWidget *box, char *stock, char *tip, void *callback, if (labeltext) { gtk_button_set_label (GTK_BUTTON (wid), labeltext); - gtk_button_set_image (GTK_BUTTON (wid), gtk_image_new_from_stock (stock, GTK_ICON_SIZE_MENU)); + img = NULL; +#if HAVE_GTK3 + if (stock) + img = gtkutil_image_new_from_stock (stock, GTK_ICON_SIZE_BUTTON); +#endif +#if !HAVE_GTK3 + if (stock) + img = gtk_image_new_from_stock (stock, GTK_ICON_SIZE_BUTTON); +#endif + if (img) + { + gtk_button_set_image (GTK_BUTTON (wid), img); +#if HAVE_GTK3 + gtk_button_set_always_show_image (GTK_BUTTON (wid), TRUE); +#endif + } gtk_button_set_use_underline (GTK_BUTTON (wid), TRUE); if (box) gtk_container_add (GTK_CONTAINER (box), wid); } else { - bbox = gtk_hbox_new (0, 0); + bbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_container_add (GTK_CONTAINER (wid), bbox); gtk_widget_show (bbox); - img = gtk_image_new_from_stock (stock, GTK_ICON_SIZE_MENU); - gtk_container_add (GTK_CONTAINER (bbox), img); - gtk_widget_show (img); + img = NULL; +#if HAVE_GTK3 + if (stock) + img = gtkutil_image_new_from_stock (stock, GTK_ICON_SIZE_BUTTON); +#endif +#if !HAVE_GTK3 + if (stock) + img = gtk_image_new_from_stock (stock, GTK_ICON_SIZE_BUTTON); +#endif + if (img) + { + gtk_container_add (GTK_CONTAINER (bbox), img); + gtk_widget_show (img); +#if HAVE_GTK3 + gtk_button_set_always_show_image (GTK_BUTTON (wid), TRUE); +#endif + } gtk_box_pack_start (GTK_BOX (box), wid, 0, 0, 0); } @@ -660,8 +1151,15 @@ gtkutil_treeview_new (GtkWidget *box, GtkTreeModel *model, win = gtk_scrolled_window_new (0, 0); gtk_container_add (GTK_CONTAINER (box), win); + if (GTK_IS_BOX (box)) + { + gtk_box_set_child_packing (GTK_BOX (box), win, TRUE, TRUE, 0, + GTK_PACK_START); + } gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (win), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_set_vexpand (win, TRUE); + gtk_widget_set_hexpand (win, TRUE); gtk_widget_show (win); view = gtk_tree_view_new_with_model (model); @@ -752,11 +1250,13 @@ gtkutil_treeview_get_selected (GtkTreeView *view, GtkTreeIter *iter_ret, ...) gboolean gtkutil_tray_icon_supported (GtkWindow *window) { -#ifndef GDK_WINDOWING_X11 - return TRUE; -#else +#ifdef GDK_WINDOWING_X11 GdkScreen *screen = gtk_window_get_screen (window); GdkDisplay *display = gdk_screen_get_display (screen); +#if HAVE_GTK3 + if (!GDK_IS_X11_DISPLAY (display)) + return FALSE; +#endif int screen_number = gdk_screen_get_number (screen); Display *xdisplay = gdk_x11_display_get_xdisplay (display); char *selection_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d", screen_number); @@ -772,6 +1272,8 @@ gtkutil_tray_icon_supported (GtkWindow *window) g_free (selection_name); return (tray_window != None); +#else + return TRUE; #endif } @@ -805,3 +1307,95 @@ gtkutil_find_font (const char *fontname) return FALSE; } #endif + +GtkWidget * +gtkutil_box_new (GtkOrientation orientation, gboolean homogeneous, gint spacing) +{ +#if HAVE_GTK3 + GtkWidget *box = gtk_box_new (orientation, spacing); + + gtk_box_set_homogeneous (GTK_BOX (box), homogeneous); + return box; +#elif !HAVE_GTK3 + if (orientation == GTK_ORIENTATION_HORIZONTAL) + return gtk_hbox_new (homogeneous, spacing); + + return gtk_vbox_new (homogeneous, spacing); +#endif +} + +GtkWidget * +gtkutil_grid_new (guint rows, guint columns, gboolean homogeneous) +{ +#if HAVE_GTK3 + GtkWidget *grid = gtk_grid_new (); + + gtk_grid_set_row_homogeneous (GTK_GRID (grid), homogeneous); + gtk_grid_set_column_homogeneous (GTK_GRID (grid), homogeneous); + return grid; +#elif !HAVE_GTK3 + return gtk_table_new (rows, columns, homogeneous); +#endif +} + +#if HAVE_GTK3 +static GtkAlign +gtkutil_align_from_options (GtkutilAttachOptions options, GtkAlign default_align) +{ + if (options & GTKUTIL_ATTACH_FILL) + return GTK_ALIGN_FILL; + + return default_align; +} +#endif + +static gboolean +gtkutil_expansion_from_options (GtkutilAttachOptions options, gboolean default_expand) +{ + if (options & GTKUTIL_ATTACH_EXPAND) + return TRUE; + + return default_expand; +} + +void +gtkutil_grid_attach (GtkWidget *table, GtkWidget *child, + guint left_attach, guint right_attach, + guint top_attach, guint bottom_attach, + GtkutilAttachOptions xoptions, GtkutilAttachOptions yoptions, + guint xpad, guint ypad) +{ +#if HAVE_GTK3 + gtk_widget_set_hexpand (child, gtkutil_expansion_from_options (xoptions, FALSE)); + gtk_widget_set_vexpand (child, gtkutil_expansion_from_options (yoptions, FALSE)); + gtk_widget_set_halign (child, gtkutil_align_from_options (xoptions, GTK_ALIGN_CENTER)); + gtk_widget_set_valign (child, gtkutil_align_from_options (yoptions, GTK_ALIGN_CENTER)); + gtk_widget_set_margin_start (child, xpad); + gtk_widget_set_margin_end (child, xpad); + gtk_widget_set_margin_top (child, ypad); + gtk_widget_set_margin_bottom (child, ypad); + gtk_grid_attach (GTK_GRID (table), child, left_attach, top_attach, + right_attach - left_attach, bottom_attach - top_attach); +#elif !HAVE_GTK3 + gtk_table_attach (GTK_TABLE (table), child, left_attach, right_attach, + top_attach, bottom_attach, xoptions, yoptions, xpad, ypad); +#endif +} + +void +gtkutil_grid_attach_defaults (GtkWidget *table, GtkWidget *child, + guint left_attach, guint right_attach, + guint top_attach, guint bottom_attach) +{ +#if HAVE_GTK3 + gtk_widget_set_hexpand (child, TRUE); + gtk_widget_set_vexpand (child, TRUE); + gtk_widget_set_halign (child, GTK_ALIGN_FILL); + gtk_widget_set_valign (child, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (table), child, left_attach, top_attach, + right_attach - left_attach, bottom_attach - top_attach); +#elif !HAVE_GTK3 + gtk_table_attach_defaults (GTK_TABLE (table), child, left_attach, right_attach, + top_attach, bottom_attach); +#endif +} diff --git a/src/fe-gtk/gtkutil.h b/src/fe-gtk/gtkutil.h index b8f442cb..e89ba3b1 100644 --- a/src/fe-gtk/gtkutil.h +++ b/src/fe-gtk/gtkutil.h @@ -22,14 +22,42 @@ #include #include "../common/fe.h" +#include "palette.h" typedef void (*filereqcallback) (void *, char *file); +#ifndef HAVE_GTK3 +#if GTK_MAJOR_VERSION >= 3 +#define HAVE_GTK3 1 +#else +#define HAVE_GTK3 0 +#endif +#endif + +#if HAVE_GTK3 +typedef enum +{ + GTKUTIL_ATTACH_EXPAND = 1 << 0, + GTKUTIL_ATTACH_SHRINK = 1 << 1, + GTKUTIL_ATTACH_FILL = 1 << 2 +} GtkutilAttachOptions; +#else +typedef GtkAttachOptions GtkutilAttachOptions; +#define GTKUTIL_ATTACH_EXPAND GTK_EXPAND +#define GTKUTIL_ATTACH_SHRINK GTK_SHRINK +#define GTKUTIL_ATTACH_FILL GTK_FILL +#endif + void gtkutil_file_req (GtkWindow *parent, const char *title, void *callback, void *userdata, char *filter, char *extensions, int flags); void gtkutil_destroy (GtkWidget * igad, GtkWidget * dgad); void gtkutil_destroy_on_esc (GtkWidget *win); GtkWidget *gtkutil_button (GtkWidget *box, char *stock, char *tip, void *callback, void *userdata, char *labeltext); +GtkWidget *gtkutil_image_new_from_stock (const char *stock, GtkIconSize size); +GtkWidget *gtkutil_button_new_from_stock (const char *stock, const char *label); +#if HAVE_GTK3 +const char *gtkutil_icon_name_from_stock (const char *stock_name); +#endif void gtkutil_label_new (char *text, GtkWidget * box); GtkWidget *gtkutil_entry_new (int max, GtkWidget * box, void *callback, gpointer userdata); @@ -44,6 +72,24 @@ gboolean gtkutil_treemodel_string_to_iter (GtkTreeModel *model, gchar *pathstr, gboolean gtkutil_treeview_get_selected_iter (GtkTreeView *view, GtkTreeIter *iter_ret); gboolean gtkutil_treeview_get_selected (GtkTreeView *view, GtkTreeIter *iter_ret, ...); gboolean gtkutil_tray_icon_supported (GtkWindow *window); +GtkWidget *gtkutil_box_new (GtkOrientation orientation, gboolean homogeneous, gint spacing); +GtkWidget *gtkutil_grid_new (guint rows, guint columns, gboolean homogeneous); +void gtkutil_grid_attach (GtkWidget *table, GtkWidget *child, + guint left_attach, guint right_attach, + guint top_attach, guint bottom_attach, + GtkutilAttachOptions xoptions, GtkutilAttachOptions yoptions, + guint xpad, guint ypad); +void gtkutil_grid_attach_defaults (GtkWidget *table, GtkWidget *child, + guint left_attach, guint right_attach, + guint top_attach, guint bottom_attach); +#if HAVE_GTK3 +void gtkutil_apply_palette (GtkWidget *widget, const GdkRGBA *bg, const GdkRGBA *fg, + const PangoFontDescription *font_desc); +void gtkutil_append_font_css (GString *css, const PangoFontDescription *font_desc); +#else +void gtkutil_apply_palette (GtkWidget *widget, const GdkColor *bg, const GdkColor *fg, + const PangoFontDescription *font_desc); +#endif #if defined (WIN32) || defined (__APPLE__) gboolean gtkutil_find_font (const char *fontname); diff --git a/src/fe-gtk/ignoregui.c b/src/fe-gtk/ignoregui.c index 074ce58f..e5429f7a 100644 --- a/src/fe-gtk/ignoregui.c +++ b/src/fe-gtk/ignoregui.c @@ -31,6 +31,17 @@ #include "gtkutil.h" #include "maingui.h" +#if HAVE_GTK3 +#define ICON_IGNORE_NEW "document-new" +#define ICON_IGNORE_DELETE "edit-delete" +#define ICON_IGNORE_CLEAR "edit-clear" +#endif +#if !HAVE_GTK3 +#define ICON_IGNORE_NEW GTK_STOCK_NEW +#define ICON_IGNORE_DELETE GTK_STOCK_DELETE +#define ICON_IGNORE_CLEAR GTK_STOCK_CLEAR +#endif + enum { MASK_COLUMN, @@ -360,7 +371,11 @@ ignore_gui_open () frame = gtk_frame_new (_("Ignore Stats:")); gtk_widget_show (frame); +#if HAVE_GTK3 + stat_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2); +#elif !HAVE_GTK3 stat_box = gtk_hbox_new (0, 2); +#endif gtk_container_set_border_width (GTK_CONTAINER (stat_box), 6); gtk_container_add (GTK_CONTAINER (frame), stat_box); gtk_widget_show (stat_box); @@ -373,17 +388,22 @@ ignore_gui_open () gtk_box_pack_start (GTK_BOX (vbox), frame, 0, 0, 5); +#if HAVE_GTK3 + box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (box), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 box = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (box), GTK_BUTTONBOX_SPREAD); +#endif gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (box), 5); gtk_widget_show (box); - gtkutil_button (box, GTK_STOCK_NEW, 0, ignore_new_entry_clicked, 0, + gtkutil_button (box, ICON_IGNORE_NEW, 0, ignore_new_entry_clicked, 0, _("Add...")); - gtkutil_button (box, GTK_STOCK_DELETE, 0, ignore_delete_entry_clicked, + gtkutil_button (box, ICON_IGNORE_DELETE, 0, ignore_delete_entry_clicked, 0, _("Delete")); - gtkutil_button (box, GTK_STOCK_CLEAR, 0, ignore_clear_entry_clicked, + gtkutil_button (box, ICON_IGNORE_CLEAR, 0, ignore_clear_entry_clicked, 0, _("Clear")); store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view))); diff --git a/src/fe-gtk/joind.c b/src/fe-gtk/joind.c index 9dc14e2b..7106ff3c 100644 --- a/src/fe-gtk/joind.c +++ b/src/fe-gtk/joind.c @@ -38,6 +38,14 @@ #include "../common/fe.h" #include "fe-gtk.h" #include "chanlist.h" +#include "gtkutil.h" + +#if HAVE_GTK3 +#define ICON_JOIND_NETWORK "network-workgroup" +#endif +#if !HAVE_GTK3 +#define ICON_JOIND_NETWORK GTK_STOCK_NETWORK +#endif static void @@ -124,7 +132,6 @@ joind_show_dialog (server *serv) GtkWidget *hbox2; GtkWidget *entry1; GtkWidget *checkbutton1; - GtkWidget *dialog_action_area1; GtkWidget *okbutton1; char buf[256]; char buf2[256]; @@ -141,20 +148,26 @@ joind_show_dialog (server *serv) dialog_vbox1 = gtk_dialog_get_content_area (GTK_DIALOG (dialog1)); gtk_widget_show (dialog_vbox1); - vbox1 = gtk_vbox_new (FALSE, 0); + vbox1 = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); gtk_widget_show (vbox1); gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox1, TRUE, TRUE, 0); - hbox1 = gtk_hbox_new (FALSE, 0); + hbox1 = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_widget_show (hbox1); gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0); - image1 = gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_LARGE_TOOLBAR); + image1 = gtkutil_image_new_from_stock (ICON_JOIND_NETWORK, GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_widget_show (image1); gtk_box_pack_start (GTK_BOX (hbox1), image1, FALSE, TRUE, 24); +#if HAVE_GTK3 + gtk_widget_set_halign (image1, GTK_ALIGN_CENTER); + gtk_widget_set_valign (image1, GTK_ALIGN_START); + gtk_widget_set_margin_top (image1, 2); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (image1), 0.5f, 0.06f); +#endif - vbox2 = gtk_vbox_new (FALSE, 10); + vbox2 = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 10); gtk_container_set_border_width (GTK_CONTAINER (vbox2), 6); gtk_widget_show (vbox2); gtk_box_pack_start (GTK_BOX (hbox1), vbox2, TRUE, TRUE, 0); @@ -166,25 +179,40 @@ joind_show_dialog (server *serv) gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label), TRUE); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); +#endif label = gtk_label_new (_("In the server list window, no channel (chat room) has been entered to be automatically joined for this network.")); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); +#endif label = gtk_label_new (_("What would you like to do next?")); gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); +#endif serv->gui->joind_radio1 = radiobutton1 = gtk_radio_button_new_with_mnemonic (NULL, _("_Nothing, I'll join a channel later.")); gtk_widget_show (radiobutton1); gtk_box_pack_start (GTK_BOX (vbox2), radiobutton1, FALSE, FALSE, 0); radiobutton1_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton1)); - hbox2 = gtk_hbox_new (FALSE, 0); + hbox2 = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_widget_show (hbox2); gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 0); @@ -205,7 +233,12 @@ joind_show_dialog (server *serv) gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label), TRUE); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); +#endif radiobutton3 = gtk_radio_button_new_with_mnemonic (NULL, _("O_pen the channel list.")); gtk_widget_show (radiobutton3); @@ -218,7 +251,12 @@ joind_show_dialog (server *serv) gtk_widget_show (label); gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); gtk_label_set_use_markup (GTK_LABEL (label), TRUE); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); +#endif serv->gui->joind_check = checkbutton1 = gtk_check_button_new_with_mnemonic (_("_Always show this dialog after connecting.")); if (prefs.hex_gui_join_dialog) @@ -226,13 +264,20 @@ joind_show_dialog (server *serv) gtk_widget_show (checkbutton1); gtk_box_pack_start (GTK_BOX (vbox1), checkbutton1, FALSE, FALSE, 0); - dialog_action_area1 = gtk_dialog_get_action_area (GTK_DIALOG (dialog1)); - gtk_widget_show (dialog_action_area1); - gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); - - okbutton1 = gtk_button_new_from_stock ("gtk-ok"); + okbutton1 = gtkutil_button_new_from_stock ("gtk-ok", _("_OK")); gtk_widget_show (okbutton1); - gtk_box_pack_end (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dialog1))), okbutton1, FALSE, TRUE, 0); +#if HAVE_GTK3 + gtk_dialog_add_action_widget (GTK_DIALOG (dialog1), okbutton1, GTK_RESPONSE_OK); +#elif !HAVE_GTK3 + { + GtkWidget *dialog_action_area1; + + dialog_action_area1 = gtk_dialog_get_action_area (GTK_DIALOG (dialog1)); + gtk_widget_show (dialog_action_area1); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END); + gtk_box_pack_end (GTK_BOX (dialog_action_area1), okbutton1, FALSE, TRUE, 0); + } +#endif gtk_widget_set_can_default (okbutton1, TRUE); g_signal_connect (G_OBJECT (dialog1), "destroy", diff --git a/src/fe-gtk/maingui.c b/src/fe-gtk/maingui.c index 310623ad..5a59b876 100644 --- a/src/fe-gtk/maingui.c +++ b/src/fe-gtk/maingui.c @@ -60,6 +60,21 @@ #include #endif +#if HAVE_GTK3 +#define ICON_TAB_DETACH "edit-redo" +#define ICON_TAB_CLOSE "window-close" +#define ICON_TAB_PREVIOUS "go-previous" +#define ICON_TAB_NEXT "go-next" +#define ICON_ENTRY_ERROR "dialog-error" +#endif +#if !HAVE_GTK3 +#define ICON_TAB_DETACH GTK_STOCK_REDO +#define ICON_TAB_CLOSE GTK_STOCK_CLOSE +#define ICON_TAB_PREVIOUS GTK_STOCK_GO_BACK +#define ICON_TAB_NEXT GTK_STOCK_GO_FORWARD +#define ICON_ENTRY_ERROR GTK_STOCK_DIALOG_ERROR +#endif + #define GUI_SPACING (3) #define GUI_BORDER (0) @@ -102,6 +117,70 @@ mg_color_component_to_pango (double value) return (guint16)(value * 65535.0 + 0.5); } +#if HAVE_GTK3 +static void +mg_apply_font_css (GtkWidget *widget, const PangoFontDescription *desc, + const char *class_name, const char *provider_key) +{ + GtkStyleContext *context; + GtkCssProvider *provider; + GString *css; + + if (!widget || !desc) + return; + + context = gtk_widget_get_style_context (widget); + if (!context) + return; + + provider = g_object_get_data (G_OBJECT (widget), provider_key); + if (!provider) + { + provider = gtk_css_provider_new (); + g_object_set_data_full (G_OBJECT (widget), provider_key, provider, g_object_unref); + } + + css = g_string_new ("."); + g_string_append (css, class_name); + g_string_append (css, " {"); + gtkutil_append_font_css (css, desc); + g_string_append (css, " }"); + gtk_css_provider_load_from_data (provider, css->str, -1, NULL); + g_string_free (css, TRUE); + + gtk_style_context_add_class (context, class_name); + gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); +} +#endif + +static void +mg_set_label_alignment_start (GtkWidget *widget) +{ +#if HAVE_GTK3 + gtk_widget_set_halign (widget, GTK_ALIGN_START); + gtk_widget_set_valign (widget, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 + gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5); +#endif +} + +static GtkWidget * +mg_box_new (GtkOrientation orientation, gboolean homogeneous, gint spacing) +{ +#if HAVE_GTK3 + GtkWidget *box = gtk_box_new (orientation, spacing); + + gtk_box_set_homogeneous (GTK_BOX (box), homogeneous); + return box; +#elif !HAVE_GTK3 + if (orientation == GTK_ORIENTATION_HORIZONTAL) + return gtk_hbox_new (homogeneous, spacing); + + return gtk_vbox_new (homogeneous, spacing); +#endif +} + static void mg_pixbuf_destroy (guchar *pixels, gpointer data) { @@ -230,7 +309,7 @@ static const char chan_flags[] = { 'c', 'n', 't', 'i', 'm', 'l', 'k' }; static chan *active_tab = NULL; /* active tab */ GtkWidget *parent_window = NULL; /* the master window */ -GtkStyle *input_style; +InputStyle *input_style; static PangoAttrList *away_list; static PangoAttrList *newdata_list; @@ -707,13 +786,21 @@ mg_progressbar_update (GtkWidget *bar) if (type == 0) { type = 1; +#if HAVE_GTK3 + gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR (bar), TRUE); +#else gtk_progress_bar_set_orientation ((GtkProgressBar *) bar, GTK_PROGRESS_RIGHT_TO_LEFT); +#endif } else { type = 0; +#if HAVE_GTK3 + gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR (bar), FALSE); +#else gtk_progress_bar_set_orientation ((GtkProgressBar *) bar, GTK_PROGRESS_LEFT_TO_RIGHT); +#endif } pos = 0.05; } @@ -1303,16 +1390,15 @@ void mg_open_quit_dialog (gboolean minimize_button) { static GtkWidget *dialog = NULL; - GtkWidget *dialog_vbox1; - GtkWidget *table1; - GtkWidget *image; - GtkWidget *checkbutton1; - GtkWidget *label; - GtkWidget *dialog_action_area1; - GtkWidget *button; - char *text, *connecttext; - int cons; - int dccs; + GtkWidget *dialog_vbox1; + GtkWidget *table1; + GtkWidget *image; + GtkWidget *checkbutton1; + GtkWidget *label; + GtkWidget *button; + char *text, *connecttext; + int cons; + int dccs; if (dialog) { @@ -1337,24 +1423,56 @@ mg_open_quit_dialog (gboolean minimize_button) dialog_vbox1 = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); gtk_widget_show (dialog_vbox1); +#if HAVE_GTK3 + table1 = gtk_grid_new (); + gtk_widget_show (table1); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), table1, TRUE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (table1), 6); + gtk_grid_set_row_spacing (GTK_GRID (table1), 12); + gtk_grid_set_column_spacing (GTK_GRID (table1), 12); +#else table1 = gtk_table_new (2, 2, FALSE); gtk_widget_show (table1); gtk_box_pack_start (GTK_BOX (dialog_vbox1), table1, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (table1), 6); gtk_table_set_row_spacings (GTK_TABLE (table1), 12); gtk_table_set_col_spacings (GTK_TABLE (table1), 12); +#endif +#if HAVE_GTK3 + image = gtk_image_new_from_icon_name ("dialog-warning", GTK_ICON_SIZE_DIALOG); +#endif +#if !HAVE_GTK3 image = gtk_image_new_from_stock ("gtk-dialog-warning", GTK_ICON_SIZE_DIALOG); +#endif gtk_widget_show (image); +#if HAVE_GTK3 + gtk_widget_set_hexpand (image, FALSE); + gtk_widget_set_vexpand (image, FALSE); + gtk_widget_set_halign (image, GTK_ALIGN_FILL); + gtk_widget_set_valign (image, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (table1), image, 0, 0, 1, 1); +#else gtk_table_attach (GTK_TABLE (table1), image, 0, 1, 0, 1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0); +#endif checkbutton1 = gtk_check_button_new_with_mnemonic (_("Don't ask next time.")); gtk_widget_show (checkbutton1); +#if HAVE_GTK3 + gtk_widget_set_hexpand (checkbutton1, TRUE); + gtk_widget_set_vexpand (checkbutton1, FALSE); + gtk_widget_set_halign (checkbutton1, GTK_ALIGN_FILL); + gtk_widget_set_valign (checkbutton1, GTK_ALIGN_CENTER); + gtk_widget_set_margin_top (checkbutton1, 4); + gtk_widget_set_margin_bottom (checkbutton1, 4); + gtk_grid_attach (GTK_GRID (table1), checkbutton1, 0, 1, 2, 1); +#else gtk_table_attach (GTK_TABLE (table1), checkbutton1, 0, 2, 1, 2, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 4); +#endif connecttext = g_strdup_printf (_("You are connected to %i IRC networks."), cons); text = g_strdup_printf ("%s\n\n%s\n%s", @@ -1365,31 +1483,60 @@ mg_open_quit_dialog (gboolean minimize_button) label = gtk_label_new (text); g_free (text); gtk_widget_show (label); + mg_set_label_alignment_start (label); +#if HAVE_GTK3 + gtk_widget_set_hexpand (label, TRUE); + gtk_widget_set_vexpand (label, TRUE); + gtk_widget_set_halign (label, GTK_ALIGN_FILL); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); + gtk_label_set_xalign (GTK_LABEL (label), 0.0f); + gtk_grid_attach (GTK_GRID (table1), label, 1, 0, 1, 1); +#else gtk_table_attach (GTK_TABLE (table1), label, 1, 2, 0, 1, (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL), (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK), 0, 0); +#endif gtk_label_set_use_markup (GTK_LABEL (label), TRUE); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - dialog_action_area1 = gtk_dialog_get_action_area (GTK_DIALOG (dialog)); - gtk_widget_show (dialog_action_area1); - gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), - GTK_BUTTONBOX_END); +#if !HAVE_GTK3 + { + GtkWidget *dialog_action_area1; - if (minimize_button && gtkutil_tray_icon_supported (GTK_WINDOW(dialog))) - { - button = gtk_button_new_with_mnemonic (_("_Minimize to Tray")); - gtk_widget_show (button); + dialog_action_area1 = gtk_dialog_get_action_area (GTK_DIALOG (dialog)); + gtk_widget_show (dialog_action_area1); + gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), + GTK_BUTTONBOX_END); + } +#endif + + if (minimize_button && gtkutil_tray_icon_supported (GTK_WINDOW(dialog))) + { + button = gtk_button_new_with_mnemonic (_("_Minimize to Tray")); + gtk_widget_show (button); gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, 1); } +#if HAVE_GTK3 + button = gtk_button_new_with_mnemonic (_("_Cancel")); + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_icon_name ("dialog-cancel", GTK_ICON_SIZE_BUTTON)); +#endif +#if !HAVE_GTK3 button = gtk_button_new_from_stock ("gtk-cancel"); +#endif gtk_widget_show (button); gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_CANCEL); gtk_widget_grab_focus (button); +#if HAVE_GTK3 + button = gtk_button_new_with_mnemonic (_("_Quit")); + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_icon_name ("application-exit", GTK_ICON_SIZE_BUTTON)); +#endif +#if !HAVE_GTK3 button = gtk_button_new_from_stock ("gtk-quit"); +#endif gtk_widget_show (button); gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, 0); @@ -1608,9 +1755,14 @@ mg_create_color_menu (GtkWidget *menu, session *sess) for (i = 0; i < 8; i++) { + guint16 red; + guint16 green; + guint16 blue; + + palette_color_get_rgb16 (&colors[i], &red, &green, &blue); sprintf (buf, "%02d " " ", - i, colors[i].red >> 8, colors[i].green >> 8, colors[i].blue >> 8); + i, red >> 8, green >> 8, blue >> 8); mg_markup_item (subsubmenu, buf, i); } @@ -1618,9 +1770,14 @@ mg_create_color_menu (GtkWidget *menu, session *sess) for (i = 8; i < 16; i++) { + guint16 red; + guint16 green; + guint16 blue; + + palette_color_get_rgb16 (&colors[i], &red, &green, &blue); sprintf (buf, "%02d " " ", - i, colors[i].red >> 8, colors[i].green >> 8, colors[i].blue >> 8); + i, red >> 8, green >> 8, blue >> 8); mg_markup_item (subsubmenu, buf, i); } } @@ -1740,9 +1897,9 @@ mg_create_tabmenu (session *sess, GdkEventButton *event, chan *ch) menu_addconnectmenu (sess->server, menu); } - mg_create_icon_item (_("_Detach"), GTK_STOCK_REDO, menu, + mg_create_icon_item (_("_Detach"), ICON_TAB_DETACH, menu, mg_detach_tab_cb, ch); - mg_create_icon_item (_("_Close"), GTK_STOCK_CLOSE, menu, + mg_create_icon_item (_("_Close"), ICON_TAB_CLOSE, menu, mg_destroy_tab_cb, ch); if (sess && tabmenu_list) menu_create (menu, tabmenu_list, sess->channel, FALSE); @@ -1756,7 +1913,11 @@ mg_create_tabmenu (session *sess, GdkEventButton *event, chan *ch) g_object_unref (menu); g_signal_connect (G_OBJECT (menu), "selection-done", G_CALLBACK (mg_menu_destroy), NULL); +#if HAVE_GTK3 + gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *)event); +#else gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, event->time); +#endif } static gboolean @@ -1873,7 +2034,15 @@ mg_userlist_button (GtkWidget * box, char *label, char *cmd, GtkWidget *wid = gtk_button_new_with_label (label); g_signal_connect (G_OBJECT (wid), "clicked", G_CALLBACK (userlist_button_cb), cmd); +#if HAVE_GTK3 + gtk_widget_set_hexpand (wid, TRUE); + gtk_widget_set_vexpand (wid, TRUE); + gtk_widget_set_halign (wid, GTK_ALIGN_FILL); + gtk_widget_set_valign (wid, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (box), wid, a, c, b - a, d - c); +#else gtk_table_attach_defaults (GTK_TABLE (box), wid, a, b, c, d); +#endif show_and_unfocus (wid); } @@ -1885,7 +2054,11 @@ mg_create_userlistbuttons (GtkWidget *box) int a = 0, b = 0; GtkWidget *tab; +#if HAVE_GTK3 + tab = gtk_grid_new (); +#else tab = gtk_table_new (5, 2, FALSE); +#endif gtk_box_pack_end (GTK_BOX (box), tab, FALSE, FALSE, 0); while (list) @@ -2209,9 +2382,8 @@ mg_limit_entry_cb (GtkWidget * igad, gpointer userdata) static void mg_apply_entry_style (GtkWidget *entry) { - gtk_widget_modify_base (entry, GTK_STATE_NORMAL, &colors[COL_BG]); - gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &colors[COL_FG]); - gtk_widget_modify_font (entry, input_style->font_desc); + gtkutil_apply_palette (entry, &colors[COL_BG], &colors[COL_FG], + input_style->font_desc); } static void @@ -2254,11 +2426,11 @@ mg_create_chanmodebuttons (session_gui *gui, GtkWidget *box) /*static void mg_create_link_buttons (GtkWidget *box, gpointer userdata) { - gtkutil_button (box, GTK_STOCK_CLOSE, _("Close this tab/window"), + gtkutil_button (box, ICON_TAB_CLOSE, _("Close this tab/window"), mg_x_click_cb, userdata, 0); if (!userdata) - gtkutil_button (box, GTK_STOCK_REDO, _("Attach/Detach this tab"), + gtkutil_button (box, ICON_TAB_DETACH, _("Attach/Detach this tab"), mg_link_cb, userdata, 0); }*/ @@ -2323,7 +2495,7 @@ mg_create_topicbar (session *sess, GtkWidget *box) GtkWidget *hbox, *topic, *bbox; session_gui *gui = sess->gui; - gui->topic_bar = hbox = gtk_hbox_new (FALSE, 0); + gui->topic_bar = hbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), hbox, 0, 0, 0); if (!gui->is_tab) @@ -2332,7 +2504,7 @@ mg_create_topicbar (session *sess, GtkWidget *box) gui->topic_entry = topic = sexy_spell_entry_new (); gtk_widget_set_name (topic, "zoitechat-inputbox"); sexy_spell_entry_set_checked (SEXY_SPELL_ENTRY (topic), FALSE); - gtk_container_add (GTK_CONTAINER (hbox), topic); + gtk_box_pack_start (GTK_BOX (hbox), topic, TRUE, TRUE, 0); mg_apply_emoji_fallback_widget (topic); g_signal_connect (G_OBJECT (topic), "activate", G_CALLBACK (mg_topic_cb), 0); @@ -2340,11 +2512,11 @@ mg_create_topicbar (session *sess, GtkWidget *box) if (prefs.hex_gui_input_style) mg_apply_entry_style (topic); - gui->topicbutton_box = bbox = gtk_hbox_new (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); mg_create_chanmodebuttons (gui, bbox); - gui->dialogbutton_box = bbox = gtk_hbox_new (FALSE, 0); + gui->dialogbutton_box = bbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), bbox, 0, 0, 0); mg_create_dialogbuttons (bbox); } @@ -2493,14 +2665,14 @@ mg_create_textarea (session *sess, GtkWidget *box) {"ZOITECHAT_USERLIST", GTK_TARGET_SAME_APP, 75 } }; - vbox = gtk_vbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (box), vbox); - inbox = gtk_hbox_new (FALSE, 2); - gtk_container_add (GTK_CONTAINER (vbox), inbox); + vbox = mg_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), vbox, TRUE, TRUE, 0); + inbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), inbox, TRUE, TRUE, 0); frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); - gtk_container_add (GTK_CONTAINER (inbox), frame); + gtk_box_pack_start (GTK_BOX (inbox), frame, TRUE, TRUE, 0); palette_get_xtext_colors (xtext_palette, XTEXT_COLS); gui->xtext = gtk_xtext_new (xtext_palette, TRUE); @@ -2516,7 +2688,12 @@ mg_create_textarea (session *sess, GtkWidget *box) g_signal_connect (G_OBJECT (xtext), "word_click", G_CALLBACK (mg_word_clicked), NULL); +#if HAVE_GTK3 + gui->vscrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, + GTK_XTEXT (xtext)->adj); +#elif !HAVE_GTK3 gui->vscrollbar = gtk_vscrollbar_new (GTK_XTEXT (xtext)->adj); +#endif gtk_box_pack_start (GTK_BOX (inbox), gui->vscrollbar, FALSE, TRUE, 0); gtk_drag_dest_set (gui->vscrollbar, 5, dnd_dest_targets, 2, @@ -2543,13 +2720,13 @@ mg_create_infoframe (GtkWidget *box) frame = gtk_frame_new (0); gtk_frame_set_shadow_type ((GtkFrame*)frame, GTK_SHADOW_OUT); - gtk_container_add (GTK_CONTAINER (box), frame); + gtk_box_pack_start (GTK_BOX (box), frame, FALSE, TRUE, 0); - hbox = gtk_hbox_new (0, 0); + hbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_container_add (GTK_CONTAINER (frame), hbox); label = gtk_label_new (NULL); - gtk_container_add (GTK_CONTAINER (hbox), label); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); return label; } @@ -2559,12 +2736,12 @@ mg_create_meters (session_gui *gui, GtkWidget *parent_box) { GtkWidget *infbox, *wid, *box; - gui->meter_box = infbox = box = gtk_vbox_new (0, 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); if ((prefs.hex_gui_lagometer & 2) || (prefs.hex_gui_throttlemeter & 2)) { - infbox = gtk_hbox_new (0, 0); + infbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), infbox, 0, 0, 0); } @@ -2625,8 +2802,8 @@ mg_create_userlist (session_gui *gui, GtkWidget *box) { GtkWidget *frame, *ulist, *vbox; - vbox = gtk_vbox_new (0, 1); - gtk_container_add (GTK_CONTAINER (box), vbox); + vbox = mg_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 1); + gtk_box_pack_start (GTK_BOX (box), vbox, TRUE, TRUE, 0); frame = gtk_frame_new (NULL); if (prefs.hex_gui_ulist_count) @@ -2637,11 +2814,6 @@ mg_create_userlist (session_gui *gui, GtkWidget *box) gui->user_tree = ulist = userlist_create (vbox); - if (prefs.hex_gui_ulist_style) - { - gtk_widget_modify_font (ulist, input_style->font_desc); - } - /* * Keep the user list in sync with the chat palette. * @@ -2652,8 +2824,8 @@ mg_create_userlist (session_gui *gui, GtkWidget *box) */ if (prefs.hex_gui_ulist_style || fe_dark_mode_is_enabled ()) { - gtk_widget_modify_base (ulist, GTK_STATE_NORMAL, &colors[COL_BG]); - gtk_widget_modify_text (ulist, GTK_STATE_NORMAL, &colors[COL_FG]); + gtkutil_apply_palette (ulist, &colors[COL_BG], &colors[COL_FG], + input_style ? input_style->font_desc : NULL); } mg_create_meters (gui, vbox); @@ -2706,44 +2878,61 @@ mg_create_center (session *sess, session_gui *gui, GtkWidget *box) GtkWidget *vbox, *hbox, *book; /* sep between top and bottom of left side */ +#if HAVE_GTK3 + gui->vpane_left = gtk_paned_new (GTK_ORIENTATION_VERTICAL); +#elif !HAVE_GTK3 gui->vpane_left = gtk_vpaned_new (); +#endif /* sep between top and bottom of right side */ +#if HAVE_GTK3 + gui->vpane_right = gtk_paned_new (GTK_ORIENTATION_VERTICAL); +#elif !HAVE_GTK3 gui->vpane_right = gtk_vpaned_new (); +#endif - /* sep between left and xtext */ - gui->hpane_left = gtk_hpaned_new (); - gtk_paned_set_position (GTK_PANED (gui->hpane_left), prefs.hex_gui_pane_left_size); + /* sep between left and xtext */ +#if HAVE_GTK3 + gui->hpane_left = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); + gtk_paned_set_wide_handle (GTK_PANED (gui->hpane_left), FALSE); +#elif !HAVE_GTK3 + gui->hpane_left = gtk_hpaned_new (); +#endif + gtk_paned_set_position (GTK_PANED (gui->hpane_left), prefs.hex_gui_pane_left_size); - /* sep between xtext and right side */ - gui->hpane_right = gtk_hpaned_new (); + /* sep between xtext and right side */ +#if HAVE_GTK3 + gui->hpane_right = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); +#elif !HAVE_GTK3 + gui->hpane_right = gtk_hpaned_new (); +#endif if (prefs.hex_gui_win_swap) { gtk_paned_pack2 (GTK_PANED (gui->hpane_left), gui->vpane_left, FALSE, TRUE); - 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 { gtk_paned_pack1 (GTK_PANED (gui->hpane_left), gui->vpane_left, FALSE, TRUE); - 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_container_add (GTK_CONTAINER (box), gui->hpane_left); + gtk_box_pack_start (GTK_BOX (box), gui->hpane_left, TRUE, TRUE, 0); gui->note_book = book = gtk_notebook_new (); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (book), FALSE); gtk_notebook_set_show_border (GTK_NOTEBOOK (book), FALSE); gtk_paned_pack1 (GTK_PANED (gui->hpane_right), book, TRUE, TRUE); - hbox = gtk_hbox_new (FALSE, 0); + hbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_paned_pack1 (GTK_PANED (gui->vpane_right), hbox, FALSE, TRUE); mg_create_userlist (gui, hbox); gui->user_box = hbox; - vbox = gtk_vbox_new (FALSE, 3); + vbox = mg_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 3); gtk_notebook_append_page (GTK_NOTEBOOK (book), vbox, NULL); mg_create_topicbar (sess, vbox); @@ -2833,8 +3022,13 @@ mg_place_userlist_and_chanview_real (session_gui *gui, GtkWidget *userlist, GtkW /* incase the previous pos was POS_HIDDEN */ gtk_widget_show (chanview); +#if HAVE_GTK3 + gtk_widget_set_margin_top (chanview, 0); + gtk_widget_set_margin_bottom (chanview, 0); +#else gtk_table_set_row_spacing (GTK_TABLE (gui->main_table), 1, 0); gtk_table_set_row_spacing (GTK_TABLE (gui->main_table), 2, 2); +#endif /* then place them back in their new positions */ switch (prefs.hex_gui_tab_pos) @@ -2852,25 +3046,67 @@ mg_place_userlist_and_chanview_real (session_gui *gui, GtkWidget *userlist, GtkW gtk_paned_pack2 (GTK_PANED (gui->vpane_right), chanview, FALSE, TRUE); break; case POS_TOP: +#if HAVE_GTK3 + gtk_widget_set_margin_bottom (chanview, GUI_SPACING - 1); + gtk_widget_set_hexpand (chanview, FALSE); + gtk_widget_set_vexpand (chanview, FALSE); + gtk_widget_set_halign (chanview, GTK_ALIGN_FILL); + gtk_widget_set_valign (chanview, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (gui->main_table), chanview, + 1, 1, 1, 1); +#else gtk_table_set_row_spacing (GTK_TABLE (gui->main_table), 1, GUI_SPACING-1); gtk_table_attach (GTK_TABLE (gui->main_table), chanview, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); +#endif break; case POS_HIDDEN: gtk_widget_hide (chanview); /* always attach it to something to avoid ref_count=0 */ if (prefs.hex_gui_ulist_pos == POS_TOP) +#if HAVE_GTK3 + { + gtk_widget_set_hexpand (chanview, FALSE); + gtk_widget_set_vexpand (chanview, FALSE); + gtk_widget_set_halign (chanview, GTK_ALIGN_FILL); + gtk_widget_set_valign (chanview, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (gui->main_table), chanview, + 1, 3, 1, 1); + } +#else gtk_table_attach (GTK_TABLE (gui->main_table), chanview, 1, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0); +#endif else +#if HAVE_GTK3 + { + gtk_widget_set_hexpand (chanview, FALSE); + gtk_widget_set_vexpand (chanview, FALSE); + gtk_widget_set_halign (chanview, GTK_ALIGN_FILL); + gtk_widget_set_valign (chanview, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (gui->main_table), chanview, + 1, 1, 1, 1); + } +#else gtk_table_attach (GTK_TABLE (gui->main_table), chanview, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); +#endif break; default:/* POS_BOTTOM */ +#if HAVE_GTK3 + gtk_widget_set_margin_top (chanview, 3); + gtk_widget_set_hexpand (chanview, FALSE); + gtk_widget_set_vexpand (chanview, FALSE); + gtk_widget_set_halign (chanview, GTK_ALIGN_FILL); + gtk_widget_set_valign (chanview, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (gui->main_table), chanview, + 1, 3, 1, 1); +#else gtk_table_set_row_spacing (GTK_TABLE (gui->main_table), 2, 3); gtk_table_attach (GTK_TABLE (gui->main_table), chanview, 1, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0); +#endif } } @@ -3018,42 +3254,86 @@ mg_fontdesc_with_fallback (const PangoFontDescription *base_desc, gboolean emoji static void mg_apply_emoji_fallback_widget (GtkWidget *widget) { - GtkStyle *style; PangoFontDescription *desc; +#if HAVE_GTK3 + GtkStyleContext *context; + const PangoFontDescription *base_desc; +#else + GtkStyle *style; +#endif if (!widget) return; +#if HAVE_GTK3 + context = gtk_widget_get_style_context (widget); + if (!context) + return; + + base_desc = gtk_style_context_get_font (context, GTK_STATE_FLAG_NORMAL); + if (!base_desc) + return; + + desc = mg_fontdesc_with_fallback (base_desc, FALSE); +#else style = gtk_widget_get_style (widget); if (!style || !style->font_desc) return; desc = mg_fontdesc_with_fallback (style->font_desc, FALSE); +#endif if (!desc) return; +#if HAVE_GTK3 + mg_apply_font_css (widget, desc, "zoitechat-emoji-font", + "zoitechat-emoji-font-provider"); +#else gtk_widget_modify_font (widget, desc); +#endif pango_font_description_free (desc); } static void mg_apply_emoji_primary_widget (GtkWidget *widget) { - GtkStyle *style; PangoFontDescription *desc; +#if HAVE_GTK3 + GtkStyleContext *context; + const PangoFontDescription *base_desc; +#else + GtkStyle *style; +#endif if (!widget) return; +#if HAVE_GTK3 + context = gtk_widget_get_style_context (widget); + if (!context) + return; + + base_desc = gtk_style_context_get_font (context, GTK_STATE_FLAG_NORMAL); + if (!base_desc) + return; + + desc = mg_fontdesc_with_fallback (base_desc, TRUE); +#else style = gtk_widget_get_style (widget); if (!style || !style->font_desc) return; desc = mg_fontdesc_with_fallback (style->font_desc, TRUE); +#endif if (!desc) return; +#if HAVE_GTK3 + mg_apply_font_css (widget, desc, "zoitechat-emoji-font", + "zoitechat-emoji-font-provider"); +#else gtk_widget_modify_font (widget, desc); +#endif pango_font_description_free (desc); } @@ -3146,7 +3426,14 @@ mg_emoji_button_cb (GtkWidget *widget, session_gui *gui) GtkWidget *menu; menu = mg_create_emoji_menu (gui); +#if HAVE_GTK3 + gtk_menu_popup_at_widget (GTK_MENU (menu), widget, + GDK_GRAVITY_SOUTH_WEST, + GDK_GRAVITY_NORTH_WEST, + NULL); +#else gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ()); +#endif } /* Search bar adapted from Conspire's by William Pitcock */ @@ -3181,7 +3468,12 @@ search_handle_event(int search_type, session *sess) if (err) { +#if HAVE_GTK3 + gtk_entry_set_icon_from_icon_name (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, ICON_ENTRY_ERROR); +#endif +#if !HAVE_GTK3 gtk_entry_set_icon_from_stock (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_DIALOG_ERROR); +#endif gtk_entry_set_icon_tooltip_text (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, _(err->message)); g_error_free (err); } @@ -3189,7 +3481,12 @@ search_handle_event(int search_type, session *sess) { if (text && text[0] == 0) /* empty string, no error */ { +#if HAVE_GTK3 + gtk_entry_set_icon_from_icon_name (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, NULL); +#endif +#if !HAVE_GTK3 gtk_entry_set_icon_from_stock (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, NULL); +#endif } else { @@ -3197,14 +3494,24 @@ search_handle_event(int search_type, session *sess) last = gtk_xtext_search (GTK_XTEXT (sess->gui->xtext), text, flags, &err); if (!last) /* Not found error */ { +#if HAVE_GTK3 + gtk_entry_set_icon_from_icon_name (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, ICON_ENTRY_ERROR); +#endif +#if !HAVE_GTK3 gtk_entry_set_icon_from_stock (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_DIALOG_ERROR); +#endif gtk_entry_set_icon_tooltip_text (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, _("No results found.")); } } } else { +#if HAVE_GTK3 + gtk_entry_set_icon_from_icon_name (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, NULL); +#endif +#if !HAVE_GTK3 gtk_entry_set_icon_from_stock (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, NULL); +#endif } } @@ -3251,7 +3558,12 @@ mg_search_toggle(session *sess) else { /* Reset search state */ +#if HAVE_GTK3 + gtk_entry_set_icon_from_icon_name (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, NULL); +#endif +#if !HAVE_GTK3 gtk_entry_set_icon_from_stock (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, NULL); +#endif /* Show and focus */ gtk_widget_show(sess->gui->shbox); @@ -3274,11 +3586,16 @@ mg_create_search(session *sess, GtkWidget *box) GtkWidget *entry, *label, *next, *previous, *highlight, *matchcase, *regex, *close; session_gui *gui = sess->gui; - gui->shbox = gtk_hbox_new(FALSE, 5); + gui->shbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 5); gtk_box_pack_start(GTK_BOX(box), gui->shbox, FALSE, FALSE, 0); close = gtk_button_new (); +#if HAVE_GTK3 + gtk_button_set_image (GTK_BUTTON (close), gtk_image_new_from_icon_name (ICON_TAB_CLOSE, GTK_ICON_SIZE_MENU)); +#endif +#if !HAVE_GTK3 gtk_button_set_image (GTK_BUTTON (close), gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU)); +#endif gtk_button_set_relief(GTK_BUTTON(close), GTK_RELIEF_NONE); gtk_widget_set_can_focus (close, FALSE); gtk_box_pack_start(GTK_BOX(gui->shbox), close, FALSE, FALSE, 0); @@ -3298,14 +3615,24 @@ mg_create_search(session *sess, GtkWidget *box) gtk_entry_set_icon_tooltip_text (GTK_ENTRY (sess->gui->shentry), GTK_ENTRY_ICON_SECONDARY, _("Search hit end or not found.")); previous = gtk_button_new (); +#if HAVE_GTK3 + gtk_button_set_image (GTK_BUTTON (previous), gtk_image_new_from_icon_name (ICON_TAB_PREVIOUS, GTK_ICON_SIZE_MENU)); +#endif +#if !HAVE_GTK3 gtk_button_set_image (GTK_BUTTON (previous), gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_MENU)); +#endif gtk_button_set_relief(GTK_BUTTON(previous), GTK_RELIEF_NONE); gtk_widget_set_can_focus (previous, FALSE); gtk_box_pack_start(GTK_BOX(gui->shbox), previous, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(previous), "clicked", G_CALLBACK(mg_search_handle_previous), sess); next = gtk_button_new (); +#if HAVE_GTK3 + gtk_button_set_image (GTK_BUTTON (next), gtk_image_new_from_icon_name (ICON_TAB_NEXT, GTK_ICON_SIZE_MENU)); +#endif +#if !HAVE_GTK3 gtk_button_set_image (GTK_BUTTON (next), gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU)); +#endif gtk_button_set_relief(GTK_BUTTON(next), GTK_RELIEF_NONE); gtk_widget_set_can_focus (next, FALSE); gtk_box_pack_start(GTK_BOX(gui->shbox), next, FALSE, FALSE, 0); @@ -3340,10 +3667,10 @@ mg_create_entry (session *sess, GtkWidget *box) GtkWidget *hbox, *but, *entry, *emoji_button; session_gui *gui = sess->gui; - hbox = gtk_hbox_new (FALSE, 0); + hbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), hbox, 0, 0, 0); - gui->nick_box = gtk_hbox_new (FALSE, 0); + gui->nick_box = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), gui->nick_box, 0, 0, 0); gui->nick_label = but = gtk_button_new_with_label (sess->server->nick); @@ -3446,7 +3773,12 @@ mg_create_tabs (session_gui *gui) gui->chanview = chanview_new (prefs.hex_gui_tab_layout, prefs.hex_gui_tab_trunc, prefs.hex_gui_tab_sort, use_icons, - prefs.hex_gui_ulist_style ? input_style : NULL); +#if HAVE_GTK3 + input_style ? input_style->font_desc : NULL +#else + prefs.hex_gui_ulist_style ? input_style : NULL +#endif + ); chanview_set_callbacks (gui->chanview, mg_switch_tab_cb, mg_xbutton_cb, mg_tab_contextmenu_cb, (void *)mg_tabs_compare); mg_place_userlist_and_chanview (gui); @@ -3489,8 +3821,16 @@ mg_create_menu (session_gui *gui, GtkWidget *table, int away_state) gui->menu = menu_create_main (accel_group, TRUE, away_state, !gui->is_tab, gui->menu_item); +#if HAVE_GTK3 + gtk_widget_set_hexpand (gui->menu, TRUE); + gtk_widget_set_vexpand (gui->menu, FALSE); + gtk_widget_set_halign (gui->menu, GTK_ALIGN_FILL); + gtk_widget_set_valign (gui->menu, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (table), gui->menu, 0, 0, 3, 1); +#else gtk_table_attach (GTK_TABLE (table), gui->menu, 0, 3, 0, 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#endif } static void @@ -3499,9 +3839,17 @@ mg_create_irctab (session *sess, GtkWidget *table) GtkWidget *vbox; session_gui *gui = sess->gui; - vbox = gtk_vbox_new (FALSE, 0); + vbox = mg_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); +#if HAVE_GTK3 + gtk_widget_set_hexpand (vbox, TRUE); + gtk_widget_set_vexpand (vbox, TRUE); + gtk_widget_set_halign (vbox, GTK_ALIGN_FILL); + gtk_widget_set_valign (vbox, GTK_ALIGN_FILL); + gtk_grid_attach (GTK_GRID (table), vbox, 1, 2, 1, 1); +#else gtk_table_attach (GTK_TABLE (table), vbox, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); +#endif mg_create_center (sess, gui, vbox); } @@ -3534,12 +3882,20 @@ mg_create_topwindow (session *sess) palette_alloc (win); + #if HAVE_GTK3 + table = gtk_grid_new (); + /* spacing under the menubar */ + gtk_grid_set_row_spacing (GTK_GRID (table), GUI_SPACING); + /* left and right borders */ + gtk_grid_set_column_spacing (GTK_GRID (table), 1); + #else table = gtk_table_new (4, 3, FALSE); /* spacing under the menubar */ gtk_table_set_row_spacing (GTK_TABLE (table), 0, GUI_SPACING); /* left and right borders */ gtk_table_set_col_spacing (GTK_TABLE (table), 0, 1); gtk_table_set_col_spacing (GTK_TABLE (table), 1, 1); + #endif gtk_container_add (GTK_CONTAINER (win), table); mg_create_irctab (sess, table); @@ -3657,6 +4013,27 @@ mg_win32_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data) } } + if (msg->message == WM_MOUSEWHEEL || msg->message == WM_MOUSEHWHEEL) + { + POINT cursor_pos; + HWND hover_hwnd; + DWORD hover_pid = 0; + + if (!GetCursorPos (&cursor_pos)) + return GDK_FILTER_CONTINUE; + + hover_hwnd = WindowFromPoint (cursor_pos); + if (!hover_hwnd || hover_hwnd == msg->hwnd) + return GDK_FILTER_CONTINUE; + + GetWindowThreadProcessId (hover_hwnd, &hover_pid); + if (hover_pid != GetCurrentProcessId ()) + return GDK_FILTER_CONTINUE; + + PostMessage (hover_hwnd, msg->message, msg->wParam, msg->lParam); + return GDK_FILTER_REMOVE; + } + return GDK_FILTER_CONTINUE; } #endif @@ -3695,12 +4072,20 @@ mg_create_tabwindow (session *sess) palette_alloc (win); + #if HAVE_GTK3 + sess->gui->main_table = table = gtk_grid_new (); + /* spacing under the menubar */ + gtk_grid_set_row_spacing (GTK_GRID (table), GUI_SPACING); + /* left and right borders */ + gtk_grid_set_column_spacing (GTK_GRID (table), 1); + #else sess->gui->main_table = table = gtk_table_new (4, 3, FALSE); /* spacing under the menubar */ gtk_table_set_row_spacing (GTK_TABLE (table), 0, GUI_SPACING); /* left and right borders */ gtk_table_set_col_spacing (GTK_TABLE (table), 0, 1); gtk_table_set_col_spacing (GTK_TABLE (table), 1, 1); + #endif gtk_container_add (GTK_CONTAINER (win), table); mg_create_irctab (sess, table); @@ -3855,7 +4240,7 @@ fe_dlgbuttons_update (session *sess) gtk_widget_destroy (gui->dialogbutton_box); - gui->dialogbutton_box = box = gtk_hbox_new (0, 0); + gui->dialogbutton_box = box = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_box_pack_start (GTK_BOX (gui->topic_bar), box, 0, 0, 0); gtk_box_reorder_child (GTK_BOX (gui->topic_bar), box, 3); mg_create_dialogbuttons (box); @@ -4008,7 +4393,7 @@ mg_create_generic_tab (char *name, char *title, int force_toplevel, if (force_toplevel || !prefs.hex_gui_tab_utils) { win = gtkutil_window_new (title, name, width, height, 2); - vbox = gtk_vbox_new (0, 0); + vbox = mg_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); *vbox_ret = vbox; gtk_container_add (GTK_CONTAINER (win), vbox); gtk_widget_show (vbox); @@ -4018,7 +4403,7 @@ mg_create_generic_tab (char *name, char *title, int force_toplevel, return win; } - vbox = gtk_vbox_new (0, 2); + vbox = mg_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 2); g_object_set_data (G_OBJECT (vbox), "w", GINT_TO_POINTER (width)); g_object_set_data (G_OBJECT (vbox), "h", GINT_TO_POINTER (height)); gtk_container_set_border_width (GTK_CONTAINER (vbox), 3); @@ -4032,7 +4417,7 @@ mg_create_generic_tab (char *name, char *title, int force_toplevel, /* if (link_buttons) { - hbox = gtk_hbox_new (FALSE, 0); + hbox = mg_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, 0, 0, 0); mg_create_link_buttons (hbox, ch); gtk_widget_show (hbox); @@ -4308,8 +4693,18 @@ mg_drag_motion_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, gui #if 0 /* are both tree/userlist on the same side? */ GtkPaned *paned; - paned = (GtkPaned *)widget->parent->parent; - if (paned->child1 != NULL && paned->child2 != NULL) + GtkWidget *parent; + GtkWidget *grandparent; + parent = gtk_widget_get_parent (widget); + grandparent = parent ? gtk_widget_get_parent (parent) : NULL; + paned = grandparent ? GTK_PANED (grandparent) : NULL; +#if HAVE_GTK3 + if (paned != NULL && + gtk_paned_get_child1 (paned) != NULL && + gtk_paned_get_child2 (paned) != NULL) +#else + if (paned != NULL && paned->child1 != NULL && paned->child2 != NULL) +#endif { cairo_rectangle (cr, 1 + ox, 2 + oy, width - 3, height - 4); cairo_rectangle (cr, 0 + ox, 1 + oy, width - 1, height - 2); diff --git a/src/fe-gtk/maingui.h b/src/fe-gtk/maingui.h index aaf5c2f8..9f7eae22 100644 --- a/src/fe-gtk/maingui.h +++ b/src/fe-gtk/maingui.h @@ -20,7 +20,7 @@ #ifndef ZOITECHAT_MAINGUI_H #define ZOITECHAT_MAINGUI_H -extern GtkStyle *input_style; +extern InputStyle *input_style; extern GtkWidget *parent_window; void mg_changui_new (session *sess, restore_gui *res, int tab, int focus); diff --git a/src/fe-gtk/menu.c b/src/fe-gtk/menu.c index 2e3bb61c..4f649445 100644 --- a/src/fe-gtk/menu.c +++ b/src/fe-gtk/menu.c @@ -267,6 +267,12 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, { GtkWidget *img, *item; char *path; +#if HAVE_GTK3 + const char *icon_name = NULL; + GtkWidget *box; + GtkWidget *image = NULL; + GtkWidget *label_widget; +#endif if (!label) item = gtk_menu_item_new (); @@ -277,7 +283,6 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, /*if (flags & XCMENU_MARKUP) item = gtk_image_menu_item_new_with_markup (label); else*/ - item = gtk_image_menu_item_new_with_mnemonic (label); img = NULL; if (access (icon, R_OK) == 0) /* try fullpath */ img = gtk_image_new_from_file (icon); @@ -288,12 +293,36 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, if (access (path, R_OK) == 0) img = gtk_image_new_from_file (path); else + { +#if HAVE_GTK3 + icon_name = gtkutil_icon_name_from_stock (icon); + if (!icon_name) + icon_name = icon; +#endif +#if !HAVE_GTK3 img = gtk_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); +#endif + } g_free (path); } +#if HAVE_GTK3 + item = gtk_menu_item_new (); + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + if (icon_name) + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); + else if (img) + image = img; + label_widget = gtk_label_new_with_mnemonic (label); + if (image) + gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), label_widget, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (item), box); +#else + item = gtk_image_menu_item_new_with_mnemonic (label); if (img) gtk_image_menu_item_set_image ((GtkImageMenuItem *)item, img); +#endif } else { @@ -301,9 +330,20 @@ menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, { item = gtk_menu_item_new_with_label (""); if (flags & XCMENU_MNEMONIC) + { +#if HAVE_GTK3 + gtk_label_set_markup_with_mnemonic (GTK_LABEL (gtk_bin_get_child (GTK_BIN (item))), label); +#else gtk_label_set_markup_with_mnemonic (GTK_LABEL (GTK_BIN (item)->child), label); - else +#endif + } else + { +#if HAVE_GTK3 + gtk_label_set_markup (GTK_LABEL (gtk_bin_get_child (GTK_BIN (item))), label); +#else gtk_label_set_markup (GTK_LABEL (GTK_BIN (item)->child), label); +#endif + } } else { if (flags & XCMENU_MNEMONIC) @@ -352,7 +392,11 @@ menu_quick_sub (char *name, GtkWidget *menu, GtkWidget **sub_item_ret, int flags if (flags & XCMENU_MARKUP) { sub_item = gtk_menu_item_new_with_label (""); +#if HAVE_GTK3 + gtk_label_set_markup (GTK_LABEL (gtk_bin_get_child (GTK_BIN (sub_item))), name); +#else gtk_label_set_markup (GTK_LABEL (GTK_BIN (sub_item)->child), name); +#endif } else { @@ -392,7 +436,11 @@ toggle_cb (GtkWidget *item, char *pref_name) { char buf[256]; +#if HAVE_GTK3 + if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item))) +#else if (GTK_CHECK_MENU_ITEM (item)->active) +#endif g_snprintf (buf, sizeof (buf), "set %s 1", pref_name); else g_snprintf (buf, sizeof (buf), "set %s 0", pref_name); @@ -573,8 +621,26 @@ menu_popup (GtkWidget *menu, GdkEventButton *event, gpointer objtounref) g_object_unref (menu); g_signal_connect (G_OBJECT (menu), "selection-done", G_CALLBACK (menu_destroy), objtounref); +#if HAVE_GTK3 + if (event) + { + gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *)event); + } + else if (parent_window) + { + gtk_menu_popup_at_widget (GTK_MENU (menu), GTK_WIDGET (parent_window), + GDK_GRAVITY_SOUTH_WEST, + GDK_GRAVITY_NORTH_WEST, + NULL); + } + else + { + gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL); + } +#else gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, event ? event->time : 0); +#endif } static void @@ -695,6 +761,9 @@ void fe_userlist_update (session *sess, struct User *user) { GList *items, *next; +#if HAVE_GTK3 + GList *iter; +#endif if (!nick_submenu || !str_copy) return; @@ -707,6 +776,17 @@ fe_userlist_update (session *sess, struct User *user) g_signal_handlers_disconnect_by_func (nick_submenu, menu_nickinfo_cb, sess); /* destroy all the old items */ +#if HAVE_GTK3 + items = gtk_container_get_children (GTK_CONTAINER (nick_submenu)); + iter = items; + while (iter) + { + next = iter->next; + gtk_widget_destroy (iter->data); + iter = next; + } + g_list_free (items); +#else items = ((GtkMenuShell *) nick_submenu)->children; while (items) { @@ -714,6 +794,7 @@ fe_userlist_update (session *sess, struct User *user) gtk_widget_destroy (items->data); items = next; } +#endif /* and re-create them with new info */ menu_create_nickinfo_menu (user, nick_submenu); @@ -838,7 +919,18 @@ menu_setting_foreach (void (*callback) (session *), int id, guint state) if (sess->gui->is_tab) maindone = TRUE; if (id != -1) - GTK_CHECK_MENU_ITEM (sess->gui->menu_item[id])->active = state; + { + GtkWidget *menu_item = sess->gui->menu_item[id]; + + if (menu_item != NULL) + { +#if HAVE_GTK3 + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), state); +#else + GTK_CHECK_MENU_ITEM (menu_item)->active = state; +#endif + } + } if (callback) callback (sess); } @@ -1168,8 +1260,22 @@ usermenu_create (GtkWidget *menu) static void usermenu_destroy (GtkWidget * menu) { - GList *items = ((GtkMenuShell *) menu)->children; + GList *items; GList *next; +#if HAVE_GTK3 + GList *iter; + + items = gtk_container_get_children (GTK_CONTAINER (menu)); + iter = items; + while (iter) + { + next = iter->next; + gtk_widget_destroy (iter->data); + iter = next; + } + g_list_free (items); +#else + items = ((GtkMenuShell *) menu)->children; while (items) { @@ -1177,6 +1283,7 @@ usermenu_destroy (GtkWidget * menu) gtk_widget_destroy (items->data); items = next; } +#endif } void @@ -1387,7 +1494,11 @@ menu_join_cb (GtkWidget *dialog, gint response, GtkEntry *entry) switch (response) { case GTK_RESPONSE_ACCEPT: +#if HAVE_GTK3 + menu_chan_join (NULL, (char *)gtk_entry_get_text (GTK_ENTRY (entry))); +#else menu_chan_join (NULL, entry->text); +#endif break; case GTK_RESPONSE_HELP: @@ -1408,19 +1519,59 @@ static void menu_join (GtkWidget * wid, gpointer none) { GtkWidget *hbox, *dialog, *entry, *label; +#if HAVE_GTK3 + GtkWidget *content_area; +#endif +#if HAVE_GTK3 + dialog = gtk_dialog_new_with_buttons (_("Join Channel"), + GTK_WINDOW (parent_window), 0, + _("Retrieve channel list"), GTK_RESPONSE_HELP, + _("_Cancel"), GTK_RESPONSE_REJECT, + _("_OK"), GTK_RESPONSE_ACCEPT, + NULL); + { + GtkWidget *button; + + button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_HELP); + if (button) + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_icon_name ("help-browser", GTK_ICON_SIZE_BUTTON)); + + button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT); + if (button) + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_icon_name ("dialog-cancel", GTK_ICON_SIZE_BUTTON)); + + button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); + if (button) + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_icon_name ("dialog-ok", GTK_ICON_SIZE_BUTTON)); + } +#endif +#if !HAVE_GTK3 dialog = gtk_dialog_new_with_buttons (_("Join Channel"), GTK_WINDOW (parent_window), 0, _("Retrieve channel list"), GTK_RESPONSE_HELP, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); +#endif +#if HAVE_GTK3 + content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + gtk_box_set_homogeneous (GTK_BOX (content_area), TRUE); +#else gtk_box_set_homogeneous (GTK_BOX (GTK_DIALOG (dialog)->vbox), TRUE); +#endif gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); - hbox = gtk_hbox_new (TRUE, 0); + hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, TRUE, 0); entry = gtk_entry_new (); +#if HAVE_GTK3 + gtk_editable_set_editable (GTK_EDITABLE (entry), FALSE); /* avoid auto-selection */ +#else GTK_ENTRY (entry)->editable = 0; /* avoid auto-selection */ +#endif gtk_entry_set_text (GTK_ENTRY (entry), "#"); g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (menu_join_entry_cb), dialog); @@ -1432,7 +1583,11 @@ menu_join (GtkWidget * wid, gpointer none) g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (menu_join_cb), entry); +#if HAVE_GTK3 + gtk_container_add (GTK_CONTAINER (content_area), hbox); +#else gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); +#endif gtk_widget_show_all (dialog); @@ -1655,7 +1810,11 @@ static void menu_layout_cb (GtkWidget *item, gpointer none) { prefs.hex_gui_tab_layout = 2; +#if HAVE_GTK3 + if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item))) +#else if (GTK_CHECK_MENU_ITEM (item)->active) +#endif prefs.hex_gui_tab_layout = 0; menu_change_layout (); @@ -1670,7 +1829,11 @@ menu_apply_metres_cb (session *sess) static void menu_metres_off (GtkWidget *item, gpointer none) { +#if HAVE_GTK3 + if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item))) +#else if (GTK_CHECK_MENU_ITEM (item)->active) +#endif { prefs.hex_gui_lagometer = 0; prefs.hex_gui_throttlemeter = 0; @@ -1682,7 +1845,11 @@ menu_metres_off (GtkWidget *item, gpointer none) static void menu_metres_text (GtkWidget *item, gpointer none) { +#if HAVE_GTK3 + if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item))) +#else if (GTK_CHECK_MENU_ITEM (item)->active) +#endif { prefs.hex_gui_lagometer = 2; prefs.hex_gui_throttlemeter = 2; @@ -1694,7 +1861,11 @@ menu_metres_text (GtkWidget *item, gpointer none) static void menu_metres_graph (GtkWidget *item, gpointer none) { +#if HAVE_GTK3 + if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item))) +#else if (GTK_CHECK_MENU_ITEM (item)->active) +#endif { prefs.hex_gui_lagometer = 1; prefs.hex_gui_throttlemeter = 1; @@ -1706,7 +1877,11 @@ menu_metres_graph (GtkWidget *item, gpointer none) static void menu_metres_both (GtkWidget *item, gpointer none) { +#if HAVE_GTK3 + if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item))) +#else if (GTK_CHECK_MENU_ITEM (item)->active) +#endif { prefs.hex_gui_lagometer = 3; prefs.hex_gui_throttlemeter = 3; @@ -1757,7 +1932,11 @@ menu_about (GtkWidget *wid, gpointer sess) gtk_about_dialog_set_program_name (dialog, _(DISPLAY_NAME)); gtk_about_dialog_set_version (dialog, PACKAGE_VERSION); - gtk_about_dialog_set_license (dialog, license); /* gtk3 can use GTK_LICENSE_GPL_2_0 */ +#if HAVE_GTK3 + gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG (dialog), GTK_LICENSE_GPL_2_0); +#else + gtk_about_dialog_set_license (dialog, license); +#endif gtk_about_dialog_set_website (dialog, "http://zoitechat.zoite.net"); gtk_about_dialog_set_website_label (dialog, "Website"); gtk_about_dialog_set_logo (dialog, pix_zoitechat); @@ -1771,12 +1950,49 @@ menu_about (GtkWidget *wid, gpointer sess) gtk_widget_show_all (GTK_WIDGET(dialog)); } +#if HAVE_GTK3 +#define ICON_NEW "document-new" +#define ICON_LOAD_PLUGIN "document-open" +#define ICON_DETACH "edit-redo" +#define ICON_CLOSE "window-close" +#define ICON_QUIT "application-exit" +#define ICON_DISCONNECT "network-disconnect" +#define ICON_CONNECT "network-connect" +#define ICON_JOIN "go-jump" +#define ICON_CHANLIST "view-list" +#define ICON_PREFERENCES "preferences-system" +#define ICON_CLEAR "edit-clear" +#define ICON_SAVE "document-save" +#define ICON_SEARCH "edit-find" +#define ICON_FIND "edit-find" +#define ICON_HELP "help-contents" +#define ICON_ABOUT "help-about" +#endif +#if !HAVE_GTK3 +#define ICON_NEW GTK_STOCK_NEW +#define ICON_LOAD_PLUGIN GTK_STOCK_REVERT_TO_SAVED +#define ICON_DETACH GTK_STOCK_REDO +#define ICON_CLOSE GTK_STOCK_CLOSE +#define ICON_QUIT GTK_STOCK_QUIT +#define ICON_DISCONNECT GTK_STOCK_DISCONNECT +#define ICON_CONNECT GTK_STOCK_CONNECT +#define ICON_JOIN GTK_STOCK_JUMP_TO +#define ICON_CHANLIST GTK_STOCK_INDEX +#define ICON_PREFERENCES GTK_STOCK_PREFERENCES +#define ICON_CLEAR GTK_STOCK_CLEAR +#define ICON_SAVE GTK_STOCK_SAVE +#define ICON_SEARCH GTK_STOCK_JUSTIFY_LEFT +#define ICON_FIND GTK_STOCK_FIND +#define ICON_HELP GTK_STOCK_HELP +#define ICON_ABOUT GTK_STOCK_ABOUT +#endif + static struct mymenu mymenu[] = { {N_("_ZoiteChat"), 0, 0, M_NEWMENU, MENU_ID_ZOITECHAT, 0, 1}, {N_("Network Li_st"), menu_open_server_list, (char *)&pix_book, M_MENUPIX, 0, 0, 1, GDK_KEY_s}, {0, 0, 0, M_SEP, 0, 0, 0}, - {N_("_New"), 0, GTK_STOCK_NEW, M_MENUSUB, 0, 0, 1}, + {N_("_New"), 0, ICON_NEW, M_MENUSUB, 0, 0, 1}, {N_("Server Tab"), menu_newserver_tab, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_t}, {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}, @@ -1784,14 +2000,14 @@ static struct mymenu mymenu[] = { {0, 0, 0, M_END, 0, 0, 0}, {0, 0, 0, M_SEP, 0, 0, 0}, - {N_("_Load Plugin or Script" ELLIPSIS), menu_loadplugin, GTK_STOCK_REVERT_TO_SAVED, M_MENUSTOCK, 0, 0, 1}, + {N_("_Load Plugin or Script" ELLIPSIS), menu_loadplugin, ICON_LOAD_PLUGIN, M_MENUSTOCK, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, /* 11 */ #define DETACH_OFFSET (12) - {0, menu_detach, GTK_STOCK_REDO, M_MENUSTOCK, 0, 0, 1}, /* 12 */ + {0, menu_detach, ICON_DETACH, M_MENUSTOCK, 0, 0, 1}, /* 12 */ #define CLOSE_OFFSET (13) - {0, menu_close, GTK_STOCK_CLOSE, M_MENUSTOCK, 0, 0, 1}, + {0, menu_close, ICON_CLOSE, M_MENUSTOCK, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, - {N_("_Quit"), menu_quit, GTK_STOCK_QUIT, M_MENUSTOCK, 0, 0, 1, GDK_KEY_q}, /* 15 */ + {N_("_Quit"), menu_quit, ICON_QUIT, M_MENUSTOCK, 0, 0, 1, GDK_KEY_q}, /* 15 */ {N_("_View"), 0, 0, M_NEWMENU, 0, 0, 1}, #define MENUBAR_OFFSET (17) @@ -1817,10 +2033,10 @@ static struct mymenu mymenu[] = { {N_ ("_Fullscreen"), menu_fullscreen_toggle, 0, M_MENUTOG, MENU_ID_FULLSCREEN, 0, 1, GDK_KEY_F11}, {N_("_Server"), 0, 0, M_NEWMENU, 0, 0, 1}, - {N_("_Disconnect"), menu_disconnect, GTK_STOCK_DISCONNECT, M_MENUSTOCK, MENU_ID_DISCONNECT, 0, 1}, - {N_("_Reconnect"), menu_reconnect, GTK_STOCK_CONNECT, M_MENUSTOCK, MENU_ID_RECONNECT, 0, 1}, - {N_("_Join a Channel" ELLIPSIS), menu_join, GTK_STOCK_JUMP_TO, M_MENUSTOCK, MENU_ID_JOIN, 0, 1}, - {N_("Channel _List"), menu_chanlist, GTK_STOCK_INDEX, M_MENUITEM, 0, 0, 1}, + {N_("_Disconnect"), menu_disconnect, ICON_DISCONNECT, M_MENUSTOCK, MENU_ID_DISCONNECT, 0, 1}, + {N_("_Reconnect"), menu_reconnect, ICON_CONNECT, M_MENUSTOCK, MENU_ID_RECONNECT, 0, 1}, + {N_("_Join a Channel" ELLIPSIS), menu_join, ICON_JOIN, M_MENUSTOCK, MENU_ID_JOIN, 0, 1}, + {N_("Channel _List"), menu_chanlist, ICON_CHANLIST, M_MENUITEM, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, #define AWAY_OFFSET (41) {N_("Marked _Away"), menu_away, 0, M_MENUTOG, MENU_ID_AWAY, 0, 1, GDK_KEY_a}, @@ -1828,7 +2044,7 @@ static struct mymenu mymenu[] = { {N_("_Usermenu"), 0, 0, M_NEWMENU, MENU_ID_USERMENU, 0, 1}, /* 40 */ {N_("S_ettings"), 0, 0, M_NEWMENU, 0, 0, 1}, - {N_("_Preferences"), menu_settings, GTK_STOCK_PREFERENCES, M_MENUSTOCK, 0, 0, 1}, + {N_("_Preferences"), menu_settings, ICON_PREFERENCES, M_MENUSTOCK, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, {N_("Auto Replace"), menu_rpopup, 0, M_MENUITEM, 0, 0, 1}, {N_("CTCP Replies"), menu_ctcpguiopen, 0, M_MENUITEM, 0, 0, 1}, @@ -1854,18 +2070,18 @@ static struct mymenu mymenu[] = { {N_("Reset Marker Line"), menu_resetmarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_m}, {N_("Move to Marker Line"), menu_movetomarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_M}, {N_("_Copy Selection"), menu_copy_selection, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_C}, - {N_("C_lear Text"), menu_flushbuffer, GTK_STOCK_CLEAR, M_MENUSTOCK, 0, 0, 1}, - {N_("Save Text" ELLIPSIS), menu_savebuffer, GTK_STOCK_SAVE, M_MENUSTOCK, 0, 0, 1}, + {N_("C_lear Text"), menu_flushbuffer, ICON_CLEAR, M_MENUSTOCK, 0, 0, 1}, + {N_("Save Text" ELLIPSIS), menu_savebuffer, ICON_SAVE, M_MENUSTOCK, 0, 0, 1}, #define SEARCH_OFFSET (70) - {N_("Search"), 0, GTK_STOCK_JUSTIFY_LEFT, M_MENUSUB, 0, 0, 1}, - {N_("Search Text" ELLIPSIS), menu_search, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_f}, - {N_("Search Next" ), menu_search_next, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_g}, - {N_("Search Previous" ), menu_search_prev, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_G}, + {N_("Search"), 0, ICON_SEARCH, M_MENUSUB, 0, 0, 1}, + {N_("Search Text" ELLIPSIS), menu_search, ICON_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_f}, + {N_("Search Next" ), menu_search_next, ICON_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_g}, + {N_("Search Previous" ), menu_search_prev, ICON_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_G}, {0, 0, 0, M_END, 0, 0, 0}, {N_("_Help"), 0, 0, M_NEWMENU, 0, 0, 1}, /* 74 */ - {N_("_Contents"), menu_docs, GTK_STOCK_HELP, M_MENUSTOCK, 0, 0, 1, GDK_KEY_F1}, - {N_("_About"), menu_about, GTK_STOCK_ABOUT, M_MENUSTOCK, 0, 0, 1}, + {N_("_Contents"), menu_docs, ICON_HELP, M_MENUSTOCK, 0, 0, 1, GDK_KEY_F1}, + {N_("_About"), menu_about, ICON_ABOUT, M_MENUSTOCK, 0, 0, 1}, {0, 0, 0, M_END, 0, 0, 0}, }; @@ -1893,15 +2109,56 @@ menu_set_fullscreen (session_gui *gui, int full) GtkWidget * create_icon_menu (char *labeltext, void *stock_name, int is_stock) { - GtkWidget *item, *img; + GtkWidget *item; +#if HAVE_GTK3 + GtkWidget *box; + GtkWidget *label_widget; + GtkWidget *image = NULL; + const char *icon_name; +#endif +#if !HAVE_GTK3 + GtkWidget *img; +#endif if (is_stock) + { +#if HAVE_GTK3 + icon_name = gtkutil_icon_name_from_stock (stock_name); + if (!icon_name) + icon_name = stock_name; + if (icon_name) + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); +#endif +#if !HAVE_GTK3 img = gtk_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); +#endif + } else + { +#if HAVE_GTK3 + image = gtk_image_new_from_pixbuf (*((GdkPixbuf **)stock_name)); +#endif +#if !HAVE_GTK3 img = gtk_image_new_from_pixbuf (*((GdkPixbuf **)stock_name)); +#endif + } +#if HAVE_GTK3 + item = gtk_menu_item_new (); + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + label_widget = gtk_label_new_with_mnemonic (labeltext); + if (image) + gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), label_widget, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (item), box); + if (image) + gtk_widget_show (image); + gtk_widget_show (label_widget); + gtk_widget_show (box); +#else item = gtk_image_menu_item_new_with_mnemonic (labeltext); gtk_image_menu_item_set_image ((GtkImageMenuItem *)item, img); gtk_widget_show (img); +#endif return item; } @@ -1920,30 +2177,71 @@ menu_canacaccel (GtkWidget *widget, guint signal_id, gpointer user_data) static GtkMenuItem * menu_find_item (GtkWidget *menu, char *name) { - GList *items = ((GtkMenuShell *) menu)->children; + GList *items; +#if HAVE_GTK3 + GList *items_head; +#endif GtkMenuItem *item; GtkWidget *child; const char *labeltext; + GtkMenuItem *found = NULL; +#if HAVE_GTK3 + items_head = gtk_container_get_children (GTK_CONTAINER (menu)); + items = items_head; +#else + items = ((GtkMenuShell *) menu)->children; +#endif while (items) { item = items->data; +#if HAVE_GTK3 + child = gtk_bin_get_child (GTK_BIN (item)); +#else child = GTK_BIN (item)->child; +#endif if (child) /* separators arn't labels, skip them */ { labeltext = g_object_get_data (G_OBJECT (item), "name"); if (!labeltext) - labeltext = gtk_label_get_text (GTK_LABEL (child)); + { + if (GTK_IS_LABEL (child)) + labeltext = gtk_label_get_text (GTK_LABEL (child)); +#ifdef HAVE_GTK3 + else if (GTK_IS_CONTAINER (child)) + { + GList *kids, *l; + kids = gtk_container_get_children (GTK_CONTAINER (child)); + for (l = kids; l; l = l->next) + { + if (GTK_IS_LABEL (l->data)) + { + labeltext = gtk_label_get_text (GTK_LABEL (l->data)); + break; + } + } + g_list_free (kids); + } +#endif + } + if (!menu_streq (labeltext, name, 1)) - return item; + { + found = item; + break; + } } else if (name == NULL) { - return item; + found = item; + break; } items = items->next; } +#if HAVE_GTK3 + g_list_free (items_head); +#endif - return NULL; + return found; } static GtkWidget * @@ -2025,7 +2323,11 @@ menu_update_cb (GtkWidget *menu, menu_entry *me, char *target) gtk_widget_set_sensitive (item, me->enable); /* must do it without triggering the callback */ if (GTK_IS_CHECK_MENU_ITEM (item)) +#if HAVE_GTK3 + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), me->state); +#else GTK_CHECK_MENU_ITEM (item)->active = me->state; +#endif } } @@ -2034,7 +2336,11 @@ static void menu_radio_cb (GtkCheckMenuItem *item, menu_entry *me) { me->state = 0; +#if HAVE_GTK3 + if (gtk_check_menu_item_get_active (item)) +#else if (item->active) +#endif me->state = 1; /* update the state, incase this was changed via right-click. */ @@ -2050,7 +2356,11 @@ static void menu_toggle_cb (GtkCheckMenuItem *item, menu_entry *me) { me->state = 0; +#if HAVE_GTK3 + if (gtk_check_menu_item_get_active (item)) +#else if (item->active) +#endif me->state = 1; /* update the state, incase this was changed via right-click. */ @@ -2092,7 +2402,17 @@ menu_reorder (GtkMenu *menu, GtkWidget *item, int pos) return; if (pos < 0) /* position offset from end/bottom */ +#if HAVE_GTK3 + { + GList *children = gtk_container_get_children (GTK_CONTAINER (menu)); + int length = g_list_length (children); + + g_list_free (children); + gtk_menu_reorder_child (menu, item, (length + pos) - 1); + } +#else gtk_menu_reorder_child (menu, item, (g_list_length (GTK_MENU_SHELL (menu)->children) + pos) - 1); +#endif else gtk_menu_reorder_child (menu, item, pos); } @@ -2158,7 +2478,17 @@ menu_add_sub (GtkWidget *menu, menu_entry *me) { pos = me->pos; if (pos < 0) /* position offset from end/bottom */ +#if HAVE_GTK3 + { + GList *children = gtk_container_get_children (GTK_CONTAINER (menu)); + int length = g_list_length (children); + + g_list_free (children); + pos = length + pos; + } +#else pos = g_list_length (GTK_MENU_SHELL (menu)->children) + pos; +#endif menu_quick_sub (me->label, menu, &item, me->markup ? XCMENU_MARKUP|XCMENU_MNEMONIC : XCMENU_MNEMONIC, pos); } return item; @@ -2436,7 +2766,11 @@ normalitem: item = gtk_check_menu_item_new_with_mnemonic (_(mymenu[i].text)); togitem: /* must avoid callback for Radio buttons */ +#if HAVE_GTK3 + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), mymenu[i].state); +#else GTK_CHECK_MENU_ITEM (item)->active = mymenu[i].state; +#endif /*gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), mymenu[i].state);*/ if (mymenu[i].key != 0) diff --git a/src/fe-gtk/meson.build b/src/fe-gtk/meson.build index 3248857c..a845ab05 100644 --- a/src/fe-gtk/meson.build +++ b/src/fe-gtk/meson.build @@ -28,18 +28,50 @@ zoitechat_gtk_sources = [ 'xtext.c' ] -gtk_dep = dependency('gtk+-2.0', version: '>= 2.24.0') +zoitechat_gtk_cflags = [] + zoitechat_gtk_deps = [ zoitechat_common_dep, libgmodule_dep, # used by libsexy - gtk_dep ] -if gtk_dep.get_pkgconfig_variable('target') == 'x11' - zoitechat_gtk_deps += dependency('x11') +if get_option('gtk3') + gtk_dep = dependency('gtk+-3.0', version: '>= 3.22') + zoitechat_gtk_cflags += '-DHAVE_GTK3' + + if host_machine.system() != 'windows' + appindicator_dep = dependency('ayatana-appindicator3-0.1', required: false) + if appindicator_dep.found() + zoitechat_gtk_deps += appindicator_dep + zoitechat_gtk_cflags += '-DHAVE_AYATANA_APPINDICATOR' + else + appindicator_dep = dependency('appindicator3-0.1', required: false) + if appindicator_dep.found() + zoitechat_gtk_deps += appindicator_dep + zoitechat_gtk_cflags += '-DHAVE_APPINDICATOR' + endif + endif + endif +else + gtk_dep = dependency('gtk+-2.0', version: '>= 2.24.0') + zoitechat_gtk_cflags += '-DHAVE_GTK2' endif -zoitechat_gtk_cflags = [] +zoitechat_gtk_deps += gtk_dep + +if host_machine.system() != 'windows' + if get_option('gtk3') + gdk_x11_dep = dependency('gdk-x11-3.0', required: false) + if gdk_x11_dep.found() + zoitechat_gtk_deps += gdk_x11_dep + endif + endif + + x11_dep = dependency('x11', required: false) + if x11_dep.found() + zoitechat_gtk_deps += x11_dep + endif +endif zoitechat_gtk_ldflags = [] diff --git a/src/fe-gtk/notifygui.c b/src/fe-gtk/notifygui.c index 42d61fdb..1ddc5700 100644 --- a/src/fe-gtk/notifygui.c +++ b/src/fe-gtk/notifygui.c @@ -37,6 +37,19 @@ #include "palette.h" #include "notifygui.h" +#if HAVE_GTK3 +#define ICON_NOTIFY_NEW "document-new" +#define ICON_NOTIFY_DELETE "edit-delete" +#define LABEL_NOTIFY_CANCEL _("_Cancel") +#define LABEL_NOTIFY_OK _("_OK") +#endif +#if !HAVE_GTK3 +#define ICON_NOTIFY_NEW GTK_STOCK_NEW +#define ICON_NOTIFY_DELETE GTK_STOCK_DELETE +#define LABEL_NOTIFY_CANCEL GTK_STOCK_CANCEL +#define LABEL_NOTIFY_OK GTK_STOCK_OK +#endif + /* model for the notify treeview */ enum @@ -64,7 +77,7 @@ notify_closegui (void) } /* Need this to be able to set the foreground colour property of a row - * from a GdkColor * in the model -Vince + * from a PaletteColor * in the model -Vince */ static void notify_treecell_property_mapper (GtkTreeViewColumn *col, GtkCellRenderer *cell, @@ -72,17 +85,44 @@ notify_treecell_property_mapper (GtkTreeViewColumn *col, GtkCellRenderer *cell, gpointer data) { gchar *text; - GdkColor *colour; + PaletteColor *colour; int model_column = GPOINTER_TO_INT (data); gtk_tree_model_get (GTK_TREE_MODEL (model), iter, COLOUR_COLUMN, &colour, model_column, &text, -1); - g_object_set (G_OBJECT (cell), "text", text, NULL); - g_object_set (G_OBJECT (cell), "foreground-gdk", colour, NULL); +#if HAVE_GTK3 + g_object_set (G_OBJECT (cell), "text", text, + PALETTE_FOREGROUND_PROPERTY, colour, NULL); + if (colour) + gdk_rgba_free (colour); +#else + g_object_set (G_OBJECT (cell), "text", text, + PALETTE_FOREGROUND_PROPERTY, colour, NULL); + if (colour) + gdk_color_free (colour); +#endif g_free (text); } +static void +notify_store_color (GtkListStore *store, GtkTreeIter *iter, const PaletteColor *color) +{ +#if HAVE_GTK3 + if (color) + { + GdkRGBA rgba = *color; + gtk_list_store_set (store, iter, COLOUR_COLUMN, &rgba, -1); + } + else + { + gtk_list_store_set (store, iter, COLOUR_COLUMN, NULL, -1); + } +#else + gtk_list_store_set (store, iter, COLOUR_COLUMN, color, -1); +#endif +} + static void notify_row_cb (GtkTreeSelection *sel, GtkTreeView *view) { @@ -105,6 +145,7 @@ notify_treeview_new (GtkWidget *box) { GtkListStore *store; GtkWidget *view; + GtkWidget *scroll; GtkTreeViewColumn *col; int col_id; @@ -113,7 +154,7 @@ notify_treeview_new (GtkWidget *box) G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_POINTER, /* can't specify colour! */ + PALETTE_GDK_TYPE, G_TYPE_POINTER ); g_return_val_if_fail (store != NULL, NULL); @@ -124,6 +165,8 @@ notify_treeview_new (GtkWidget *box) STATUS_COLUMN, _("Status"), SERVER_COLUMN, _("Network"), SEEN_COLUMN, _("Last Seen"), -1); + scroll = gtk_widget_get_parent (view); + gtk_box_set_child_packing (GTK_BOX (box), scroll, TRUE, TRUE, 0, GTK_PACK_START); gtk_tree_view_column_set_expand (gtk_tree_view_get_column (GTK_TREE_VIEW (view), 0), TRUE); for (col_id=0; (col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), col_id)); @@ -200,7 +243,8 @@ notify_gui_update (void) if (!valid) /* create new tree row if required */ gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, name, 1, status, - 2, server, 3, seen, 4, &colors[4], 5, NULL, -1); + 2, server, 3, seen, 5, NULL, -1); + notify_store_color (store, &iter, &colors[4]); if (valid) valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter); @@ -225,7 +269,8 @@ notify_gui_update (void) if (!valid) /* create new tree row if required */ gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, name, 1, status, - 2, server, 3, seen, 4, &colors[3], 5, servnot, -1); + 2, server, 3, seen, 5, servnot, -1); + notify_store_color (store, &iter, &colors[3]); if (valid) valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter); @@ -344,45 +389,50 @@ fe_notify_ask (char *nick, char *networks) char buf[256]; dialog = gtk_dialog_new_with_buttons (msg, NULL, 0, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + LABEL_NOTIFY_CANCEL, GTK_RESPONSE_REJECT, + LABEL_NOTIFY_OK, GTK_RESPONSE_ACCEPT, NULL); if (parent_window) gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent_window)); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); - table = gtk_table_new (2, 3, FALSE); + table = gtkutil_grid_new (2, 3, FALSE); gtk_container_set_border_width (GTK_CONTAINER (table), 12); +#if HAVE_GTK3 + gtk_grid_set_row_spacing (GTK_GRID (table), 3); + gtk_grid_set_column_spacing (GTK_GRID (table), 8); +#else gtk_table_set_row_spacings (GTK_TABLE (table), 3); gtk_table_set_col_spacings (GTK_TABLE (table), 8); +#endif gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), table); label = gtk_label_new (msg); - gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1); + gtkutil_grid_attach_defaults (table, label, 0, 1, 0, 1); entry = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (entry), nick); g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (notifygui_add_enter), dialog); - gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 0, 1); + gtkutil_grid_attach_defaults (table, entry, 1, 2, 0, 1); g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (notifygui_add_cb), entry); label = gtk_label_new (_("Notify on these networks:")); - gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 2, 3); + gtkutil_grid_attach_defaults (table, label, 0, 1, 2, 3); wid = gtk_entry_new (); g_object_set_data (G_OBJECT (entry), "net", wid); g_signal_connect (G_OBJECT (wid), "activate", G_CALLBACK (notifygui_add_enter), dialog); gtk_entry_set_text (GTK_ENTRY (wid), networks ? networks : "ALL"); - gtk_table_attach_defaults (GTK_TABLE (table), wid, 1, 2, 2, 3); + gtkutil_grid_attach_defaults (table, wid, 1, 2, 2, 3); label = gtk_label_new (NULL); g_snprintf (buf, sizeof (buf), "%s", _("Comma separated list of networks is accepted.")); gtk_label_set_markup (GTK_LABEL (label), buf); - gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, 3, 4); + gtkutil_grid_attach_defaults (table, label, 1, 2, 3, 4); gtk_widget_show_all (dialog); } @@ -415,17 +465,22 @@ notify_opengui (void) view = notify_treeview_new (vbox); g_object_set_data (G_OBJECT (notify_window), "view", view); +#if HAVE_GTK3 + bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 bbox = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD); +#endif gtk_container_set_border_width (GTK_CONTAINER (bbox), 5); gtk_box_pack_end (GTK_BOX (vbox), bbox, 0, 0, 0); gtk_widget_show (bbox); - gtkutil_button (bbox, GTK_STOCK_NEW, 0, notify_add_clicked, 0, + gtkutil_button (bbox, ICON_NOTIFY_NEW, 0, notify_add_clicked, 0, _("Add...")); notify_button_remove = - gtkutil_button (bbox, GTK_STOCK_DELETE, 0, notify_remove_clicked, 0, + gtkutil_button (bbox, ICON_NOTIFY_DELETE, 0, notify_remove_clicked, 0, _("Remove")); notify_button_opendialog = diff --git a/src/fe-gtk/palette.c b/src/fe-gtk/palette.c index f2af5bd1..1092dc6a 100644 --- a/src/fe-gtk/palette.c +++ b/src/fe-gtk/palette.c @@ -38,121 +38,167 @@ #include "../common/cfgfiles.h" #include "../common/typedef.h" +#if HAVE_GTK3 +#define PALETTE_COLOR_INIT(r, g, b) { (r) / 65535.0, (g) / 65535.0, (b) / 65535.0, 1.0 } +#else +#define PALETTE_COLOR_INIT(r, g, b) { 0, (r), (g), (b) } +#endif + +static void +palette_color_set_rgb16 (PaletteColor *color, guint16 red, guint16 green, guint16 blue) +{ +#if HAVE_GTK3 + char color_string[16]; + GdkRGBA parsed = { 0 }; + gboolean parsed_ok; + + g_snprintf (color_string, sizeof (color_string), "#%04x%04x%04x", + red, green, blue); + parsed_ok = gdk_rgba_parse (&parsed, color_string); + if (!parsed_ok) + { + parsed.red = red / 65535.0; + parsed.green = green / 65535.0; + parsed.blue = blue / 65535.0; + parsed.alpha = 1.0; + } + *color = parsed; +#else + char color_string[16]; + + g_snprintf (color_string, sizeof (color_string), "#%04x%04x%04x", red, green, blue); + if (!gdk_color_parse (color_string, color)) + { + color->red = red; + color->green = green; + color->blue = blue; + color->pixel = 0; + } +#endif +} + static XTextColor -palette_color_from_gdk (const GdkColor *color) +palette_color_from_gdk (const PaletteColor *color) { XTextColor result; +#if HAVE_GTK3 + result.red = color->red; + result.green = color->green; + result.blue = color->blue; + result.alpha = color->alpha; +#else result.red = color->red / 65535.0; result.green = color->green / 65535.0; result.blue = color->blue / 65535.0; result.alpha = 1.0; +#endif return result; } -GdkColor colors[] = { +PaletteColor colors[] = { /* colors for xtext */ - {0, 0xd3d3, 0xd7d7, 0xcfcf}, /* 0 white */ - {0, 0x2e2e, 0x3434, 0x3636}, /* 1 black */ - {0, 0x3434, 0x6565, 0xa4a4}, /* 2 blue */ - {0, 0x4e4e, 0x9a9a, 0x0606}, /* 3 green */ - {0, 0xcccc, 0x0000, 0x0000}, /* 4 red */ - {0, 0x8f8f, 0x3939, 0x0202}, /* 5 light red */ - {0, 0x5c5c, 0x3535, 0x6666}, /* 6 purple */ - {0, 0xcece, 0x5c5c, 0x0000}, /* 7 orange */ - {0, 0xc4c4, 0xa0a0, 0x0000}, /* 8 yellow */ - {0, 0x7373, 0xd2d2, 0x1616}, /* 9 green */ - {0, 0x1111, 0xa8a8, 0x7979}, /* 10 aqua */ - {0, 0x5858, 0xa1a1, 0x9d9d}, /* 11 light aqua */ - {0, 0x5757, 0x7979, 0x9e9e}, /* 12 blue */ - {0, 0xa0d0, 0x42d4, 0x6562}, /* 13 light purple */ - {0, 0x5555, 0x5757, 0x5353}, /* 14 grey */ - {0, 0x8888, 0x8a8a, 0x8585}, /* 15 light grey */ + PALETTE_COLOR_INIT (0xd3d3, 0xd7d7, 0xcfcf), /* 0 white */ + PALETTE_COLOR_INIT (0x2e2e, 0x3434, 0x3636), /* 1 black */ + PALETTE_COLOR_INIT (0x3434, 0x6565, 0xa4a4), /* 2 blue */ + PALETTE_COLOR_INIT (0x4e4e, 0x9a9a, 0x0606), /* 3 green */ + PALETTE_COLOR_INIT (0xcccc, 0x0000, 0x0000), /* 4 red */ + PALETTE_COLOR_INIT (0x8f8f, 0x3939, 0x0202), /* 5 light red */ + PALETTE_COLOR_INIT (0x5c5c, 0x3535, 0x6666), /* 6 purple */ + PALETTE_COLOR_INIT (0xcece, 0x5c5c, 0x0000), /* 7 orange */ + PALETTE_COLOR_INIT (0xc4c4, 0xa0a0, 0x0000), /* 8 yellow */ + PALETTE_COLOR_INIT (0x7373, 0xd2d2, 0x1616), /* 9 green */ + PALETTE_COLOR_INIT (0x1111, 0xa8a8, 0x7979), /* 10 aqua */ + PALETTE_COLOR_INIT (0x5858, 0xa1a1, 0x9d9d), /* 11 light aqua */ + PALETTE_COLOR_INIT (0x5757, 0x7979, 0x9e9e), /* 12 blue */ + PALETTE_COLOR_INIT (0xa0d0, 0x42d4, 0x6562), /* 13 light purple */ + PALETTE_COLOR_INIT (0x5555, 0x5757, 0x5353), /* 14 grey */ + PALETTE_COLOR_INIT (0x8888, 0x8a8a, 0x8585), /* 15 light grey */ - {0, 0xd3d3, 0xd7d7, 0xcfcf}, /* 16 white */ - {0, 0x2e2e, 0x3434, 0x3636}, /* 17 black */ - {0, 0x3434, 0x6565, 0xa4a4}, /* 18 blue */ - {0, 0x4e4e, 0x9a9a, 0x0606}, /* 19 green */ - {0, 0xcccc, 0x0000, 0x0000}, /* 20 red */ - {0, 0x8f8f, 0x3939, 0x0202}, /* 21 light red */ - {0, 0x5c5c, 0x3535, 0x6666}, /* 22 purple */ - {0, 0xcece, 0x5c5c, 0x0000}, /* 23 orange */ - {0, 0xc4c4, 0xa0a0, 0x0000}, /* 24 yellow */ - {0, 0x7373, 0xd2d2, 0x1616}, /* 25 green */ - {0, 0x1111, 0xa8a8, 0x7979}, /* 26 aqua */ - {0, 0x5858, 0xa1a1, 0x9d9d}, /* 27 light aqua */ - {0, 0x5757, 0x7979, 0x9e9e}, /* 28 blue */ - {0, 0xa0d0, 0x42d4, 0x6562}, /* 29 light purple */ - {0, 0x5555, 0x5757, 0x5353}, /* 30 grey */ - {0, 0x8888, 0x8a8a, 0x8585}, /* 31 light grey */ + PALETTE_COLOR_INIT (0xd3d3, 0xd7d7, 0xcfcf), /* 16 white */ + PALETTE_COLOR_INIT (0x2e2e, 0x3434, 0x3636), /* 17 black */ + PALETTE_COLOR_INIT (0x3434, 0x6565, 0xa4a4), /* 18 blue */ + PALETTE_COLOR_INIT (0x4e4e, 0x9a9a, 0x0606), /* 19 green */ + PALETTE_COLOR_INIT (0xcccc, 0x0000, 0x0000), /* 20 red */ + PALETTE_COLOR_INIT (0x8f8f, 0x3939, 0x0202), /* 21 light red */ + PALETTE_COLOR_INIT (0x5c5c, 0x3535, 0x6666), /* 22 purple */ + PALETTE_COLOR_INIT (0xcece, 0x5c5c, 0x0000), /* 23 orange */ + PALETTE_COLOR_INIT (0xc4c4, 0xa0a0, 0x0000), /* 24 yellow */ + PALETTE_COLOR_INIT (0x7373, 0xd2d2, 0x1616), /* 25 green */ + PALETTE_COLOR_INIT (0x1111, 0xa8a8, 0x7979), /* 26 aqua */ + PALETTE_COLOR_INIT (0x5858, 0xa1a1, 0x9d9d), /* 27 light aqua */ + PALETTE_COLOR_INIT (0x5757, 0x7979, 0x9e9e), /* 28 blue */ + PALETTE_COLOR_INIT (0xa0d0, 0x42d4, 0x6562), /* 29 light purple */ + PALETTE_COLOR_INIT (0x5555, 0x5757, 0x5353), /* 30 grey */ + PALETTE_COLOR_INIT (0x8888, 0x8a8a, 0x8585), /* 31 light grey */ - {0, 0xd3d3, 0xd7d7, 0xcfcf}, /* 32 marktext Fore (white) */ - {0, 0x2020, 0x4a4a, 0x8787}, /* 33 marktext Back (blue) */ - {0, 0x2512, 0x29e8, 0x2b85}, /* 34 foreground (black) */ - {0, 0xfae0, 0xfae0, 0xf8c4}, /* 35 background (white) */ - {0, 0x8f8f, 0x3939, 0x0202}, /* 36 marker line (red) */ + PALETTE_COLOR_INIT (0xd3d3, 0xd7d7, 0xcfcf), /* 32 marktext Fore (white) */ + PALETTE_COLOR_INIT (0x2020, 0x4a4a, 0x8787), /* 33 marktext Back (blue) */ + PALETTE_COLOR_INIT (0x2512, 0x29e8, 0x2b85), /* 34 foreground (black) */ + PALETTE_COLOR_INIT (0xfae0, 0xfae0, 0xf8c4), /* 35 background (white) */ + PALETTE_COLOR_INIT (0x8f8f, 0x3939, 0x0202), /* 36 marker line (red) */ /* colors for GUI */ - {0, 0x3434, 0x6565, 0xa4a4}, /* 37 tab New Data (dark red) */ - {0, 0x4e4e, 0x9a9a, 0x0606}, /* 38 tab Nick Mentioned (blue) */ - {0, 0xcece, 0x5c5c, 0x0000}, /* 39 tab New Message (red) */ - {0, 0x8888, 0x8a8a, 0x8585}, /* 40 away user (grey) */ - {0, 0xa4a4, 0x0000, 0x0000}, /* 41 spell checker color (red) */ + PALETTE_COLOR_INIT (0x3434, 0x6565, 0xa4a4), /* 37 tab New Data (dark red) */ + PALETTE_COLOR_INIT (0x4e4e, 0x9a9a, 0x0606), /* 38 tab Nick Mentioned (blue) */ + PALETTE_COLOR_INIT (0xcece, 0x5c5c, 0x0000), /* 39 tab New Message (red) */ + PALETTE_COLOR_INIT (0x8888, 0x8a8a, 0x8585), /* 40 away user (grey) */ + PALETTE_COLOR_INIT (0xa4a4, 0x0000, 0x0000), /* 41 spell checker color (red) */ }; /* User palette snapshot (what we write to colors.conf) */ -static GdkColor user_colors[MAX_COL + 1]; +static PaletteColor user_colors[MAX_COL + 1]; static gboolean user_colors_valid = FALSE; /* Dark palette snapshot (saved separately so dark mode can have its own custom palette). */ -static GdkColor dark_user_colors[MAX_COL + 1]; +static PaletteColor dark_user_colors[MAX_COL + 1]; static gboolean dark_user_colors_valid = FALSE; /* ZoiteChat's curated dark palette (applies when prefs.hex_gui_dark_mode is enabled). */ -static const GdkColor dark_colors[MAX_COL + 1] = { +static const PaletteColor dark_colors[MAX_COL + 1] = { /* mIRC colors 0-15 */ - {0, 0xe5e5, 0xe5e5, 0xe5e5}, /* 0 white */ - {0, 0x3c3c, 0x3c3c, 0x3c3c}, /* 1 black (dark gray for contrast) */ - {0, 0x5656, 0x9c9c, 0xd6d6}, /* 2 blue */ - {0, 0x0d0d, 0xbcbc, 0x7979}, /* 3 green */ - {0, 0xf4f4, 0x4747, 0x4747}, /* 4 red */ - {0, 0xcece, 0x9191, 0x7878}, /* 5 light red / brown */ - {0, 0xc5c5, 0x8686, 0xc0c0}, /* 6 purple */ - {0, 0xd7d7, 0xbaba, 0x7d7d}, /* 7 orange */ - {0, 0xdcdc, 0xdcdc, 0xaaaa}, /* 8 yellow */ - {0, 0xb5b5, 0xcece, 0xa8a8}, /* 9 light green */ - {0, 0x4e4e, 0xc9c9, 0xb0b0}, /* 10 aqua */ - {0, 0x9c9c, 0xdcdc, 0xfefe}, /* 11 light aqua */ - {0, 0x3737, 0x9494, 0xffff}, /* 12 light blue */ - {0, 0xd6d6, 0x7070, 0xd6d6}, /* 13 pink */ - {0, 0x8080, 0x8080, 0x8080}, /* 14 gray */ - {0, 0xc0c0, 0xc0c0, 0xc0c0}, /* 15 light gray */ + PALETTE_COLOR_INIT (0xe5e5, 0xe5e5, 0xe5e5), /* 0 white */ + PALETTE_COLOR_INIT (0x3c3c, 0x3c3c, 0x3c3c), /* 1 black (dark gray for contrast) */ + PALETTE_COLOR_INIT (0x5656, 0x9c9c, 0xd6d6), /* 2 blue */ + PALETTE_COLOR_INIT (0x0d0d, 0xbcbc, 0x7979), /* 3 green */ + PALETTE_COLOR_INIT (0xf4f4, 0x4747, 0x4747), /* 4 red */ + PALETTE_COLOR_INIT (0xcece, 0x9191, 0x7878), /* 5 light red / brown */ + PALETTE_COLOR_INIT (0xc5c5, 0x8686, 0xc0c0), /* 6 purple */ + PALETTE_COLOR_INIT (0xd7d7, 0xbaba, 0x7d7d), /* 7 orange */ + PALETTE_COLOR_INIT (0xdcdc, 0xdcdc, 0xaaaa), /* 8 yellow */ + PALETTE_COLOR_INIT (0xb5b5, 0xcece, 0xa8a8), /* 9 light green */ + PALETTE_COLOR_INIT (0x4e4e, 0xc9c9, 0xb0b0), /* 10 aqua */ + PALETTE_COLOR_INIT (0x9c9c, 0xdcdc, 0xfefe), /* 11 light aqua */ + PALETTE_COLOR_INIT (0x3737, 0x9494, 0xffff), /* 12 light blue */ + PALETTE_COLOR_INIT (0xd6d6, 0x7070, 0xd6d6), /* 13 pink */ + PALETTE_COLOR_INIT (0x8080, 0x8080, 0x8080), /* 14 gray */ + PALETTE_COLOR_INIT (0xc0c0, 0xc0c0, 0xc0c0), /* 15 light gray */ /* mIRC colors 16-31 (repeat) */ - {0, 0xe5e5, 0xe5e5, 0xe5e5}, {0, 0x3c3c, 0x3c3c, 0x3c3c}, - {0, 0x5656, 0x9c9c, 0xd6d6}, {0, 0x0d0d, 0xbcbc, 0x7979}, - {0, 0xf4f4, 0x4747, 0x4747}, {0, 0xcece, 0x9191, 0x7878}, - {0, 0xc5c5, 0x8686, 0xc0c0}, {0, 0xd7d7, 0xbaba, 0x7d7d}, - {0, 0xdcdc, 0xdcdc, 0xaaaa}, {0, 0xb5b5, 0xcece, 0xa8a8}, - {0, 0x4e4e, 0xc9c9, 0xb0b0}, {0, 0x9c9c, 0xdcdc, 0xfefe}, - {0, 0x3737, 0x9494, 0xffff}, {0, 0xd6d6, 0x7070, 0xd6d6}, - {0, 0x8080, 0x8080, 0x8080}, {0, 0xc0c0, 0xc0c0, 0xc0c0}, + PALETTE_COLOR_INIT (0xe5e5, 0xe5e5, 0xe5e5), PALETTE_COLOR_INIT (0x3c3c, 0x3c3c, 0x3c3c), + PALETTE_COLOR_INIT (0x5656, 0x9c9c, 0xd6d6), PALETTE_COLOR_INIT (0x0d0d, 0xbcbc, 0x7979), + PALETTE_COLOR_INIT (0xf4f4, 0x4747, 0x4747), PALETTE_COLOR_INIT (0xcece, 0x9191, 0x7878), + PALETTE_COLOR_INIT (0xc5c5, 0x8686, 0xc0c0), PALETTE_COLOR_INIT (0xd7d7, 0xbaba, 0x7d7d), + PALETTE_COLOR_INIT (0xdcdc, 0xdcdc, 0xaaaa), PALETTE_COLOR_INIT (0xb5b5, 0xcece, 0xa8a8), + PALETTE_COLOR_INIT (0x4e4e, 0xc9c9, 0xb0b0), PALETTE_COLOR_INIT (0x9c9c, 0xdcdc, 0xfefe), + PALETTE_COLOR_INIT (0x3737, 0x9494, 0xffff), PALETTE_COLOR_INIT (0xd6d6, 0x7070, 0xd6d6), + PALETTE_COLOR_INIT (0x8080, 0x8080, 0x8080), PALETTE_COLOR_INIT (0xc0c0, 0xc0c0, 0xc0c0), /* selection colors */ - {0, 0xffff, 0xffff, 0xffff}, /* 32 COL_MARK_FG */ - {0, 0x2626, 0x4f4f, 0x7878}, /* 33 COL_MARK_BG */ + PALETTE_COLOR_INIT (0xffff, 0xffff, 0xffff), /* 32 COL_MARK_FG */ + PALETTE_COLOR_INIT (0x2626, 0x4f4f, 0x7878), /* 33 COL_MARK_BG */ /* foreground/background */ - {0, 0xd4d4, 0xd4d4, 0xd4d4}, /* 34 COL_FG */ - {0, 0x1e1e, 0x1e1e, 0x1e1e}, /* 35 COL_BG */ + PALETTE_COLOR_INIT (0xd4d4, 0xd4d4, 0xd4d4), /* 34 COL_FG */ + PALETTE_COLOR_INIT (0x1e1e, 0x1e1e, 0x1e1e), /* 35 COL_BG */ /* interface colors */ - {0, 0x4040, 0x4040, 0x4040}, /* 36 COL_MARKER (marker line) */ - {0, 0x3737, 0x9494, 0xffff}, /* 37 COL_NEW_DATA (tab: new data) */ - {0, 0xd7d7, 0xbaba, 0x7d7d}, /* 38 COL_HILIGHT (tab: nick mentioned) */ - {0, 0xf4f4, 0x4747, 0x4747}, /* 39 COL_NEW_MSG (tab: new message) */ - {0, 0x8080, 0x8080, 0x8080}, /* 40 COL_AWAY (tab: away) */ - {0, 0xf4f4, 0x4747, 0x4747}, /* 41 COL_SPELL (spellcheck underline) */ + PALETTE_COLOR_INIT (0x4040, 0x4040, 0x4040), /* 36 COL_MARKER (marker line) */ + PALETTE_COLOR_INIT (0x3737, 0x9494, 0xffff), /* 37 COL_NEW_DATA (tab: new data) */ + PALETTE_COLOR_INIT (0xd7d7, 0xbaba, 0x7d7d), /* 38 COL_HILIGHT (tab: nick mentioned) */ + PALETTE_COLOR_INIT (0xf4f4, 0x4747, 0x4747), /* 39 COL_NEW_MSG (tab: new message) */ + PALETTE_COLOR_INIT (0x8080, 0x8080, 0x8080), /* 40 COL_AWAY (tab: away) */ + PALETTE_COLOR_INIT (0xf4f4, 0x4747, 0x4747), /* 41 COL_SPELL (spellcheck underline) */ }; void @@ -168,7 +214,7 @@ palette_get_xtext_colors (XTextColor *palette, size_t palette_len) } void -palette_user_set_color (int idx, const GdkColor *col) +palette_user_set_color (int idx, const PaletteColor *col) { if (!col) return; @@ -181,14 +227,18 @@ palette_user_set_color (int idx, const GdkColor *col) user_colors_valid = TRUE; } +#if HAVE_GTK3 + user_colors[idx] = *col; +#else user_colors[idx].red = col->red; user_colors[idx].green = col->green; user_colors[idx].blue = col->blue; user_colors[idx].pixel = 0; +#endif } void -palette_dark_set_color (int idx, const GdkColor *col) +palette_dark_set_color (int idx, const PaletteColor *col) { if (!col) return; @@ -202,26 +252,20 @@ palette_dark_set_color (int idx, const GdkColor *col) dark_user_colors_valid = TRUE; } +#if HAVE_GTK3 + dark_user_colors[idx] = *col; +#else dark_user_colors[idx].red = col->red; dark_user_colors[idx].green = col->green; dark_user_colors[idx].blue = col->blue; dark_user_colors[idx].pixel = 0; +#endif } void palette_alloc (GtkWidget * widget) { - int i; - static int done_alloc = FALSE; - GdkColormap *cmap; - - if (!done_alloc) /* don't do it again */ - { - done_alloc = TRUE; - cmap = gtk_widget_get_colormap (widget); - for (i = MAX_COL; i >= 0; i--) - gdk_colormap_alloc_color (cmap, &colors[i], FALSE, TRUE); - } + (void) widget; } void @@ -247,9 +291,7 @@ palette_load (void) g_snprintf (prefname, sizeof prefname, "color_%d", i); if (cfg_get_color (cfg, prefname, &red, &green, &blue)) { - colors[i].red = red; - colors[i].green = green; - colors[i].blue = blue; + palette_color_set_rgb16 (&colors[i], red, green, blue); } } @@ -259,9 +301,7 @@ palette_load (void) g_snprintf (prefname, sizeof prefname, "color_%d", i); if (cfg_get_color (cfg, prefname, &red, &green, &blue)) { - colors[j].red = red; - colors[j].green = green; - colors[j].blue = blue; + palette_color_set_rgb16 (&colors[j], red, green, blue); } } @@ -273,9 +313,7 @@ palette_load (void) g_snprintf (prefname, sizeof prefname, "dark_color_%d", i); if (cfg_get_color (cfg, prefname, &red, &green, &blue)) { - dark_user_colors[i].red = red; - dark_user_colors[i].green = green; - dark_user_colors[i].blue = blue; + palette_color_set_rgb16 (&dark_user_colors[i], red, green, blue); dark_found = TRUE; } } @@ -285,9 +323,7 @@ palette_load (void) g_snprintf (prefname, sizeof prefname, "dark_color_%d", i); if (cfg_get_color (cfg, prefname, &red, &green, &blue)) { - dark_user_colors[j].red = red; - dark_user_colors[j].green = green; - dark_user_colors[j].blue = blue; + palette_color_set_rgb16 (&dark_user_colors[j], red, green, blue); dark_found = TRUE; } } @@ -309,8 +345,8 @@ palette_save (void) { int i, j, fh; char prefname[256]; - const GdkColor *lightpal = colors; - const GdkColor *darkpal = NULL; + const PaletteColor *lightpal = colors; + const PaletteColor *darkpal = NULL; gboolean dark_mode_active = fe_dark_mode_is_enabled (); /* If we're currently in dark mode, keep colors.conf's legacy keys as the user's light palette. */ @@ -343,13 +379,25 @@ palette_save (void) for (i = 0; i < 32; i++) { g_snprintf (prefname, sizeof prefname, "color_%d", i); - cfg_put_color (fh, lightpal[i].red, lightpal[i].green, lightpal[i].blue, prefname); + guint16 red; + guint16 green; + guint16 blue; + + palette_color_get_rgb16 (&lightpal[i], &red, &green, &blue); + cfg_put_color (fh, red, green, blue, prefname); } for (i = 256, j = 32; j < MAX_COL + 1; i++, j++) { g_snprintf (prefname, sizeof prefname, "color_%d", i); - cfg_put_color (fh, lightpal[j].red, lightpal[j].green, lightpal[j].blue, prefname); + { + guint16 red; + guint16 green; + guint16 blue; + + palette_color_get_rgb16 (&lightpal[j], &red, &green, &blue); + cfg_put_color (fh, red, green, blue, prefname); + } } /* Dark palette (new keys) */ @@ -358,13 +406,25 @@ palette_save (void) for (i = 0; i < 32; i++) { g_snprintf (prefname, sizeof prefname, "dark_color_%d", i); - cfg_put_color (fh, darkpal[i].red, darkpal[i].green, darkpal[i].blue, prefname); + guint16 red; + guint16 green; + guint16 blue; + + palette_color_get_rgb16 (&darkpal[i], &red, &green, &blue); + cfg_put_color (fh, red, green, blue, prefname); } for (i = 256, j = 32; j < MAX_COL + 1; i++, j++) { g_snprintf (prefname, sizeof prefname, "dark_color_%d", i); - cfg_put_color (fh, darkpal[j].red, darkpal[j].green, darkpal[j].blue, prefname); + { + guint16 red; + guint16 green; + guint16 blue; + + palette_color_get_rgb16 (&darkpal[j], &red, &green, &blue); + cfg_put_color (fh, red, green, blue, prefname); + } } } @@ -374,16 +434,25 @@ palette_save (void) static gboolean -palette_color_eq (const GdkColor *a, const GdkColor *b) +palette_color_eq (const PaletteColor *a, const PaletteColor *b) { - return a->red == b->red && a->green == b->green && a->blue == b->blue; + guint16 red_a; + guint16 green_a; + guint16 blue_a; + guint16 red_b; + guint16 green_b; + guint16 blue_b; + + palette_color_get_rgb16 (a, &red_a, &green_a, &blue_a); + palette_color_get_rgb16 (b, &red_b, &green_b, &blue_b); + + return red_a == red_b && green_a == green_b && blue_a == blue_b; } gboolean palette_apply_dark_mode (gboolean enable) { - GdkColor old_colors[MAX_COL + 1]; - GdkColormap *cmap; + PaletteColor old_colors[MAX_COL + 1]; int i; gboolean changed = FALSE; @@ -406,16 +475,12 @@ palette_apply_dark_mode (gboolean enable) else memcpy (colors, user_colors, sizeof (colors)); - /* Allocate the new colors for GTK's colormap. */ - cmap = gdk_colormap_get_system (); - for (i = 0; i <= MAX_COL; i++) - gdk_colormap_alloc_color (cmap, &colors[i], FALSE, TRUE); + /* Track whether any palette entries changed. */ + (void) i; for (i = 0; i <= MAX_COL; i++) { - if (old_colors[i].red != colors[i].red || - old_colors[i].green != colors[i].green || - old_colors[i].blue != colors[i].blue) + if (!palette_color_eq (&old_colors[i], &colors[i])) { changed = TRUE; break; diff --git a/src/fe-gtk/palette.h b/src/fe-gtk/palette.h index 285360ec..65c0633f 100644 --- a/src/fe-gtk/palette.h +++ b/src/fe-gtk/palette.h @@ -24,7 +24,31 @@ #include "xtext-color.h" -extern GdkColor colors[]; +#if HAVE_GTK3 +typedef GdkRGBA PaletteColor; +#define PALETTE_GDK_TYPE GDK_TYPE_RGBA +#define PALETTE_FOREGROUND_PROPERTY "foreground-rgba" +#else +typedef GdkColor PaletteColor; +#define PALETTE_GDK_TYPE GDK_TYPE_COLOR +#define PALETTE_FOREGROUND_PROPERTY "foreground-gdk" +#endif + +extern PaletteColor colors[]; + +static inline void +palette_color_get_rgb16 (const PaletteColor *color, guint16 *red, guint16 *green, guint16 *blue) +{ +#if HAVE_GTK3 + *red = (guint16) CLAMP (color->red * 65535.0 + 0.5, 0.0, 65535.0); + *green = (guint16) CLAMP (color->green * 65535.0 + 0.5, 0.0, 65535.0); + *blue = (guint16) CLAMP (color->blue * 65535.0 + 0.5, 0.0, 65535.0); +#else + *red = color->red; + *green = color->green; + *blue = color->blue; +#endif +} #define COL_MARK_FG 32 #define COL_MARK_BG 33 @@ -43,8 +67,8 @@ void palette_load (void); void palette_save (void); /* Keep a copy of the user's palette so dark mode can be toggled without losing it. */ -void palette_user_set_color (int idx, const GdkColor *col); -void palette_dark_set_color (int idx, const GdkColor *col); +void palette_user_set_color (int idx, const PaletteColor *col); +void palette_dark_set_color (int idx, const PaletteColor *col); /* * Apply ZoiteChat's built-in "dark mode" palette. diff --git a/src/fe-gtk/plugin-tray.c b/src/fe-gtk/plugin-tray.c index 6acb8282..9aa7104e 100644 --- a/src/fe-gtk/plugin-tray.c +++ b/src/fe-gtk/plugin-tray.c @@ -31,18 +31,39 @@ #include "menu.h" #include "gtkutil.h" +#if HAVE_GTK3 +#include +#if defined(GTK_DISABLE_DEPRECATED) +typedef struct _GtkStatusIcon GtkStatusIcon; +#endif +#ifndef WIN32 +#if defined(HAVE_AYATANA_APPINDICATOR) +#include +#elif defined(HAVE_APPINDICATOR) +#include +#endif +#endif +#define ICON_TRAY_PREFERENCES "preferences-system" +#define ICON_TRAY_QUIT "application-exit" +#else +#define ICON_TRAY_PREFERENCES GTK_STOCK_PREFERENCES +#define ICON_TRAY_QUIT GTK_STOCK_QUIT +#endif + #ifndef WIN32 #include #endif typedef enum /* current icon status */ { - TS_NONE, - TS_MESSAGE, - TS_HIGHLIGHT, - TS_FILEOFFER, - TS_CUSTOM /* plugin */ -} TrayStatus; + TRAY_ICON_NONE, + TRAY_ICON_NORMAL, + TRAY_ICON_MESSAGE, + TRAY_ICON_HIGHLIGHT, + TRAY_ICON_FILEOFFER, + TRAY_ICON_CUSTOM1, + TRAY_ICON_CUSTOM2 +} TrayIconState; typedef enum { @@ -51,7 +72,37 @@ typedef enum WS_HIDDEN } WinStatus; +#if HAVE_GTK3 && !defined(WIN32) && (defined(HAVE_AYATANA_APPINDICATOR) || defined(HAVE_APPINDICATOR)) +#define HAVE_APPINDICATOR_BACKEND 1 +#else +#define HAVE_APPINDICATOR_BACKEND 0 +#endif + +#if HAVE_APPINDICATOR_BACKEND +/* GTK3: use AppIndicator/StatusNotifier item for tray integration. */ +typedef GIcon *TrayIcon; +typedef GIcon *TrayCustomIcon; +#define tray_icon_free(i) g_object_unref(i) + +#define ICON_NORMAL_NAME "net.zoite.Zoitechat" +#define ICON_MSG_NAME "mail-unread" +#define ICON_HILIGHT_NAME "dialog-warning" +#define ICON_FILE_NAME "folder-download" + +static TrayIcon tray_icon_normal; +static TrayIcon tray_icon_msg; +static TrayIcon tray_icon_hilight; +static TrayIcon tray_icon_file; + +#define ICON_NORMAL tray_icon_normal +#define ICON_MSG tray_icon_msg +#define ICON_HILIGHT tray_icon_hilight +#define ICON_FILE tray_icon_file +#endif + +#if !HAVE_APPINDICATOR_BACKEND typedef GdkPixbuf* TrayIcon; +typedef GdkPixbuf* TrayCustomIcon; #define tray_icon_from_file(f) gdk_pixbuf_new_from_file(f,NULL) #define tray_icon_free(i) g_object_unref(i) @@ -59,19 +110,59 @@ typedef GdkPixbuf* TrayIcon; #define ICON_MSG pix_tray_message #define ICON_HILIGHT pix_tray_highlight #define ICON_FILE pix_tray_fileoffer +#endif +#if HAVE_GTK3 && defined(GTK_DISABLE_DEPRECATED) && !HAVE_APPINDICATOR_BACKEND +GtkStatusIcon *gtk_status_icon_new_from_pixbuf (GdkPixbuf *pixbuf); +void gtk_status_icon_set_from_pixbuf (GtkStatusIcon *status_icon, GdkPixbuf *pixbuf); +void gtk_status_icon_set_tooltip_text (GtkStatusIcon *status_icon, const gchar *text); +gboolean gtk_status_icon_is_embedded (GtkStatusIcon *status_icon); +#endif #define TIMEOUT 500 -static GtkStatusIcon *sticon; +void tray_apply_setup (void); +static gboolean tray_menu_try_restore (void); +static void tray_cleanup (void); +static void tray_init (void); +static void tray_set_icon_state (TrayIcon icon, TrayIconState state); +static void tray_menu_restore_cb (GtkWidget *item, gpointer userdata); +static void tray_menu_notify_cb (GObject *tray, GParamSpec *pspec, gpointer user_data); +#if HAVE_APPINDICATOR_BACKEND +static void tray_menu_show_cb (GtkWidget *menu, gpointer userdata); +#endif +#if !HAVE_APPINDICATOR_BACKEND +static void tray_menu_cb (GtkWidget *widget, guint button, guint time, gpointer userdata); +#endif + +typedef struct +{ + gboolean (*init)(void); + void (*set_icon)(TrayIcon icon); + void (*set_tooltip)(const char *text); + gboolean (*is_embedded)(void); + void (*cleanup)(void); +} TrayBackendOps; + +#if HAVE_APPINDICATOR_BACKEND +static AppIndicator *tray_indicator; +static GtkWidget *tray_menu; +#endif +#if !HAVE_APPINDICATOR_BACKEND +static GtkStatusIcon *tray_status_icon; +#endif +static gboolean tray_backend_active = FALSE; + static gint flash_tag; -static TrayStatus tray_status; -#ifdef WIN32 +static TrayIconState tray_icon_state; +static TrayIcon tray_flash_icon; +static TrayIconState tray_flash_state; +#if defined(WIN32) static guint tray_menu_timer; static gint64 tray_menu_inactivetime; #endif static zoitechat_plugin *ph; -static TrayIcon custom_icon1; -static TrayIcon custom_icon2; +static TrayCustomIcon custom_icon1; +static TrayCustomIcon custom_icon2; static int tray_priv_count = 0; static int tray_pub_count = 0; @@ -79,12 +170,401 @@ static int tray_hilight_count = 0; static int tray_file_count = 0; static int tray_restore_timer = 0; +#if HAVE_APPINDICATOR_BACKEND +static TrayCustomIcon +tray_icon_from_file (const char *filename) +{ + GFile *file; + TrayCustomIcon icon; -void tray_apply_setup (void); -static gboolean tray_menu_try_restore (void); -static void tray_cleanup (void); -static void tray_init (void); + if (!filename) + return NULL; + file = g_file_new_for_path (filename); + icon = g_file_icon_new (file); + g_object_unref (file); + + return icon; +} + +static char * +tray_gtk3_cache_pixbuf_icon (const char *basename, GdkPixbuf *pixbuf) +{ + char *cache_dir; + char *filename; + char *path; + + if (!pixbuf || !basename) + return NULL; + + cache_dir = g_build_filename (g_get_user_cache_dir (), "zoitechat", "tray-icons", NULL); + if (g_mkdir_with_parents (cache_dir, 0700) != 0) + { + g_free (cache_dir); + return NULL; + } + + filename = g_strdup_printf ("%s.png", basename); + path = g_build_filename (cache_dir, filename, NULL); + g_free (filename); + g_free (cache_dir); + + if (!g_file_test (path, G_FILE_TEST_EXISTS)) + gdk_pixbuf_save (pixbuf, path, "png", NULL, NULL); + + return path; +} + +static char * +tray_gtk3_fallback_icon_path_for_name (const char *name) +{ + if (g_strcmp0 (name, ICON_NORMAL_NAME) == 0) + return tray_gtk3_cache_pixbuf_icon ("tray_normal", pix_tray_normal); + if (g_strcmp0 (name, ICON_MSG_NAME) == 0) + return tray_gtk3_cache_pixbuf_icon ("tray_message", pix_tray_message); + if (g_strcmp0 (name, ICON_HILIGHT_NAME) == 0) + return tray_gtk3_cache_pixbuf_icon ("tray_highlight", pix_tray_highlight); + if (g_strcmp0 (name, ICON_FILE_NAME) == 0) + return tray_gtk3_cache_pixbuf_icon ("tray_fileoffer", pix_tray_fileoffer); + + return NULL; +} + +static void +tray_gtk3_icons_init (void) +{ + if (!tray_icon_normal) + tray_icon_normal = g_themed_icon_new (ICON_NORMAL_NAME); + if (!tray_icon_msg) + tray_icon_msg = g_themed_icon_new (ICON_MSG_NAME); + if (!tray_icon_hilight) + tray_icon_hilight = g_themed_icon_new (ICON_HILIGHT_NAME); + if (!tray_icon_file) + tray_icon_file = g_themed_icon_new (ICON_FILE_NAME); +} + +static void +tray_gtk3_icons_cleanup (void) +{ + g_clear_object (&tray_icon_normal); + g_clear_object (&tray_icon_msg); + g_clear_object (&tray_icon_hilight); + g_clear_object (&tray_icon_file); +} + +static GtkIconTheme *tray_gtk3_icon_theme = NULL; +static gulong tray_gtk3_icon_theme_changed_handler = 0; + +static void +tray_gtk3_reapply_icon_state (void) +{ + switch (tray_icon_state) + { + case TRAY_ICON_NORMAL: + tray_set_icon_state (ICON_NORMAL, TRAY_ICON_NORMAL); + break; + case TRAY_ICON_MESSAGE: + tray_set_icon_state (ICON_MSG, TRAY_ICON_MESSAGE); + break; + case TRAY_ICON_HIGHLIGHT: + tray_set_icon_state (ICON_HILIGHT, TRAY_ICON_HIGHLIGHT); + break; + case TRAY_ICON_FILEOFFER: + tray_set_icon_state (ICON_FILE, TRAY_ICON_FILEOFFER); + break; + case TRAY_ICON_CUSTOM1: + tray_set_icon_state (custom_icon1, TRAY_ICON_CUSTOM1); + break; + case TRAY_ICON_CUSTOM2: + tray_set_icon_state (custom_icon2, TRAY_ICON_CUSTOM2); + break; + case TRAY_ICON_NONE: + default: + break; + } +} + +static void +tray_gtk3_theme_changed_cb (GtkIconTheme *theme, gpointer user_data) +{ + (void)theme; + (void)user_data; + + if (!tray_backend_active) + return; + + tray_gtk3_icons_cleanup (); + tray_gtk3_icons_init (); + tray_gtk3_reapply_icon_state (); +} + +static const char * +tray_gtk3_icon_to_name (TrayIcon icon, char **allocated) +{ + const char * const *names; + GtkIconTheme *theme; + GFile *file; + + if (!icon) + return NULL; + + if (G_IS_THEMED_ICON (icon)) + { + names = g_themed_icon_get_names (G_THEMED_ICON (icon)); + if (names && names[0]) + { + theme = gtk_icon_theme_get_default (); + if (theme && gtk_icon_theme_has_icon (theme, names[0])) + return names[0]; + + *allocated = tray_gtk3_fallback_icon_path_for_name (names[0]); + if (*allocated) + return *allocated; + } + } + + if (G_IS_FILE_ICON (icon)) + { + file = g_file_icon_get_file (G_FILE_ICON (icon)); + if (file) + { + *allocated = g_file_get_path (file); + if (*allocated) + return *allocated; + } + } + + *allocated = g_icon_to_string (icon); + return *allocated; +} + +static void +tray_app_indicator_set_icon (TrayIcon icon) +{ + char *icon_name_alloc = NULL; + const char *icon_name; + + if (!tray_indicator) + return; + + icon_name = tray_gtk3_icon_to_name (icon, &icon_name_alloc); + if (!icon_name) + return; + + app_indicator_set_icon_full (tray_indicator, icon_name, _(DISPLAY_NAME)); + app_indicator_set_status (tray_indicator, APP_INDICATOR_STATUS_ACTIVE); + + g_free (icon_name_alloc); +} + +static void +tray_app_indicator_set_tooltip (const char *text) +{ + if (!tray_indicator) + return; + + app_indicator_set_title (tray_indicator, text ? text : ""); +} + +static gboolean +tray_app_indicator_is_embedded (void) +{ + gboolean connected = TRUE; + GObjectClass *klass; + + if (!tray_indicator) + return FALSE; + + klass = G_OBJECT_GET_CLASS (tray_indicator); + if (klass && g_object_class_find_property (klass, "connected")) + { + g_object_get (tray_indicator, "connected", &connected, NULL); + } + + return connected; +} + +static void +tray_app_indicator_cleanup (void) +{ + if (tray_indicator) + { + g_object_unref (tray_indicator); + tray_indicator = NULL; + } + + if (tray_menu) + { + gtk_widget_destroy (tray_menu); + tray_menu = NULL; + } +} + +static gboolean +tray_app_indicator_init (void) +{ + GObjectClass *klass; + + tray_indicator = app_indicator_new ("zoitechat", ICON_NORMAL_NAME, + APP_INDICATOR_CATEGORY_COMMUNICATIONS); + if (!tray_indicator) + return FALSE; + + tray_menu = gtk_menu_new (); + g_signal_connect (G_OBJECT (tray_menu), "show", + G_CALLBACK (tray_menu_show_cb), NULL); + app_indicator_set_menu (tray_indicator, GTK_MENU (tray_menu)); + app_indicator_set_status (tray_indicator, APP_INDICATOR_STATUS_ACTIVE); + + klass = G_OBJECT_GET_CLASS (tray_indicator); + if (klass && g_object_class_find_property (klass, "connected")) + { + g_signal_connect (G_OBJECT (tray_indicator), "notify::connected", + G_CALLBACK (tray_menu_notify_cb), NULL); + } + + return TRUE; +} + +static const TrayBackendOps tray_backend_ops = { + tray_app_indicator_init, + tray_app_indicator_set_icon, + tray_app_indicator_set_tooltip, + tray_app_indicator_is_embedded, + tray_app_indicator_cleanup +}; +#endif + +#if !HAVE_APPINDICATOR_BACKEND +static void +tray_status_icon_set_icon (TrayIcon icon) +{ + if (!tray_status_icon) + return; + + gtk_status_icon_set_from_pixbuf (tray_status_icon, icon); +} + +static void +tray_status_icon_set_tooltip (const char *text) +{ + if (!tray_status_icon) + return; + + gtk_status_icon_set_tooltip_text (tray_status_icon, text); +} + +static gboolean +tray_status_icon_is_embedded (void) +{ + if (!tray_status_icon) + return FALSE; + + return gtk_status_icon_is_embedded (tray_status_icon); +} + +static void +tray_status_icon_cleanup (void) +{ + if (tray_status_icon) + { + g_object_unref (tray_status_icon); + tray_status_icon = NULL; + } +} + +static gboolean +tray_status_icon_init (void) +{ + tray_status_icon = gtk_status_icon_new_from_pixbuf (ICON_NORMAL); + if (!tray_status_icon) + return FALSE; + + g_signal_connect (G_OBJECT (tray_status_icon), "popup-menu", + G_CALLBACK (tray_menu_cb), tray_status_icon); + + g_signal_connect (G_OBJECT (tray_status_icon), "activate", + G_CALLBACK (tray_menu_restore_cb), NULL); + + g_signal_connect (G_OBJECT (tray_status_icon), "notify::embedded", + G_CALLBACK (tray_menu_notify_cb), NULL); + + return TRUE; +} + +static const TrayBackendOps tray_backend_ops = { + tray_status_icon_init, + tray_status_icon_set_icon, + tray_status_icon_set_tooltip, + tray_status_icon_is_embedded, + tray_status_icon_cleanup +}; +#endif + +static gboolean +tray_backend_init (void) +{ + if (!tray_backend_ops.init) + return FALSE; + +#if HAVE_APPINDICATOR_BACKEND + tray_gtk3_icons_init (); + if (!tray_gtk3_icon_theme) + tray_gtk3_icon_theme = gtk_icon_theme_get_default (); + if (tray_gtk3_icon_theme && tray_gtk3_icon_theme_changed_handler == 0) + { + tray_gtk3_icon_theme_changed_handler = g_signal_connect ( + tray_gtk3_icon_theme, + "changed", + G_CALLBACK (tray_gtk3_theme_changed_cb), + NULL); + } +#endif + tray_backend_active = tray_backend_ops.init (); + return tray_backend_active; +} + +static void +tray_backend_set_icon (TrayIcon icon) +{ + if (tray_backend_active && tray_backend_ops.set_icon) + tray_backend_ops.set_icon (icon); +} + +static void +tray_backend_set_tooltip (const char *text) +{ + if (tray_backend_active && tray_backend_ops.set_tooltip) + tray_backend_ops.set_tooltip (text); +} + +static gboolean +tray_backend_is_embedded (void) +{ + if (!tray_backend_active || !tray_backend_ops.is_embedded) + return FALSE; + + return tray_backend_ops.is_embedded (); +} + +static void +tray_backend_cleanup (void) +{ + if (tray_backend_ops.cleanup) + tray_backend_ops.cleanup (); + +#if HAVE_APPINDICATOR_BACKEND + if (tray_gtk3_icon_theme && tray_gtk3_icon_theme_changed_handler) + { + g_signal_handler_disconnect (tray_gtk3_icon_theme, + tray_gtk3_icon_theme_changed_handler); + tray_gtk3_icon_theme_changed_handler = 0; + } + tray_gtk3_icon_theme = NULL; + tray_gtk3_icons_cleanup (); +#endif + tray_backend_active = FALSE; +} static WinStatus tray_get_window_status (void) @@ -136,11 +616,27 @@ tray_count_networks (void) return cons; } +static void +tray_set_icon_state (TrayIcon icon, TrayIconState state) +{ + tray_backend_set_icon (icon); + tray_icon_state = state; +} + +static void +tray_set_custom_icon_state (TrayCustomIcon icon, TrayIconState state) +{ + tray_backend_set_icon (icon); + tray_icon_state = state; +} + void fe_tray_set_tooltip (const char *text) { - if (sticon) - gtk_status_icon_set_tooltip_text (sticon, text); + if (!tray_backend_active) + return; + + tray_backend_set_tooltip (text); } static void @@ -168,9 +664,9 @@ tray_stop_flash (void) flash_tag = 0; } - if (sticon) + if (tray_backend_active) { - gtk_status_icon_set_from_pixbuf (sticon, ICON_NORMAL); + tray_set_icon_state (ICON_NORMAL, TRAY_ICON_NORMAL); nets = tray_count_networks (); chans = tray_count_channels (); if (nets) @@ -192,7 +688,8 @@ tray_stop_flash (void) custom_icon2 = NULL; } - tray_status = TS_NONE; + tray_flash_icon = NULL; + tray_flash_state = TRAY_ICON_NONE; } static void @@ -205,40 +702,42 @@ tray_reset_counts (void) } static int -tray_timeout_cb (TrayIcon icon) +tray_timeout_cb (gpointer userdata) { + (void)userdata; + if (custom_icon1) { - if (gtk_status_icon_get_pixbuf (sticon) == custom_icon1) + if (tray_icon_state == TRAY_ICON_CUSTOM1) { if (custom_icon2) - gtk_status_icon_set_from_pixbuf (sticon, custom_icon2); + tray_set_custom_icon_state (custom_icon2, TRAY_ICON_CUSTOM2); else - gtk_status_icon_set_from_pixbuf (sticon, ICON_NORMAL); + tray_set_icon_state (ICON_NORMAL, TRAY_ICON_NORMAL); } else { - gtk_status_icon_set_from_pixbuf (sticon, custom_icon1); + tray_set_custom_icon_state (custom_icon1, TRAY_ICON_CUSTOM1); } } else { - if (gtk_status_icon_get_pixbuf (sticon) == ICON_NORMAL) - gtk_status_icon_set_from_pixbuf (sticon, icon); + if (tray_icon_state == TRAY_ICON_NORMAL) + tray_set_icon_state (tray_flash_icon, tray_flash_state); else - gtk_status_icon_set_from_pixbuf (sticon, ICON_NORMAL); + tray_set_icon_state (ICON_NORMAL, TRAY_ICON_NORMAL); } return 1; } static void -tray_set_flash (TrayIcon icon) +tray_set_flash (TrayIcon icon, TrayIconState state) { - if (!sticon) + if (!tray_backend_active) return; /* already flashing the same icon */ - if (flash_tag && gtk_status_icon_get_pixbuf (sticon) == icon) + if (flash_tag && tray_icon_state == state) return; /* no flashing if window is focused */ @@ -247,16 +746,18 @@ tray_set_flash (TrayIcon icon) tray_stop_flash (); - gtk_status_icon_set_from_pixbuf (sticon, icon); + tray_flash_icon = icon; + tray_flash_state = state; + tray_set_icon_state (icon, state); if (prefs.hex_gui_tray_blink) - flash_tag = g_timeout_add (TIMEOUT, (GSourceFunc) tray_timeout_cb, icon); + flash_tag = g_timeout_add (TIMEOUT, (GSourceFunc) tray_timeout_cb, NULL); } void fe_tray_set_flash (const char *filename1, const char *filename2, int tout) { tray_apply_setup (); - if (!sticon) + if (!tray_backend_active) return; tray_stop_flash (); @@ -268,16 +769,15 @@ fe_tray_set_flash (const char *filename1, const char *filename2, int tout) if (filename2) custom_icon2 = tray_icon_from_file (filename2); - gtk_status_icon_set_from_pixbuf (sticon, custom_icon1); + tray_set_custom_icon_state (custom_icon1, TRAY_ICON_CUSTOM1); flash_tag = g_timeout_add (tout, (GSourceFunc) tray_timeout_cb, NULL); - tray_status = TS_CUSTOM; } void fe_tray_set_icon (feicon icon) { tray_apply_setup (); - if (!sticon) + if (!tray_backend_active) return; tray_stop_flash (); @@ -288,13 +788,13 @@ fe_tray_set_icon (feicon icon) break; case FE_ICON_MESSAGE: case FE_ICON_PRIVMSG: - tray_set_flash (ICON_MSG); + tray_set_flash (ICON_MSG, TRAY_ICON_MESSAGE); break; case FE_ICON_HIGHLIGHT: - tray_set_flash (ICON_HILIGHT); + tray_set_flash (ICON_HILIGHT, TRAY_ICON_HIGHLIGHT); break; case FE_ICON_FILEOFFER: - tray_set_flash (ICON_FILE); + tray_set_flash (ICON_FILE, TRAY_ICON_FILEOFFER); } } @@ -302,7 +802,7 @@ void fe_tray_set_file (const char *filename) { tray_apply_setup (); - if (!sticon) + if (!tray_backend_active) return; tray_stop_flash (); @@ -310,8 +810,7 @@ fe_tray_set_file (const char *filename) if (filename) { custom_icon1 = tray_icon_from_file (filename); - gtk_status_icon_set_from_pixbuf (sticon, custom_icon1); - tray_status = TS_CUSTOM; + tray_set_custom_icon_state (custom_icon1, TRAY_ICON_CUSTOM1); } } @@ -324,7 +823,7 @@ tray_toggle_visibility (gboolean force_hide) static int fullscreen; GtkWindow *win; - if (!sticon) + if (!tray_backend_active) return FALSE; /* ph may have an invalid context now */ @@ -369,15 +868,22 @@ tray_toggle_visibility (gboolean force_hide) static void tray_menu_restore_cb (GtkWidget *item, gpointer userdata) { + (void)item; + (void)userdata; + tray_toggle_visibility (FALSE); } static void tray_menu_notify_cb (GObject *tray, GParamSpec *pspec, gpointer user_data) { - if (sticon) + (void)tray; + (void)pspec; + (void)user_data; + + if (tray_backend_active) { - if (!gtk_status_icon_is_embedded (sticon)) + if (!tray_backend_is_embedded ()) { tray_restore_timer = g_timeout_add(500, (GSourceFunc)tray_menu_try_restore, NULL); } @@ -403,6 +909,9 @@ tray_menu_try_restore (void) static void tray_menu_quit_cb (GtkWidget *item, gpointer userdata) { + (void)item; + (void)userdata; + mg_open_quit_dialog (FALSE); } @@ -483,6 +992,8 @@ blink_item (unsigned int *setting, GtkWidget *menu, char *label) static void tray_menu_destroy (GtkWidget *menu, gpointer userdata) { + (void)userdata; + gtk_widget_destroy (menu); g_object_unref (menu); #ifdef WIN32 @@ -494,6 +1005,8 @@ tray_menu_destroy (GtkWidget *menu, gpointer userdata) static gboolean tray_menu_enter_cb (GtkWidget *menu) { + (void)menu; + tray_menu_inactivetime = 0; return FALSE; } @@ -501,6 +1014,8 @@ tray_menu_enter_cb (GtkWidget *menu) static gboolean tray_menu_left_cb (GtkWidget *menu) { + (void)menu; + tray_menu_inactivetime = g_get_real_time (); return FALSE; } @@ -521,14 +1036,16 @@ tray_check_hide (GtkWidget *menu) static void tray_menu_settings (GtkWidget * wid, gpointer none) { + (void)wid; + (void)none; + extern void setup_open (void); setup_open (); } static void -tray_menu_cb (GtkWidget *widget, guint button, guint time, gpointer userdata) +tray_menu_populate (GtkWidget *menu) { - static GtkWidget *menu; GtkWidget *submenu; GtkWidget *item; int away_status; @@ -536,15 +1053,6 @@ tray_menu_cb (GtkWidget *widget, guint button, guint time, gpointer userdata) /* ph may have an invalid context now */ zoitechat_set_context (ph, zoitechat_find_context (ph, NULL, NULL)); - /* close any old menu */ - if (G_IS_OBJECT (menu)) - { - tray_menu_destroy (menu, NULL); - } - - menu = gtk_menu_new (); - /*gtk_menu_set_screen (GTK_MENU (menu), gtk_widget_get_screen (widget));*/ - if (tray_get_window_status () == WS_HIDDEN) tray_make_item (menu, _("_Restore Window"), tray_menu_restore_cb, NULL); else @@ -574,59 +1082,96 @@ tray_menu_cb (GtkWidget *widget, guint button, guint time, gpointer userdata) menu_add_plugin_items (menu, "\x5$TRAY", NULL); tray_make_item (menu, NULL, tray_menu_quit_cb, NULL); - mg_create_icon_item (_("_Preferences"), GTK_STOCK_PREFERENCES, menu, tray_menu_settings, NULL); + mg_create_icon_item (_("_Preferences"), ICON_TRAY_PREFERENCES, menu, tray_menu_settings, NULL); tray_make_item (menu, NULL, tray_menu_quit_cb, NULL); - mg_create_icon_item (_("_Quit"), GTK_STOCK_QUIT, menu, tray_menu_quit_cb, NULL); + mg_create_icon_item (_("_Quit"), ICON_TRAY_QUIT, menu, tray_menu_quit_cb, NULL); +} + +#if HAVE_GTK3 && !defined(WIN32) +static void +tray_menu_clear (GtkWidget *menu) +{ + GList *children; + GList *iter; + + children = gtk_container_get_children (GTK_CONTAINER (menu)); + for (iter = children; iter; iter = iter->next) + gtk_widget_destroy (GTK_WIDGET (iter->data)); + g_list_free (children); +} + +static void +tray_menu_show_cb (GtkWidget *menu, gpointer userdata) +{ + (void)userdata; + + tray_menu_clear (menu); + tray_menu_populate (menu); +} +#endif + +#if !HAVE_APPINDICATOR_BACKEND +static void +tray_menu_cb (GtkWidget *widget, guint button, guint time, gpointer userdata) +{ + static GtkWidget *menu; + + (void)widget; + + /* close any old menu */ + if (G_IS_OBJECT (menu)) + { + tray_menu_destroy (menu, NULL); + } + + menu = gtk_menu_new (); + /*gtk_menu_set_screen (GTK_MENU (menu), gtk_widget_get_screen (widget));*/ + tray_menu_populate (menu); g_object_ref (menu); g_object_ref_sink (menu); g_object_unref (menu); g_signal_connect (G_OBJECT (menu), "selection-done", - G_CALLBACK (tray_menu_destroy), NULL); + G_CALLBACK (tray_menu_destroy), NULL); #ifdef WIN32 g_signal_connect (G_OBJECT (menu), "leave-notify-event", - G_CALLBACK (tray_menu_left_cb), NULL); + G_CALLBACK (tray_menu_left_cb), NULL); g_signal_connect (G_OBJECT (menu), "enter-notify-event", - G_CALLBACK (tray_menu_enter_cb), NULL); + G_CALLBACK (tray_menu_enter_cb), NULL); tray_menu_timer = g_timeout_add (500, (GSourceFunc)tray_check_hide, menu); #endif gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, - userdata, button, time); + userdata, button, time); } +#endif static void tray_init (void) { flash_tag = 0; - tray_status = TS_NONE; + tray_icon_state = TRAY_ICON_NONE; + tray_flash_icon = NULL; + tray_flash_state = TRAY_ICON_NONE; custom_icon1 = NULL; custom_icon2 = NULL; - sticon = gtk_status_icon_new_from_pixbuf (ICON_NORMAL); - if (!sticon) + if (!tray_backend_init ()) return; - - g_signal_connect (G_OBJECT (sticon), "popup-menu", - G_CALLBACK (tray_menu_cb), sticon); - - g_signal_connect (G_OBJECT (sticon), "activate", - G_CALLBACK (tray_menu_restore_cb), NULL); - - g_signal_connect (G_OBJECT (sticon), "notify::embedded", - G_CALLBACK (tray_menu_notify_cb), NULL); + tray_icon_state = TRAY_ICON_NORMAL; + tray_set_icon_state (ICON_NORMAL, TRAY_ICON_NORMAL); } static int tray_hilight_cb (char *word[], void *userdata) { - /*if (tray_status == TS_HIGHLIGHT) + /*if (tray_icon_state == TRAY_ICON_HIGHLIGHT) return ZOITECHAT_EAT_NONE;*/ if (prefs.hex_input_tray_hilight) { - tray_set_flash (ICON_HILIGHT); + tray_set_flash (ICON_HILIGHT, TRAY_ICON_HIGHLIGHT); /* FIXME: hides any previous private messages */ tray_hilight_count++; @@ -645,12 +1190,12 @@ tray_hilight_cb (char *word[], void *userdata) static int tray_message_cb (char *word[], void *userdata) { - if (/*tray_status == TS_MESSAGE ||*/ tray_status == TS_HIGHLIGHT) + if (/*tray_icon_state == TRAY_ICON_MESSAGE ||*/ tray_icon_state == TRAY_ICON_HIGHLIGHT) return ZOITECHAT_EAT_NONE; if (prefs.hex_input_tray_chans) { - tray_set_flash (ICON_MSG); + tray_set_flash (ICON_MSG, TRAY_ICON_MESSAGE); tray_pub_count++; if (tray_pub_count == 1) @@ -677,7 +1222,7 @@ tray_priv (char *from, char *text) if (prefs.hex_input_tray_priv) { - tray_set_flash (ICON_MSG); + tray_set_flash (ICON_MSG, TRAY_ICON_MESSAGE); tray_priv_count++; if (tray_priv_count == 1) @@ -711,7 +1256,7 @@ tray_dcc_cb (char *word[], void *userdata) { const char *network; -/* if (tray_status == TS_FILEOFFER) +/* if (tray_icon_state == TRAY_ICON_FILEOFFER) return ZOITECHAT_EAT_NONE;*/ network = zoitechat_get_info (ph, "network"); @@ -720,7 +1265,7 @@ tray_dcc_cb (char *word[], void *userdata) if (prefs.hex_input_tray_priv && (!prefs.hex_away_omit_alerts || tray_find_away_status () != 1)) { - tray_set_flash (ICON_FILE); + tray_set_flash (ICON_FILE, TRAY_ICON_FILEOFFER); tray_file_count++; if (tray_file_count == 1) @@ -747,17 +1292,14 @@ tray_cleanup (void) { tray_stop_flash (); - if (sticon) - { - g_object_unref ((GObject *)sticon); - sticon = NULL; - } + if (tray_backend_active) + tray_backend_cleanup (); } void tray_apply_setup (void) { - if (sticon) + if (tray_backend_active) { if (!prefs.hex_gui_tray) tray_cleanup (); diff --git a/src/fe-gtk/plugingui.c b/src/fe-gtk/plugingui.c index bebe68dc..9d739a66 100644 --- a/src/fe-gtk/plugingui.c +++ b/src/fe-gtk/plugingui.c @@ -48,6 +48,54 @@ enum static GtkWidget *plugin_window = NULL; +static const char * +plugingui_safe_string (const char *value) +{ + return value ? value : ""; +} + +static session * +plugingui_get_target_session (void) +{ + if (is_session (current_sess)) + return current_sess; + + fe_message (_("No active session available for addon command."), FE_MSG_ERROR); + return NULL; +} + +#if HAVE_GTK3 +#define ICON_PLUGIN_LOAD "document-open" +#define ICON_PLUGIN_UNLOAD "edit-delete" +#define ICON_PLUGIN_RELOAD "view-refresh" +#endif +#if !HAVE_GTK3 +#define ICON_PLUGIN_LOAD GTK_STOCK_REVERT_TO_SAVED +#define ICON_PLUGIN_UNLOAD GTK_STOCK_DELETE +#define ICON_PLUGIN_RELOAD GTK_STOCK_REFRESH +#endif + +#if HAVE_GTK3 +static GtkWidget * +plugingui_icon_button (GtkWidget *box, const char *label, + const char *icon_name, GCallback callback, + gpointer userdata) +{ + GtkWidget *button; + GtkWidget *image; + + button = gtk_button_new_with_mnemonic (label); + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); + gtk_button_set_image (GTK_BUTTON (button), image); + gtk_button_set_use_underline (GTK_BUTTON (button), TRUE); + gtk_container_add (GTK_CONTAINER (box), button); + g_signal_connect (G_OBJECT (button), "clicked", callback, userdata); + gtk_widget_show (button); + + return button; +} +#endif + static GtkWidget * plugingui_treeview_new (GtkWidget *box) @@ -120,21 +168,27 @@ fe_pluginlist_update (void) return; view = g_object_get_data (G_OBJECT (plugin_window), "view"); + if (!GTK_IS_TREE_VIEW (view)) + return; + store = GTK_LIST_STORE (gtk_tree_view_get_model (view)); + if (!GTK_IS_LIST_STORE (store)) + return; + gtk_list_store_clear (store); list = plugin_list; while (list) { pl = list->data; - if (pl->version[0] != 0) + if (pl && pl->version && pl->version[0] != 0) { gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, NAME_COLUMN, pl->name, - VERSION_COLUMN, pl->version, - FILE_COLUMN, file_part (pl->filename), - DESC_COLUMN, pl->desc, - FILEPATH_COLUMN, pl->filename, -1); + gtk_list_store_set (store, &iter, NAME_COLUMN, plugingui_safe_string (pl->name), + VERSION_COLUMN, plugingui_safe_string (pl->version), + FILE_COLUMN, pl->filename ? file_part (pl->filename) : "", + DESC_COLUMN, plugingui_safe_string (pl->desc), + FILEPATH_COLUMN, plugingui_safe_string (pl->filename), -1); } list = list->next; } @@ -143,15 +197,36 @@ fe_pluginlist_update (void) static void plugingui_load_cb (session *sess, char *file) { + session *target_sess; + if (file) { char *buf; + char *load_target; - if (strchr (file, ' ')) - buf = g_strdup_printf ("LOAD \"%s\"", file); + target_sess = is_session (sess) ? sess : current_sess; + if (!is_session (target_sess)) + { + fe_message (_("No active session available for loading addons."), FE_MSG_ERROR); + return; + } + + load_target = g_strdup (file); + +#ifdef WIN32 + /* + * The command parser is more reliable with forward slashes on Windows + * paths (especially when quoted), so normalize before issuing LOAD. + */ + g_strdelimit (load_target, "\\", '/'); +#endif + + if (strchr (load_target, ' ')) + buf = g_strdup_printf ("LOAD \"%s\"", load_target); else - buf = g_strdup_printf ("LOAD %s", file); - handle_command (sess, buf, FALSE); + buf = g_strdup_printf ("LOAD %s", load_target); + handle_command (target_sess, buf, FALSE); + g_free (load_target); g_free (buf); } } @@ -159,12 +234,15 @@ plugingui_load_cb (session *sess, char *file) void plugingui_load (void) { - char *sub_dir = g_build_filename (get_xdir(), "addons", NULL); + const char *xdir = get_xdir (); + char *sub_dir = NULL; - gtkutil_file_req (NULL, _("Select a Plugin or Script to load"), plugingui_load_cb, current_sess, - sub_dir, "*."PLUGIN_SUFFIX";*.lua;*.pl;*.py;*.tcl;*.js", FRF_FILTERISINITIAL|FRF_EXTENSIONS); + if (xdir && xdir[0] != '\0') + sub_dir = g_build_filename (xdir, "addons", NULL); - g_free (sub_dir); + gtkutil_file_req (NULL, _("Select a Plugin or Script to load"), plugingui_load_cb, NULL, + sub_dir, "*."PLUGIN_SUFFIX";*.lua;*.pl;*.py;*.tcl;*.js", FRF_FILTERISINITIAL|FRF_EXTENSIONS); + g_free (sub_dir); } static void @@ -177,6 +255,7 @@ static void plugingui_unload (GtkWidget * wid, gpointer unused) { char *modname, *file; + session *target_sess; GtkTreeView *view; GtkTreeIter iter; @@ -184,6 +263,18 @@ plugingui_unload (GtkWidget * wid, gpointer unused) if (!gtkutil_treeview_get_selected (view, &iter, NAME_COLUMN, &modname, FILEPATH_COLUMN, &file, -1)) return; + if (!modname || !*modname) + { + g_free (modname); + g_free (file); + return; + } + if (!file || !*file) + { + g_free (modname); + g_free (file); + return; + } if (g_str_has_suffix (file, "."PLUGIN_SUFFIX)) { @@ -194,11 +285,19 @@ plugingui_unload (GtkWidget * wid, gpointer unused) { char *buf; /* let python.so or perl.so handle it */ + target_sess = plugingui_get_target_session (); + if (!target_sess) + { + g_free (modname); + g_free (file); + return; + } + if (strchr (file, ' ')) buf = g_strdup_printf ("UNLOAD \"%s\"", file); else buf = g_strdup_printf ("UNLOAD %s", file); - handle_command (current_sess, buf, FALSE); + handle_command (target_sess, buf, FALSE); g_free (buf); } @@ -210,16 +309,24 @@ static void plugingui_reloadbutton_cb (GtkWidget *wid, GtkTreeView *view) { char *file = plugingui_getfilename(view); + session *target_sess; if (file) { char *buf; + target_sess = plugingui_get_target_session (); + if (!target_sess) + { + g_free (file); + return; + } + if (strchr (file, ' ')) buf = g_strdup_printf ("RELOAD \"%s\"", file); else buf = g_strdup_printf ("RELOAD %s", file); - handle_command (current_sess, buf, FALSE); + handle_command (target_sess, buf, FALSE); g_free (buf); g_free (file); } @@ -229,6 +336,7 @@ void plugingui_open (void) { GtkWidget *view; + GtkWidget *view_scroll; GtkWidget *vbox, *hbox; char buf[128]; @@ -244,22 +352,46 @@ plugingui_open (void) gtkutil_destroy_on_esc (plugin_window); view = plugingui_treeview_new (vbox); + view_scroll = gtk_widget_get_parent (view); + if (view_scroll) + { + gtk_box_set_child_packing (GTK_BOX (vbox), view_scroll, TRUE, TRUE, 0, GTK_PACK_START); + gtk_widget_set_hexpand (view_scroll, TRUE); + gtk_widget_set_vexpand (view_scroll, TRUE); + } g_object_set_data (G_OBJECT (plugin_window), "view", view); +#if HAVE_GTK3 + hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 hbox = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD); +#endif gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); gtk_box_pack_end (GTK_BOX (vbox), hbox, 0, 0, 0); - gtkutil_button (hbox, GTK_STOCK_REVERT_TO_SAVED, NULL, +#if HAVE_GTK3 + { + plugingui_icon_button (hbox, _("_Load..."), ICON_PLUGIN_LOAD, + G_CALLBACK (plugingui_loadbutton_cb), NULL); + plugingui_icon_button (hbox, _("_Unload"), ICON_PLUGIN_UNLOAD, + G_CALLBACK (plugingui_unload), NULL); + plugingui_icon_button (hbox, _("_Reload"), ICON_PLUGIN_RELOAD, + G_CALLBACK (plugingui_reloadbutton_cb), view); + } +#endif +#if !HAVE_GTK3 + gtkutil_button (hbox, ICON_PLUGIN_LOAD, NULL, plugingui_loadbutton_cb, NULL, _("_Load...")); - gtkutil_button (hbox, GTK_STOCK_DELETE, NULL, + gtkutil_button (hbox, ICON_PLUGIN_UNLOAD, NULL, plugingui_unload, NULL, _("_Unload")); - gtkutil_button (hbox, GTK_STOCK_REFRESH, NULL, + gtkutil_button (hbox, ICON_PLUGIN_RELOAD, NULL, plugingui_reloadbutton_cb, view, _("_Reload")); +#endif fe_pluginlist_update (); diff --git a/src/fe-gtk/rawlog.c b/src/fe-gtk/rawlog.c index 284b5c6d..89174cd2 100644 --- a/src/fe-gtk/rawlog.c +++ b/src/fe-gtk/rawlog.c @@ -42,6 +42,15 @@ #include "xtext.h" #include "fkeys.h" +#if HAVE_GTK3 +#define ICON_RAWLOG_CLEAR "edit-clear" +#define ICON_RAWLOG_SAVE_AS "document-save-as" +#endif +#if !HAVE_GTK3 +#define ICON_RAWLOG_CLEAR GTK_STOCK_CLEAR +#define ICON_RAWLOG_SAVE_AS GTK_STOCK_SAVE_AS +#endif + static void close_rawlog (GtkWidget *wid, server *serv) { @@ -119,7 +128,13 @@ open_rawlog (struct server *serv) scrolledwindow = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN); +#if HAVE_GTK3 + gtk_widget_set_hexpand (scrolledwindow, TRUE); + gtk_widget_set_vexpand (scrolledwindow, TRUE); + gtk_box_pack_start (GTK_BOX (vbox), scrolledwindow, TRUE, TRUE, 0); +#elif !HAVE_GTK3 gtk_container_add (GTK_CONTAINER (vbox), scrolledwindow); +#endif palette_get_xtext_colors (xtext_palette, XTEXT_COLS); serv->gui->rawlog_textlist = gtk_xtext_new (xtext_palette, 0); @@ -127,14 +142,19 @@ open_rawlog (struct server *serv) gtk_xtext_set_font (GTK_XTEXT (serv->gui->rawlog_textlist), prefs.hex_text_font); GTK_XTEXT (serv->gui->rawlog_textlist)->ignore_hidden = 1; +#if HAVE_GTK3 + bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 bbox = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD); +#endif gtk_box_pack_end (GTK_BOX (vbox), bbox, 0, 0, 4); - gtkutil_button (bbox, GTK_STOCK_CLEAR, NULL, rawlog_clearbutton, + gtkutil_button (bbox, ICON_RAWLOG_CLEAR, NULL, rawlog_clearbutton, serv, _("Clear Raw Log")); - gtkutil_button (bbox, GTK_STOCK_SAVE_AS, NULL, rawlog_savebutton, + gtkutil_button (bbox, ICON_RAWLOG_SAVE_AS, NULL, rawlog_savebutton, serv, _("Save As...")); /* Copy selection to clipboard when Ctrl+Shift+C is pressed AND text auto-copy is disabled */ diff --git a/src/fe-gtk/servlistgui.c b/src/fe-gtk/servlistgui.c index 33f73e50..2a014be6 100644 --- a/src/fe-gtk/servlistgui.c +++ b/src/fe-gtk/servlistgui.c @@ -39,6 +39,21 @@ #define SERVLIST_X_PADDING 4 /* horizontal paddig in the network editor */ #define SERVLIST_Y_PADDING 0 /* vertical padding in the network editor */ +#if HAVE_GTK3 +#define ICON_SERVLIST_CONNECT "network-connect" +#define ICON_SERVLIST_ADD "list-add" +#define ICON_SERVLIST_REMOVE "list-remove" +#define ICON_SERVLIST_CLOSE "window-close" +#define ICON_SERVLIST_ERROR "dialog-error" +#endif +#if !HAVE_GTK3 +#define ICON_SERVLIST_CONNECT GTK_STOCK_CONNECT +#define ICON_SERVLIST_ADD GTK_STOCK_ADD +#define ICON_SERVLIST_REMOVE GTK_STOCK_REMOVE +#define ICON_SERVLIST_CLOSE GTK_STOCK_CLOSE +#define ICON_SERVLIST_ERROR GTK_STOCK_DIALOG_ERROR +#endif + #ifdef USE_OPENSSL # define DEFAULT_SERVER "newserver/6697" #else @@ -92,6 +107,22 @@ static session *servlist_sess; static void servlist_network_row_cb (GtkTreeSelection *sel, gpointer user_data); static GtkWidget *servlist_open_edit (GtkWidget *parent, ircnet *net); +#if HAVE_GTK3 +static GtkWidget * +servlist_icon_button_new (const char *label, const char *icon_name) +{ + GtkWidget *button; + GtkWidget *image; + + button = gtk_button_new_with_mnemonic (label); + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON (button), image); + gtk_button_set_always_show_image (GTK_BUTTON (button), TRUE); + + return button; +} +#endif + static const char *pages[]= { @@ -1251,6 +1282,73 @@ servlist_check_cb (GtkWidget *but, gpointer num_p) } } +typedef enum +{ + SERVLIST_ALIGN_START, + SERVLIST_ALIGN_CENTER, + SERVLIST_ALIGN_FILL +} servlist_align; + +#if HAVE_GTK3 +static GtkAlign +servlist_align_to_gtk (servlist_align align) +{ + switch (align) + { + case SERVLIST_ALIGN_FILL: + return GTK_ALIGN_FILL; + case SERVLIST_ALIGN_CENTER: + return GTK_ALIGN_CENTER; + case SERVLIST_ALIGN_START: + default: + return GTK_ALIGN_START; + } +} +#endif + +static void +servlist_table_attach (GtkWidget *table, GtkWidget *child, + guint left_attach, guint right_attach, + guint top_attach, guint bottom_attach, + gboolean hexpand, gboolean vexpand, + servlist_align halign, servlist_align valign, + guint xpad, guint ypad) +{ +#if HAVE_GTK3 + gtk_widget_set_hexpand (child, hexpand); + gtk_widget_set_vexpand (child, vexpand); + gtk_widget_set_halign (child, servlist_align_to_gtk (halign)); + gtk_widget_set_valign (child, servlist_align_to_gtk (valign)); + gtk_widget_set_margin_start (child, xpad); + gtk_widget_set_margin_end (child, xpad); + gtk_widget_set_margin_top (child, ypad); + gtk_widget_set_margin_bottom (child, ypad); + gtk_grid_attach (GTK_GRID (table), child, left_attach, top_attach, + right_attach - left_attach, bottom_attach - top_attach); +#else + GtkAttachOptions xoptions = 0; + GtkAttachOptions yoptions = 0; + + if (hexpand) + xoptions |= GTK_EXPAND; + else + xoptions |= GTK_SHRINK; + if (halign == SERVLIST_ALIGN_FILL) + xoptions |= GTK_FILL; + + if (vexpand) + yoptions |= GTK_EXPAND; + else + yoptions |= GTK_SHRINK; + if (valign == SERVLIST_ALIGN_FILL) + yoptions |= GTK_FILL; + + gtk_table_attach (GTK_TABLE (table), child, left_attach, right_attach, + top_attach, bottom_attach, xoptions, yoptions, + xpad, ypad); +#endif +} + static GtkWidget * servlist_create_check (int num, int state, GtkWidget *table, int row, int col, char *labeltext) { @@ -1260,7 +1358,10 @@ servlist_create_check (int num, int state, GtkWidget *table, int row, int col, c gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (but), state); g_signal_connect (G_OBJECT (but), "toggled", G_CALLBACK (servlist_check_cb), GINT_TO_POINTER (num)); - gtk_table_attach (GTK_TABLE (table), but, col, col+2, row, row+1, GTK_FILL|GTK_EXPAND, 0, SERVLIST_X_PADDING, SERVLIST_Y_PADDING); + servlist_table_attach (table, but, col, col + 2, row, row + 1, + TRUE, FALSE, + SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_CENTER, + SERVLIST_X_PADDING, SERVLIST_Y_PADDING); gtk_widget_show (but); return but; @@ -1276,8 +1377,16 @@ servlist_create_entry (GtkWidget *table, char *labeltext, int row, if (label_ret) *label_ret = label; gtk_widget_show (label); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row+1, GTK_FILL, 0, SERVLIST_X_PADDING, SERVLIST_Y_PADDING); + servlist_table_attach (table, label, 0, 1, row, row + 1, + FALSE, FALSE, + SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER, + SERVLIST_X_PADDING, SERVLIST_Y_PADDING); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); +#endif entry = gtk_entry_new (); gtk_widget_set_tooltip_text (entry, tip); @@ -1285,7 +1394,10 @@ servlist_create_entry (GtkWidget *table, char *labeltext, int row, gtk_entry_set_text (GTK_ENTRY (entry), def ? def : ""); gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry); - gtk_table_attach (GTK_TABLE (table), entry, 1, 2, row, row+1, GTK_FILL|GTK_EXPAND, 0, SERVLIST_X_PADDING, SERVLIST_Y_PADDING); + servlist_table_attach (table, entry, 1, 2, row, row + 1, + TRUE, FALSE, + SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_CENTER, + SERVLIST_X_PADDING, SERVLIST_Y_PADDING); return entry; } @@ -1563,14 +1675,24 @@ servlist_username_changed_cb (GtkEntry *entry, gpointer userdata) if (gtk_entry_get_text (entry)[0] == 0) { +#if HAVE_GTK3 + gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, ICON_SERVLIST_ERROR); +#endif +#if !HAVE_GTK3 gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_DIALOG_ERROR); +#endif gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, _("User name cannot be left blank.")); gtk_widget_set_sensitive (connect_btn, FALSE); } else { +#if HAVE_GTK3 + gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, NULL); +#endif +#if !HAVE_GTK3 gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY, NULL); +#endif gtk_widget_set_sensitive (connect_btn, TRUE); } } @@ -1585,22 +1707,38 @@ servlist_nick_changed_cb (GtkEntry *entry, gpointer userdata) if (!nick1[0] || !nick2[0]) { entry = GTK_ENTRY(!nick1[0] ? entry_nick1 : entry_nick2); +#if HAVE_GTK3 + gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, ICON_SERVLIST_ERROR); +#endif +#if !HAVE_GTK3 gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_DIALOG_ERROR); +#endif gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, _("You cannot have an empty nick name.")); gtk_widget_set_sensitive (connect_btn, FALSE); } else if (!rfc_casecmp (nick1, nick2)) { +#if HAVE_GTK3 + gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, ICON_SERVLIST_ERROR); +#endif +#if !HAVE_GTK3 gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_DIALOG_ERROR); +#endif gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, _("You must have two unique nick names.")); gtk_widget_set_sensitive (connect_btn, FALSE); } else { +#if HAVE_GTK3 + gtk_entry_set_icon_from_icon_name (GTK_ENTRY(entry_nick1), GTK_ENTRY_ICON_SECONDARY, NULL); + gtk_entry_set_icon_from_icon_name (GTK_ENTRY(entry_nick2), GTK_ENTRY_ICON_SECONDARY, NULL); +#endif +#if !HAVE_GTK3 gtk_entry_set_icon_from_stock (GTK_ENTRY(entry_nick1), GTK_ENTRY_ICON_SECONDARY, NULL); gtk_entry_set_icon_from_stock (GTK_ENTRY(entry_nick2), GTK_ENTRY_ICON_SECONDARY, NULL); +#endif gtk_widget_set_sensitive (connect_btn, TRUE); } } @@ -1680,7 +1818,12 @@ bold_label (char *text) g_snprintf (buf, sizeof (buf), "%s", text); label = gtk_label_new (buf); gtk_label_set_use_markup (GTK_LABEL (label), TRUE); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); +#endif gtk_widget_show (label); return label; @@ -1727,12 +1870,12 @@ servlist_open_edit (GtkWidget *parent, ircnet *net) gtk_window_set_type_hint (GTK_WINDOW (editwindow), GDK_WINDOW_TYPE_HINT_DIALOG); gtk_window_set_role (GTK_WINDOW (editwindow), "editserv"); - vbox5 = gtk_vbox_new (FALSE, 0); + vbox5 = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); gtk_container_add (GTK_CONTAINER (editwindow), vbox5); /* Tabs and buttons */ - hbox1 = gtk_hbox_new (FALSE, 0); + hbox1 = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox5), hbox1, TRUE, TRUE, 4); scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL); @@ -1845,18 +1988,32 @@ servlist_open_edit (GtkWidget *parent, ircnet *net) /* Button Box */ +#if HAVE_GTK3 + vbuttonbox1 = gtk_button_box_new (GTK_ORIENTATION_VERTICAL); +#elif !HAVE_GTK3 vbuttonbox1 = gtk_vbutton_box_new (); +#endif gtk_box_set_spacing (GTK_BOX (vbuttonbox1), 3); gtk_button_box_set_layout (GTK_BUTTON_BOX (vbuttonbox1), GTK_BUTTONBOX_START); gtk_box_pack_start (GTK_BOX (hbox1), vbuttonbox1, FALSE, FALSE, 3); - buttonadd = gtk_button_new_from_stock ("gtk-add"); +#if HAVE_GTK3 + buttonadd = servlist_icon_button_new (_("_Add"), ICON_SERVLIST_ADD); +#endif +#if !HAVE_GTK3 + buttonadd = gtk_button_new_from_stock (GTK_STOCK_ADD); +#endif g_signal_connect (G_OBJECT (buttonadd), "clicked", G_CALLBACK (servlist_addbutton_cb), notebook); gtk_container_add (GTK_CONTAINER (vbuttonbox1), buttonadd); gtk_widget_set_can_default (buttonadd, TRUE); - buttonremove = gtk_button_new_from_stock ("gtk-remove"); +#if HAVE_GTK3 + buttonremove = servlist_icon_button_new (_("_Remove"), ICON_SERVLIST_REMOVE); +#endif +#if !HAVE_GTK3 + buttonremove = gtk_button_new_from_stock (GTK_STOCK_REMOVE); +#endif g_signal_connect (G_OBJECT (buttonremove), "clicked", G_CALLBACK (servlist_deletebutton_cb), notebook); gtk_container_add (GTK_CONTAINER (vbuttonbox1), buttonremove); @@ -1870,10 +2027,15 @@ servlist_open_edit (GtkWidget *parent, ircnet *net) /* Checkboxes and entries */ - table3 = gtk_table_new (13, 2, FALSE); + table3 = gtkutil_grid_new (13, 2, FALSE); gtk_box_pack_start (GTK_BOX (vbox5), table3, FALSE, FALSE, 0); +#if HAVE_GTK3 + gtk_grid_set_row_spacing (GTK_GRID (table3), 2); + gtk_grid_set_column_spacing (GTK_GRID (table3), 8); +#else gtk_table_set_row_spacings (GTK_TABLE (table3), 2); gtk_table_set_col_spacings (GTK_TABLE (table3), 8); +#endif check = servlist_create_check (0, !(net->flags & FLAG_CYCLE), table3, 0, 0, _("Connect to selected server only")); gtk_widget_set_tooltip_text (check, _("Don't cycle through all the servers when the connection fails.")); @@ -1895,10 +2057,21 @@ servlist_open_edit (GtkWidget *parent, ircnet *net) edit_entry_user = servlist_create_entry (table3, _("_User name:"), 9, net->user, &edit_label_user, 0); label_logintype = gtk_label_new (_("Login method:")); - gtk_table_attach (GTK_TABLE (table3), label_logintype, 0, 1, 10, 11, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), SERVLIST_X_PADDING, SERVLIST_Y_PADDING); + servlist_table_attach (table3, label_logintype, 0, 1, 10, 11, + FALSE, FALSE, + SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER, + SERVLIST_X_PADDING, SERVLIST_Y_PADDING); +#if HAVE_GTK3 + gtk_widget_set_halign (label_logintype, GTK_ALIGN_START); + gtk_widget_set_valign (label_logintype, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label_logintype), 0, 0.5); +#endif combobox_logintypes = servlist_create_logintypecombo (notebook); - gtk_table_attach (GTK_TABLE (table3), combobox_logintypes, 1, 2, 10, 11, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 4, 2); + servlist_table_attach (table3, combobox_logintypes, 1, 2, 10, 11, + FALSE, FALSE, + SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL, + 4, 2); edit_entry_pass = servlist_create_entry (table3, _("Password:"), 11, net->pass, 0, _("Password used for login. If in doubt, leave blank.")); gtk_entry_set_visibility (GTK_ENTRY (edit_entry_pass), FALSE); @@ -1906,21 +2079,46 @@ servlist_open_edit (GtkWidget *parent, ircnet *net) gtk_widget_set_sensitive (edit_entry_pass, FALSE); label34 = gtk_label_new (_("Character set:")); - gtk_table_attach (GTK_TABLE (table3), label34, 0, 1, 12, 13, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), SERVLIST_X_PADDING, SERVLIST_Y_PADDING); + servlist_table_attach (table3, label34, 0, 1, 12, 13, + FALSE, FALSE, + SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER, + SERVLIST_X_PADDING, SERVLIST_Y_PADDING); +#if HAVE_GTK3 + gtk_widget_set_halign (label34, GTK_ALIGN_START); + gtk_widget_set_valign (label34, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label34), 0, 0.5); +#endif comboboxentry_charset = servlist_create_charsetcombo (); - gtk_table_attach (GTK_TABLE (table3), comboboxentry_charset, 1, 2, 12, 13, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 4, 2); + servlist_table_attach (table3, comboboxentry_charset, 1, 2, 12, 13, + FALSE, FALSE, + SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL, + 4, 2); /* Rule and Close button */ +#if HAVE_GTK3 + hseparator2 = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); +#elif !HAVE_GTK3 hseparator2 = gtk_hseparator_new (); +#endif gtk_box_pack_start (GTK_BOX (vbox5), hseparator2, FALSE, FALSE, 8); - hbuttonbox4 = gtk_hbutton_box_new (); - gtk_box_pack_start (GTK_BOX (vbox5), hbuttonbox4, FALSE, FALSE, 0); +#if HAVE_GTK3 + hbuttonbox4 = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox4), GTK_BUTTONBOX_END); +#elif !HAVE_GTK3 + hbuttonbox4 = gtk_hbutton_box_new (); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox4), GTK_BUTTONBOX_END); +#endif + gtk_box_pack_start (GTK_BOX (vbox5), hbuttonbox4, FALSE, FALSE, 0); - button10 = gtk_button_new_from_stock ("gtk-close"); +#if HAVE_GTK3 + button10 = servlist_icon_button_new (_("_Close"), ICON_SERVLIST_CLOSE); +#endif +#if !HAVE_GTK3 + button10 = gtk_button_new_from_stock (GTK_STOCK_CLOSE); +#endif g_signal_connect (G_OBJECT (button10), "clicked", G_CALLBACK (servlist_edit_close_cb), 0); gtk_container_add (GTK_CONTAINER (hbuttonbox4), button10); @@ -1994,82 +2192,115 @@ servlist_open_networks (void) if (current_sess) gtk_window_set_transient_for (GTK_WINDOW (servlist), GTK_WINDOW (current_sess->gui->window)); - vbox1 = gtk_vbox_new (FALSE, 0); + vbox1 = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); gtk_widget_show (vbox1); gtk_container_add (GTK_CONTAINER (servlist), vbox1); label2 = bold_label (_("User Information")); gtk_box_pack_start (GTK_BOX (vbox1), label2, FALSE, FALSE, 0); - table1 = gtk_table_new (5, 2, FALSE); + table1 = gtkutil_grid_new (5, 2, FALSE); gtk_widget_show (table1); gtk_box_pack_start (GTK_BOX (vbox1), table1, FALSE, FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (table1), 8); +#if HAVE_GTK3 + gtk_grid_set_row_spacing (GTK_GRID (table1), 2); + gtk_grid_set_column_spacing (GTK_GRID (table1), 4); +#else gtk_table_set_row_spacings (GTK_TABLE (table1), 2); gtk_table_set_col_spacings (GTK_TABLE (table1), 4); +#endif label3 = gtk_label_new_with_mnemonic (_("_Nick name:")); gtk_widget_show (label3); - gtk_table_attach (GTK_TABLE (table1), label3, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + servlist_table_attach (table1, label3, 0, 1, 0, 1, + FALSE, FALSE, + SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER, + 0, 0); +#if HAVE_GTK3 + gtk_widget_set_halign (label3, GTK_ALIGN_START); + gtk_widget_set_valign (label3, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label3), 0, 0.5); +#endif label4 = gtk_label_new (_("Second choice:")); gtk_widget_show (label4); - gtk_table_attach (GTK_TABLE (table1), label4, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + servlist_table_attach (table1, label4, 0, 1, 1, 2, + FALSE, FALSE, + SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER, + 0, 0); +#if HAVE_GTK3 + gtk_widget_set_halign (label4, GTK_ALIGN_START); + gtk_widget_set_valign (label4, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label4), 0, 0.5); +#endif label5 = gtk_label_new (_("Third choice:")); gtk_widget_show (label5); - gtk_table_attach (GTK_TABLE (table1), label5, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + servlist_table_attach (table1, label5, 0, 1, 2, 3, + FALSE, FALSE, + SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER, + 0, 0); +#if HAVE_GTK3 + gtk_widget_set_halign (label5, GTK_ALIGN_START); + gtk_widget_set_valign (label5, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label5), 0, 0.5); +#endif label6 = gtk_label_new_with_mnemonic (_("_User name:")); gtk_widget_show (label6); - gtk_table_attach (GTK_TABLE (table1), label6, 0, 1, 3, 4, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + servlist_table_attach (table1, label6, 0, 1, 3, 4, + FALSE, FALSE, + SERVLIST_ALIGN_START, SERVLIST_ALIGN_CENTER, + 0, 0); +#if HAVE_GTK3 + gtk_widget_set_halign (label6, GTK_ALIGN_START); + gtk_widget_set_valign (label6, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label6), 0, 0.5); +#endif /* label7 = gtk_label_new_with_mnemonic (_("Rea_l name:")); gtk_widget_show (label7); gtk_table_attach (GTK_TABLE (table1), label7, 0, 1, 4, 5, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (label7), 0, 0.5);*/ + */ entry_nick1 = entry1 = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (entry1), prefs.hex_irc_nick1); gtk_widget_show (entry1); - gtk_table_attach (GTK_TABLE (table1), entry1, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + servlist_table_attach (table1, entry1, 1, 2, 0, 1, + TRUE, FALSE, + SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_CENTER, + 0, 0); entry_nick2 = entry2 = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (entry2), prefs.hex_irc_nick2); gtk_widget_show (entry2); - gtk_table_attach (GTK_TABLE (table1), entry2, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + servlist_table_attach (table1, entry2, 1, 2, 1, 2, + TRUE, FALSE, + SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_CENTER, + 0, 0); entry_nick3 = entry3 = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (entry3), prefs.hex_irc_nick3); gtk_widget_show (entry3); - gtk_table_attach (GTK_TABLE (table1), entry3, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + servlist_table_attach (table1, entry3, 1, 2, 2, 3, + TRUE, FALSE, + SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_CENTER, + 0, 0); entry_guser = entry4 = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (entry4), prefs.hex_irc_user_name); gtk_widget_show (entry4); - gtk_table_attach (GTK_TABLE (table1), entry4, 1, 2, 3, 4, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + servlist_table_attach (table1, entry4, 1, 2, 3, 4, + TRUE, FALSE, + SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_CENTER, + 0, 0); /* entry_greal = entry5 = gtk_entry_new (); gtk_entry_set_text (GTK_ENTRY (entry5), prefs.hex_irc_real_name); @@ -2078,25 +2309,31 @@ servlist_open_networks (void) (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); */ - vbox2 = gtk_vbox_new (FALSE, 0); + vbox2 = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); gtk_widget_show (vbox2); gtk_box_pack_start (GTK_BOX (vbox1), vbox2, TRUE, TRUE, 0); label1 = bold_label (_("Networks")); gtk_box_pack_start (GTK_BOX (vbox2), label1, FALSE, FALSE, 0); - table4 = gtk_table_new (2, 2, FALSE); + table4 = gtkutil_grid_new (2, 2, FALSE); gtk_widget_show (table4); gtk_box_pack_start (GTK_BOX (vbox2), table4, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (table4), 8); +#if HAVE_GTK3 + gtk_grid_set_row_spacing (GTK_GRID (table4), 2); + gtk_grid_set_column_spacing (GTK_GRID (table4), 3); +#else gtk_table_set_row_spacings (GTK_TABLE (table4), 2); gtk_table_set_col_spacings (GTK_TABLE (table4), 3); +#endif scrolledwindow3 = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (scrolledwindow3); - gtk_table_attach (GTK_TABLE (table4), scrolledwindow3, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); + servlist_table_attach (table4, scrolledwindow3, 0, 1, 0, 1, + TRUE, TRUE, + SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL, + 0, 0); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow3), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow3), @@ -2123,10 +2360,11 @@ servlist_open_networks (void) "weight", 2, NULL); - hbox = gtk_hbox_new (0, FALSE); - gtk_table_attach (GTK_TABLE (table4), hbox, 0, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); + servlist_table_attach (table4, hbox, 0, 2, 1, 2, + FALSE, FALSE, + SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_CENTER, + 0, 0); gtk_widget_show (hbox); checkbutton_skip = @@ -2147,22 +2385,37 @@ servlist_open_networks (void) G_CALLBACK (fav_servlist), 0); gtk_widget_show (checkbutton_fav); +#if HAVE_GTK3 + vbuttonbox2 = gtk_button_box_new (GTK_ORIENTATION_VERTICAL); +#elif !HAVE_GTK3 vbuttonbox2 = gtk_vbutton_box_new (); +#endif gtk_box_set_spacing (GTK_BOX (vbuttonbox2), 3); gtk_button_box_set_layout (GTK_BUTTON_BOX (vbuttonbox2), GTK_BUTTONBOX_START); gtk_widget_show (vbuttonbox2); - gtk_table_attach (GTK_TABLE (table4), vbuttonbox2, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); + servlist_table_attach (table4, vbuttonbox2, 1, 2, 0, 1, + FALSE, FALSE, + SERVLIST_ALIGN_FILL, SERVLIST_ALIGN_FILL, + 0, 0); - button_add = gtk_button_new_from_stock ("gtk-add"); +#if HAVE_GTK3 + button_add = servlist_icon_button_new (_("_Add"), ICON_SERVLIST_ADD); +#endif +#if !HAVE_GTK3 + button_add = gtk_button_new_from_stock (GTK_STOCK_ADD); +#endif g_signal_connect (G_OBJECT (button_add), "clicked", G_CALLBACK (servlist_addnet_cb), networks_tree); gtk_widget_show (button_add); gtk_container_add (GTK_CONTAINER (vbuttonbox2), button_add); gtk_widget_set_can_default (button_add, TRUE); - button_remove = gtk_button_new_from_stock ("gtk-remove"); +#if HAVE_GTK3 + button_remove = servlist_icon_button_new (_("_Remove"), ICON_SERVLIST_REMOVE); +#endif +#if !HAVE_GTK3 + button_remove = gtk_button_new_from_stock (GTK_STOCK_REMOVE); +#endif g_signal_connect (G_OBJECT (button_remove), "clicked", G_CALLBACK (servlist_deletenet_cb), 0); gtk_widget_show (button_remove); @@ -2193,23 +2446,38 @@ servlist_open_networks (void) gtk_container_add (GTK_CONTAINER (vbuttonbox2), button_sort); gtk_widget_set_can_default (button_sort, TRUE); +#if HAVE_GTK3 + hseparator1 = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); +#elif !HAVE_GTK3 hseparator1 = gtk_hseparator_new (); +#endif gtk_widget_show (hseparator1); gtk_box_pack_start (GTK_BOX (vbox1), hseparator1, FALSE, TRUE, 4); +#if HAVE_GTK3 + hbuttonbox1 = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 hbuttonbox1 = gtk_hbutton_box_new (); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD); +#endif gtk_widget_show (hbuttonbox1); gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, FALSE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 8); - button_close = gtk_button_new_from_stock ("gtk-close"); +#if HAVE_GTK3 + button_close = servlist_icon_button_new (_("_Close"), ICON_SERVLIST_CLOSE); +#endif +#if !HAVE_GTK3 + button_close = gtk_button_new_from_stock (GTK_STOCK_CLOSE); +#endif gtk_widget_show (button_close); g_signal_connect (G_OBJECT (button_close), "clicked", G_CALLBACK (servlist_close_cb), 0); gtk_container_add (GTK_CONTAINER (hbuttonbox1), button_close); gtk_widget_set_can_default (button_close, TRUE); - button_connect = gtkutil_button (hbuttonbox1, GTK_STOCK_CONNECT, NULL, +button_connect = gtkutil_button (hbuttonbox1, ICON_SERVLIST_CONNECT, NULL, servlist_connect_cb, NULL, _("C_onnect")); gtk_widget_set_can_default (button_connect, TRUE); diff --git a/src/fe-gtk/setup.c b/src/fe-gtk/setup.c index b56e2c21..0402e27e 100644 --- a/src/fe-gtk/setup.c +++ b/src/fe-gtk/setup.c @@ -48,7 +48,7 @@ #endif #include "sexy-spell-entry.h" -GtkStyle *create_input_style (GtkStyle *); +InputStyle *create_input_style (InputStyle *); #define LABEL_INDENT 12 @@ -706,6 +706,74 @@ static const setting identd_settings[] = #define setup_set_int(pr,set,num) *((int *)pr+set->offset)=num #define setup_set_str(pr,set,str) strcpy(((char *)pr)+set->offset,str) +typedef enum +{ + SETUP_ALIGN_START, + SETUP_ALIGN_CENTER, + SETUP_ALIGN_FILL +} setup_align; + +#if HAVE_GTK3 +static GtkAlign +setup_align_to_gtk (setup_align align) +{ + switch (align) + { + case SETUP_ALIGN_FILL: + return GTK_ALIGN_FILL; + case SETUP_ALIGN_CENTER: + return GTK_ALIGN_CENTER; + case SETUP_ALIGN_START: + default: + return GTK_ALIGN_START; + } +} +#endif + +static void +setup_table_attach (GtkWidget *table, GtkWidget *child, + guint left_attach, guint right_attach, + guint top_attach, guint bottom_attach, + gboolean hexpand, gboolean vexpand, + setup_align halign, setup_align valign, + guint xpad, guint ypad) +{ +#if HAVE_GTK3 + gtk_widget_set_hexpand (child, hexpand); + gtk_widget_set_vexpand (child, vexpand); + gtk_widget_set_halign (child, setup_align_to_gtk (halign)); + gtk_widget_set_valign (child, setup_align_to_gtk (valign)); + gtk_widget_set_margin_start (child, xpad); + gtk_widget_set_margin_end (child, xpad); + gtk_widget_set_margin_top (child, ypad); + gtk_widget_set_margin_bottom (child, ypad); + + gtk_grid_attach (GTK_GRID (table), child, left_attach, top_attach, + right_attach - left_attach, bottom_attach - top_attach); +#else + GtkAttachOptions xoptions = 0; + GtkAttachOptions yoptions = 0; + + if (hexpand) + xoptions |= GTK_EXPAND; + else + xoptions |= GTK_SHRINK; + if (halign == SETUP_ALIGN_FILL) + xoptions |= GTK_FILL; + + if (vexpand) + yoptions |= GTK_EXPAND; + else + yoptions |= GTK_SHRINK; + if (valign == SETUP_ALIGN_FILL) + yoptions |= GTK_FILL; + + gtk_table_attach (GTK_TABLE (table), child, left_attach, right_attach, + top_attach, bottom_attach, xoptions, yoptions, + xpad, ypad); +#endif +} + static void setup_3oggle_cb (GtkToggleButton *but, unsigned int *setting) @@ -727,8 +795,14 @@ setup_headlabel (GtkWidget *tab, int row, int col, char *text) label = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (label), buf); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (tab), label, col, col + 1, row, row + 1, 0, 0, 4, 0); +#endif + setup_table_attach (tab, label, col, col + 1, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, 4, 0); } static void @@ -748,34 +822,43 @@ setup_create_3oggle (GtkWidget *tab, int row, const setting *set) int *offsets = (int *)set->list; label = gtk_label_new (_(set->label)); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); +#endif if (set->tooltip) { gtk_widget_set_tooltip_text (label, _(set->tooltip)); } - gtk_table_attach (GTK_TABLE (tab), label, 2, 3, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); + setup_table_attach (tab, label, 2, 3, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); wid = gtk_check_button_new (); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid), setup_get_int3 (&setup_prefs, offsets[0])); g_signal_connect (G_OBJECT (wid), "toggled", G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[0]); - gtk_table_attach (GTK_TABLE (tab), wid, 3, 4, row, row + 1, 0, 0, 0, 0); + setup_table_attach (tab, wid, 3, 4, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_CENTER, SETUP_ALIGN_CENTER, 0, 0); wid = gtk_check_button_new (); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid), setup_get_int3 (&setup_prefs, offsets[1])); g_signal_connect (G_OBJECT (wid), "toggled", G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[1]); - gtk_table_attach (GTK_TABLE (tab), wid, 4, 5, row, row + 1, 0, 0, 0, 0); + setup_table_attach (tab, wid, 4, 5, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_CENTER, SETUP_ALIGN_CENTER, 0, 0); wid = gtk_check_button_new (); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wid), setup_get_int3 (&setup_prefs, offsets[2])); g_signal_connect (G_OBJECT (wid), "toggled", G_CALLBACK (setup_3oggle_cb), ((int *)&setup_prefs) + offsets[2]); - gtk_table_attach (GTK_TABLE (tab), wid, 5, 6, row, row + 1, 0, 0, 0, 0); + setup_table_attach (tab, wid, 5, 6, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_CENTER, SETUP_ALIGN_CENTER, 0, 0); } static void @@ -813,8 +896,8 @@ setup_create_toggleR (GtkWidget *tab, int row, const setting *set) G_CALLBACK (setup_toggle_cb), (gpointer)set); if (set->tooltip) gtk_widget_set_tooltip_text (wid, _(set->tooltip)); - gtk_table_attach (GTK_TABLE (tab), wid, 4, 5, row, row + 1, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); + setup_table_attach (tab, wid, 4, 5, row, row + 1, TRUE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); } static GtkWidget * @@ -829,8 +912,8 @@ setup_create_toggleL (GtkWidget *tab, int row, const setting *set) G_CALLBACK (setup_toggle_cb), (gpointer)set); if (set->tooltip) gtk_widget_set_tooltip_text (wid, _(set->tooltip)); - gtk_table_attach (GTK_TABLE (tab), wid, 2, row==6 ? 6 : 4, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); + setup_table_attach (tab, wid, 2, row==6 ? 6 : 4, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, LABEL_INDENT, 0); return wid; } @@ -858,20 +941,37 @@ setup_spin_cb (GtkSpinButton *spin, const setting *set) static GtkWidget * setup_create_spin (GtkWidget *table, int row, const setting *set) { - GtkWidget *label, *wid, *rbox, *align; + GtkWidget *label, *wid, *rbox; +#if !HAVE_GTK3 + GtkWidget *align; +#endif char *text; label = gtk_label_new (_(set->label)); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); +#endif + setup_table_attach (table, label, 2, 3, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); +#if HAVE_GTK3 + rbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); + gtk_widget_set_halign (rbox, GTK_ALIGN_START); + gtk_widget_set_valign (rbox, GTK_ALIGN_CENTER); + setup_table_attach (table, rbox, 3, 4, row, row + 1, TRUE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); +#elif !HAVE_GTK3 align = gtk_alignment_new (0.0, 0.5, 0.0, 0.0); - gtk_table_attach (GTK_TABLE (table), align, 3, 4, row, row + 1, - GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); + setup_table_attach (table, align, 3, 4, row, row + 1, TRUE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); - rbox = gtk_hbox_new (0, 0); + rbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); gtk_container_add (GTK_CONTAINER (align), rbox); +#endif wid = gtk_spin_button_new_with_range (0, set->extra, 1); g_object_set_data (G_OBJECT (wid), "lbl", label); @@ -909,11 +1009,11 @@ setup_apply_trans (int *tag) } static void -setup_hscale_cb (GtkHScale *wid, const setting *set) +setup_hscale_cb (GtkRange *wid, const setting *set) { static int tag = 0; - setup_set_int (&setup_prefs, set, (int) gtk_range_get_value (GTK_RANGE (wid))); + setup_set_int (&setup_prefs, set, (int) gtk_range_get_value (wid)); if (tag == 0) { @@ -927,17 +1027,27 @@ setup_create_hscale (GtkWidget *table, int row, const setting *set) GtkWidget *wid; wid = gtk_label_new (_(set->label)); +#if HAVE_GTK3 + gtk_widget_set_halign (wid, GTK_ALIGN_START); + gtk_widget_set_valign (wid, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); +#endif + setup_table_attach (table, wid, 2, 3, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); +#if HAVE_GTK3 + wid = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0., 255., 1.); +#elif !HAVE_GTK3 wid = gtk_hscale_new_with_range (0., 255., 1.); +#endif gtk_scale_set_value_pos (GTK_SCALE (wid), GTK_POS_RIGHT); gtk_range_set_value (GTK_RANGE (wid), setup_get_int (&setup_prefs, set)); g_signal_connect (G_OBJECT(wid), "value_changed", G_CALLBACK (setup_hscale_cb), (gpointer)set); - gtk_table_attach (GTK_TABLE (table), wid, 3, 6, row, row + 1, - GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + setup_table_attach (table, wid, 3, 6, row, row + 1, TRUE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); #ifndef WIN32 /* Windows always supports this */ /* Only used for transparency currently */ @@ -986,13 +1096,23 @@ setup_create_radio (GtkWidget *table, int row, const setting *set) GSList *group; wid = gtk_label_new (_(set->label)); +#if HAVE_GTK3 + gtk_widget_set_halign (wid, GTK_ALIGN_START); + gtk_widget_set_valign (wid, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); +#endif + setup_table_attach (table, wid, 2, 3, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); - hbox = gtk_hbox_new (0, 0); - gtk_table_attach (GTK_TABLE (table), hbox, 3, 4, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); +#if HAVE_GTK3 + hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); +#elif !HAVE_GTK3 + hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); +#endif + setup_table_attach (table, hbox, 3, 4, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); i = 0; group = NULL; @@ -1049,9 +1169,15 @@ setup_create_id_menu (GtkWidget *table, char *label, int row, char *dest) }; wid = gtk_label_new (label); +#if HAVE_GTK3 + gtk_widget_set_halign (wid, GTK_ALIGN_START); + gtk_widget_set_valign (wid, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); +#endif + setup_table_attach (table, wid, 2, 3, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); wid = gtk_option_menu_new (); menu = gtk_menu_new (); @@ -1081,8 +1207,8 @@ setup_create_id_menu (GtkWidget *table, char *label, int row, char *dest) gtk_option_menu_set_menu (GTK_OPTION_MENU (wid), menu); gtk_option_menu_set_history (GTK_OPTION_MENU (wid), def); - gtk_table_attach (GTK_TABLE (table), wid, 3, 4, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); + setup_table_attach (table, wid, 3, 4, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); } */ @@ -1095,9 +1221,15 @@ setup_create_menu (GtkWidget *table, int row, const setting *set) int i; wid = gtk_label_new (_(set->label)); +#if HAVE_GTK3 + gtk_widget_set_halign (wid, GTK_ALIGN_START); + gtk_widget_set_valign (wid, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); +#endif + setup_table_attach (table, wid, 2, 3, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); cbox = gtk_combo_box_text_new (); @@ -1109,10 +1241,14 @@ setup_create_menu (GtkWidget *table, int row, const setting *set) g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (setup_menu_cb), (gpointer)set); - box = gtk_hbox_new (0, 0); +#if HAVE_GTK3 + box = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); +#elif !HAVE_GTK3 + box = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); +#endif gtk_box_pack_start (GTK_BOX (box), cbox, 0, 0, 0); - gtk_table_attach (GTK_TABLE (table), box, 3, 4, row, row + 1, - GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); + setup_table_attach (table, box, 3, 4, row, row + 1, TRUE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); } static void @@ -1143,6 +1279,7 @@ setup_browsefile_cb (GtkWidget *button, GtkWidget *entry) entry, NULL, filter, filter_type|FRF_RECENTLYUSED|FRF_MODAL); } +#if !HAVE_GTK3 static void setup_fontsel_destroy (GtkWidget *button, GtkFontSelectionDialog *dialog) { @@ -1171,6 +1308,28 @@ setup_fontsel_cancel (GtkWidget *button, GtkFontSelectionDialog *dialog) gtk_widget_destroy (GTK_WIDGET (dialog)); font_dialog = NULL; } +#endif + +#if HAVE_GTK3 +static void +setup_fontchooser_response (GtkDialog *dialog, gint response, GtkWidget *entry) +{ + if (response == GTK_RESPONSE_OK) + { + char *font_name; + + font_name = gtk_font_chooser_get_font (GTK_FONT_CHOOSER (dialog)); + if (font_name) + { + gtk_entry_set_text (GTK_ENTRY (entry), font_name); + g_free (font_name); + } + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); + font_dialog = NULL; +} +#endif static void setup_browsefolder_cb (GtkWidget *button, GtkEntry *entry) @@ -1181,6 +1340,24 @@ setup_browsefolder_cb (GtkWidget *button, GtkEntry *entry) static void setup_browsefont_cb (GtkWidget *button, GtkWidget *entry) { +#if HAVE_GTK3 + GtkWidget *dialog; + const char *font_name; + + dialog = gtk_font_chooser_dialog_new (_("Select font"), GTK_WINDOW (setup_window)); + font_dialog = dialog; /* global var */ + + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + font_name = gtk_entry_get_text (GTK_ENTRY (entry)); + if (font_name[0]) + gtk_font_chooser_set_font (GTK_FONT_CHOOSER (dialog), font_name); + + g_signal_connect (G_OBJECT (dialog), "response", + G_CALLBACK (setup_fontchooser_response), entry); + + gtk_widget_show (dialog); +#elif !HAVE_GTK3 GtkFontSelection *sel; GtkFontSelectionDialog *dialog; GtkWidget *ok_button; @@ -1207,6 +1384,7 @@ setup_browsefont_cb (GtkWidget *button, GtkWidget *entry) G_CALLBACK (setup_fontsel_cancel), dialog); gtk_widget_show (GTK_WIDGET (dialog)); +#endif } static void @@ -1244,9 +1422,9 @@ setup_entry_cb (GtkEntry *entry, setting *set) static void setup_create_label (GtkWidget *table, int row, const setting *set) { - gtk_table_attach (GTK_TABLE (table), setup_create_italic_label (_(set->label)), - set->extra ? 1 : 3, 5, row, row + 1, GTK_FILL, - GTK_SHRINK | GTK_FILL, 0, 0); + setup_table_attach (table, setup_create_italic_label (_(set->label)), + set->extra ? 1 : 3, 5, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); } static GtkWidget * @@ -1256,9 +1434,15 @@ setup_create_entry (GtkWidget *table, int row, const setting *set) GtkWidget *wid, *bwid; label = gtk_label_new (_(set->label)); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); +#endif + setup_table_attach (table, label, 2, 3, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); wid = gtk_entry_new (); g_object_set_data (G_OBJECT (wid), "lbl", label); @@ -1283,15 +1467,15 @@ setup_create_entry (GtkWidget *table, int row, const setting *set) gtk_widget_set_sensitive (wid, FALSE); if (set->type == ST_ENTRY) - gtk_table_attach (GTK_TABLE (table), wid, 3, 6, row, row + 1, - GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + setup_table_attach (table, wid, 3, 6, row, row + 1, TRUE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); else { - gtk_table_attach (GTK_TABLE (table), wid, 3, 5, row, row + 1, - GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0); + setup_table_attach (table, wid, 3, 5, row, row + 1, TRUE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_CENTER, 0, 0); bwid = gtk_button_new_with_label (_("Browse...")); - gtk_table_attach (GTK_TABLE (table), bwid, 5, 6, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_FILL, 0, 0); + setup_table_attach (table, bwid, 5, 6, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); if (set->type == ST_EFILE) g_signal_connect (G_OBJECT (bwid), "clicked", G_CALLBACK (setup_browsefile_cb), wid); @@ -1319,17 +1503,22 @@ setup_create_header (GtkWidget *table, int row, char *labeltext) label = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (label), buf); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 0, 4, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 5); +#endif + setup_table_attach (table, label, 0, 4, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, 0, 5); } static void setup_create_button (GtkWidget *table, int row, char *label, GCallback callback) { GtkWidget *but = gtk_button_new_with_label (label); - gtk_table_attach (GTK_TABLE (table), but, 2, 3, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 5); + setup_table_attach (table, but, 2, 3, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 5); g_signal_connect (G_OBJECT (but), "clicked", callback, NULL); } @@ -1338,10 +1527,15 @@ setup_create_frame (void) { GtkWidget *tab; - tab = gtk_table_new (3, 2, FALSE); + tab = gtkutil_grid_new (3, 2, FALSE); gtk_container_set_border_width (GTK_CONTAINER (tab), 6); +#if HAVE_GTK3 + gtk_grid_set_row_spacing (GTK_GRID (tab), 2); + gtk_grid_set_column_spacing (GTK_GRID (tab), 3); +#else gtk_table_set_row_spacings (GTK_TABLE (tab), 2); gtk_table_set_col_spacings (GTK_TABLE (tab), 3); +#endif return tab; } @@ -1462,9 +1656,15 @@ setup_create_dark_mode_menu (GtkWidget *table, int row, const setting *set) int i; wid = gtk_label_new (_(set->label)); +#if HAVE_GTK3 + gtk_widget_set_halign (wid, GTK_ALIGN_START); + gtk_widget_set_valign (wid, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (wid), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), wid, 2, 3, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); +#endif + setup_table_attach (table, wid, 2, 3, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); cbox = gtk_combo_box_text_new (); @@ -1476,18 +1676,24 @@ setup_create_dark_mode_menu (GtkWidget *table, int row, const setting *set) g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (setup_dark_mode_menu_cb), (gpointer)set); - box = gtk_hbox_new (0, 0); +#if HAVE_GTK3 + box = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); +#elif !HAVE_GTK3 + box = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0); +#endif gtk_box_pack_start (GTK_BOX (box), cbox, 0, 0, 0); - gtk_table_attach (GTK_TABLE (table), box, 3, 4, row, row + 1, - GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0); + setup_table_attach (table, box, 3, 4, row, row + 1, TRUE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); return cbox; } static void -setup_color_button_apply (GtkWidget *button, const GdkColor *color) +setup_color_button_apply (GtkWidget *button, const PaletteColor *color) { GtkWidget *target = g_object_get_data (G_OBJECT (button), "zoitechat-color-box"); + GtkWidget *apply_widget = GTK_IS_WIDGET (target) ? target : button; +#if !HAVE_GTK3 GtkStateType states[] = { GTK_STATE_NORMAL, GTK_STATE_PRELIGHT, @@ -1496,26 +1702,81 @@ setup_color_button_apply (GtkWidget *button, const GdkColor *color) GTK_STATE_INSENSITIVE }; guint i; - GtkWidget *apply_widget = GTK_IS_WIDGET (target) ? target : button; +#endif +#if HAVE_GTK3 + gtkutil_apply_palette (apply_widget, color, NULL, NULL); +#else for (i = 0; i < G_N_ELEMENTS (states); i++) gtk_widget_modify_bg (apply_widget, states[i], color); +#endif if (apply_widget != button) +#if HAVE_GTK3 + gtkutil_apply_palette (button, color, NULL, NULL); +#else for (i = 0; i < G_N_ELEMENTS (states); i++) gtk_widget_modify_bg (button, states[i], color); +#endif gtk_widget_queue_draw (button); } +#if HAVE_GTK3 +typedef struct +{ + GtkWidget *button; + PaletteColor *color; +} setup_color_dialog_data; + +static void +setup_rgba_from_palette (const PaletteColor *color, GdkRGBA *rgba) +{ + guint16 red, green, blue; + char color_string[16]; + + palette_color_get_rgb16 (color, &red, &green, &blue); + g_snprintf (color_string, sizeof (color_string), "#%04x%04x%04x", + red, green, blue); + if (!gdk_rgba_parse (rgba, color_string)) + { + rgba->red = red / 65535.0; + rgba->green = green / 65535.0; + rgba->blue = blue / 65535.0; + rgba->alpha = 1.0; + } +} + +static void +setup_color_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data) +{ + setup_color_dialog_data *data = user_data; + + if (response_id == GTK_RESPONSE_OK) + { + GdkRGBA rgba; + + gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog), &rgba); + *data->color = rgba; + color_change = TRUE; + setup_color_button_apply (data->button, data->color); + + if (fe_dark_mode_is_enabled_for (setup_prefs.hex_gui_dark_mode)) + palette_dark_set_color ((int)(data->color - colors), data->color); + else + palette_user_set_color ((int)(data->color - colors), data->color); + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); + g_free (data); +} +#else static void setup_color_ok_cb (GtkWidget *button, GtkWidget *dialog) { GtkColorSelectionDialog *cdialog = GTK_COLOR_SELECTION_DIALOG (dialog); - GdkColor *col; - GdkColor old_color; + PaletteColor *col; col = g_object_get_data (G_OBJECT (button), "c"); - old_color = *col; button = g_object_get_data (G_OBJECT (button), "b"); @@ -1529,13 +1790,8 @@ setup_color_ok_cb (GtkWidget *button, GtkWidget *dialog) gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (gtk_color_selection_dialog_get_color_selection (cdialog)), col); - gdk_colormap_alloc_color (gtk_widget_get_colormap (button), col, TRUE, TRUE); - setup_color_button_apply (button, col); - /* is this line correct?? */ - gdk_colormap_free_colors (gtk_widget_get_colormap (button), &old_color, 1); - /* Persist custom colors for the palette the user is editing. */ if (fe_dark_mode_is_enabled_for (setup_prefs.hex_gui_dark_mode)) palette_dark_set_color ((int)(col - colors), col); @@ -1544,13 +1800,33 @@ setup_color_ok_cb (GtkWidget *button, GtkWidget *dialog) gtk_widget_destroy (dialog); } +#endif static void setup_color_cb (GtkWidget *button, gpointer userdata) { +#if HAVE_GTK3 + GtkWidget *dialog; + PaletteColor *color; + GdkRGBA rgba; + setup_color_dialog_data *data; + + color = &colors[GPOINTER_TO_INT (userdata)]; + + dialog = gtk_color_chooser_dialog_new (_("Select color"), GTK_WINDOW (setup_window)); + setup_rgba_from_palette (color, &rgba); + gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (dialog), &rgba); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + data = g_new0 (setup_color_dialog_data, 1); + data->button = button; + data->color = color; + g_signal_connect (dialog, "response", G_CALLBACK (setup_color_response_cb), data); + gtk_widget_show (dialog); +#else GtkWidget *dialog, *cancel_button, *ok_button, *help_button; GtkColorSelectionDialog *cdialog; - GdkColor *color; + PaletteColor *color; color = &colors[GPOINTER_TO_INT (userdata)]; @@ -1577,6 +1853,7 @@ setup_color_cb (GtkWidget *button, gpointer userdata) g_object_unref (cancel_button); g_object_unref (ok_button); g_object_unref (help_button); +#endif } static void @@ -1585,7 +1862,9 @@ setup_create_color_button (GtkWidget *table, int num, int row, int col) GtkWidget *but; GtkWidget *label; GtkWidget *box; +#if !HAVE_GTK3 GtkWidget *alignment; +#endif char buf[64]; if (num > 31) @@ -1602,19 +1881,24 @@ setup_create_color_button (GtkWidget *table, int num, int row, int col) gtk_event_box_set_visible_window (GTK_EVENT_BOX (box), TRUE); gtk_container_add (GTK_CONTAINER (box), label); gtk_container_add (GTK_CONTAINER (but), box); +#if HAVE_GTK3 + gtk_widget_set_halign (box, GTK_ALIGN_CENTER); + gtk_widget_set_valign (box, GTK_ALIGN_CENTER); +#else alignment = gtk_bin_get_child (GTK_BIN (but)); if (GTK_IS_ALIGNMENT (alignment)) { gtk_alignment_set (GTK_ALIGNMENT (alignment), 0.5, 0.5, 1.0, 1.0); gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 0, 0); } +#endif gtk_widget_show (label); gtk_widget_show (box); /* win32 build uses this to turn off themeing */ g_object_set_data (G_OBJECT (but), "zoitechat-color", (gpointer)1); g_object_set_data (G_OBJECT (but), "zoitechat-color-box", box); - gtk_table_attach (GTK_TABLE (table), but, col, col+1, row, row+1, - GTK_SHRINK, GTK_SHRINK, 0, 0); + setup_table_attach (table, but, col, col + 1, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_CENTER, SETUP_ALIGN_CENTER, 0, 0); g_signal_connect (G_OBJECT (but), "clicked", G_CALLBACK (setup_color_cb), GINT_TO_POINTER (num)); setup_color_button_apply (but, &colors[num]); @@ -1629,9 +1913,15 @@ setup_create_other_colorR (char *text, int num, int row, GtkWidget *tab) GtkWidget *label; label = gtk_label_new (text); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (tab), label, 5, 9, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); +#endif + setup_table_attach (tab, label, 5, 9, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); setup_create_color_button (tab, num, row, 9); } @@ -1641,9 +1931,15 @@ setup_create_other_color (char *text, int num, int row, GtkWidget *tab) GtkWidget *label; label = gtk_label_new (text); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (tab), label, 2, 3, row, row + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); +#endif + setup_table_attach (tab, label, 2, 3, row, row + 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); setup_create_color_button (tab, num, row, 3); } @@ -1655,29 +1951,46 @@ setup_create_color_page (void) GtkWidget *tab, *box, *label; int i; - box = gtk_vbox_new (FALSE, 0); + box = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (box), 6); - tab = gtk_table_new (9, 2, FALSE); + tab = gtkutil_grid_new (9, 2, FALSE); gtk_container_set_border_width (GTK_CONTAINER (tab), 6); +#if HAVE_GTK3 + gtk_grid_set_row_spacing (GTK_GRID (tab), 2); + gtk_grid_set_column_spacing (GTK_GRID (tab), 3); +#else gtk_table_set_row_spacings (GTK_TABLE (tab), 2); gtk_table_set_col_spacings (GTK_TABLE (tab), 3); +#endif gtk_container_add (GTK_CONTAINER (box), tab); setup_create_header (tab, 0, N_("Text Colors")); label = gtk_label_new (_("mIRC colors:")); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (tab), label, 2, 3, 1, 2, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); +#endif + setup_table_attach (tab, label, 2, 3, 1, 2, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); for (i = 0; i < 16; i++) setup_create_color_button (tab, i, 1, i+3); label = gtk_label_new (_("Local colors:")); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (tab), label, 2, 3, 2, 3, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); +#endif + setup_table_attach (tab, label, 2, 3, 2, 3, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, + LABEL_INDENT, 0); for (i = 16; i < 32; i++) setup_create_color_button (tab, i, 2, (i+3) - 16); @@ -1703,9 +2016,15 @@ setup_create_color_page (void) setup_create_header (tab, 15, N_("Color Stripping")); /* label = gtk_label_new (_("Strip colors from:")); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (tab), label, 2, 3, 16, 17, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, LABEL_INDENT, 0); */ +#endif + setup_table_attach (tab, label, 2, 3, 16, 17, FALSE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, + LABEL_INDENT, 0); */ for (i = 0; i < 3; i++) { @@ -1905,7 +2224,11 @@ setup_create_theme_page (void) ui = g_new0 (setup_theme_ui, 1); - box = gtk_vbox_new (FALSE, 6); +#if HAVE_GTK3 + box = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 6); +#elif !HAVE_GTK3 + box = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 6); +#endif gtk_container_set_border_width (GTK_CONTAINER (box), 6); themes_dir = g_build_filename (get_xdir (), "themes", NULL); @@ -1913,12 +2236,21 @@ setup_create_theme_page (void) label = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (label), markup); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); +#endif gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0); g_free (markup); g_free (themes_dir); - hbox = gtk_hbox_new (FALSE, 6); +#if HAVE_GTK3 + hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 6); +#elif !HAVE_GTK3 + hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 6); +#endif gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0); ui->combo = gtk_combo_box_text_new (); @@ -1926,7 +2258,11 @@ setup_create_theme_page (void) g_signal_connect (G_OBJECT (ui->combo), "changed", G_CALLBACK (setup_theme_selection_changed), ui); - button_box = gtk_hbox_new (FALSE, 6); +#if HAVE_GTK3 + button_box = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 6); +#elif !HAVE_GTK3 + button_box = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 6); +#endif gtk_box_pack_start (GTK_BOX (hbox), button_box, FALSE, FALSE, 0); ui->apply_button = gtk_button_new_with_mnemonic (_("_Apply Theme")); @@ -1945,7 +2281,12 @@ setup_create_theme_page (void) G_CALLBACK (setup_theme_open_folder_cb), ui); ui->status_label = gtk_label_new (NULL); +#if HAVE_GTK3 + gtk_widget_set_halign (ui->status_label, GTK_ALIGN_START); + gtk_widget_set_valign (ui->status_label, GTK_ALIGN_CENTER); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (ui->status_label), 0.0, 0.5); +#endif gtk_box_pack_start (GTK_BOX (box), ui->status_label, FALSE, FALSE, 0); setup_theme_populate (ui); @@ -2138,11 +2479,19 @@ setup_create_sound_page (void) GtkWidget *sound_play; GtkTreeSelection *sel; - vbox1 = gtk_vbox_new (FALSE, 0); +#if HAVE_GTK3 + vbox1 = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); +#elif !HAVE_GTK3 + vbox1 = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); +#endif gtk_container_set_border_width (GTK_CONTAINER (vbox1), 6); gtk_widget_show (vbox1); - vbox2 = gtk_vbox_new (FALSE, 0); +#if HAVE_GTK3 + vbox2 = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); +#elif !HAVE_GTK3 + vbox2 = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); +#endif gtk_widget_show (vbox2); gtk_container_add (GTK_CONTAINER (vbox1), vbox2); @@ -2165,46 +2514,42 @@ setup_create_sound_page (void) gtk_container_add (GTK_CONTAINER (scrolledwindow1), sound_tree); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (sound_tree), TRUE); - table1 = gtk_table_new (2, 3, FALSE); + table1 = gtkutil_grid_new (2, 3, FALSE); gtk_widget_show (table1); gtk_box_pack_start (GTK_BOX (vbox2), table1, FALSE, TRUE, 8); +#if HAVE_GTK3 + gtk_grid_set_row_spacing (GTK_GRID (table1), 2); + gtk_grid_set_column_spacing (GTK_GRID (table1), 4); +#else gtk_table_set_row_spacings (GTK_TABLE (table1), 2); gtk_table_set_col_spacings (GTK_TABLE (table1), 4); +#endif sound_label = gtk_label_new_with_mnemonic (_("Sound file:")); gtk_widget_show (sound_label); - gtk_table_attach (GTK_TABLE (table1), sound_label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_misc_set_alignment (GTK_MISC (sound_label), 0, 0.5); + setup_table_attach (table1, sound_label, 0, 1, 0, 1, FALSE, FALSE, + SETUP_ALIGN_START, SETUP_ALIGN_CENTER, 0, 0); sndfile_entry = gtk_entry_new (); g_signal_connect (G_OBJECT (sndfile_entry), "changed", G_CALLBACK (setup_snd_changed_cb), sound_tree); gtk_widget_show (sndfile_entry); - gtk_table_attach (GTK_TABLE (table1), sndfile_entry, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + setup_table_attach (table1, sndfile_entry, 0, 1, 1, 2, TRUE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); sound_browse = gtk_button_new_with_mnemonic (_("_Browse...")); g_signal_connect (G_OBJECT (sound_browse), "clicked", G_CALLBACK (setup_snd_browse_cb), sndfile_entry); gtk_widget_show (sound_browse); - gtk_table_attach (GTK_TABLE (table1), sound_browse, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + setup_table_attach (table1, sound_browse, 1, 2, 1, 2, FALSE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); -#ifdef GTK_STOCK_MEDIA_PLAY - sound_play = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY); -#else - sound_play = gtk_button_new_with_mnemonic (_("_Play")); -#endif + sound_play = gtkutil_button_new_from_stock ("gtk-media-play", _("_Play")); g_signal_connect (G_OBJECT (sound_play), "clicked", G_CALLBACK (setup_snd_play_cb), sndfile_entry); gtk_widget_show (sound_play); - gtk_table_attach (GTK_TABLE (table1), sound_play, 2, 3, 1, 2, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); + setup_table_attach (table1, sound_play, 2, 3, 1, 2, FALSE, FALSE, + SETUP_ALIGN_FILL, SETUP_ALIGN_FILL, 0, 0); setup_snd_row_cb (sel, NULL); @@ -2218,14 +2563,27 @@ setup_add_page (const char *title, GtkWidget *book, GtkWidget *tab) GtkScrolledWindow *sw; char buf[128]; - vvbox = gtk_vbox_new (FALSE, 0); +#if HAVE_GTK3 + vvbox = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); +#elif !HAVE_GTK3 + vvbox = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0); +#endif /* label */ label = gtk_label_new (NULL); g_snprintf (buf, sizeof (buf), "%s", _(title)); gtk_label_set_markup (GTK_LABEL (label), buf); +#if HAVE_GTK3 + gtk_widget_set_halign (label, GTK_ALIGN_START); + gtk_widget_set_valign (label, GTK_ALIGN_CENTER); + gtk_widget_set_margin_start (label, 2); + gtk_widget_set_margin_end (label, 2); + gtk_widget_set_margin_top (label, 1); + gtk_widget_set_margin_bottom (label, 1); +#elif !HAVE_GTK3 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_misc_set_padding (GTK_MISC (label), 2, 1); +#endif gtk_box_pack_start (GTK_BOX (vvbox), label, FALSE, FALSE, 2); gtk_container_add (GTK_CONTAINER (vvbox), tab); @@ -2314,7 +2672,7 @@ setup_create_pages (GtkWidget *box) gtk_notebook_set_show_tabs (GTK_NOTEBOOK (book), FALSE); gtk_notebook_set_show_border (GTK_NOTEBOOK (book), FALSE); - gtk_container_add (GTK_CONTAINER (box), book); + gtk_box_pack_start (GTK_BOX (box), book, TRUE, TRUE, 0); return book; } @@ -2427,9 +2785,14 @@ setup_create_tree (GtkWidget *box, GtkWidget *book) static void setup_apply_entry_style (GtkWidget *entry) { +#if HAVE_GTK3 + gtkutil_apply_palette (entry, &colors[COL_BG], &colors[COL_FG], + input_style->font_desc); +#else gtk_widget_modify_base (entry, GTK_STATE_NORMAL, &colors[COL_BG]); gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &colors[COL_FG]); gtk_widget_modify_font (entry, input_style->font_desc); +#endif } static void @@ -2438,10 +2801,28 @@ setup_apply_to_sess (session_gui *gui) mg_update_xtext (gui->xtext); chanview_apply_theme ((chanview *) gui->chanview); - if (prefs.hex_gui_ulist_style) - gtk_widget_modify_font (gui->user_tree, input_style->font_desc); +#if !HAVE_GTK3 + if (prefs.hex_gui_ulist_style) + gtk_widget_modify_font (gui->user_tree, input_style->font_desc); +#endif - if (prefs.hex_gui_ulist_style || fe_dark_mode_is_enabled ()) +#if HAVE_GTK3 + { + const PaletteColor *bg = NULL; + const PaletteColor *fg = NULL; + const PangoFontDescription *font = NULL; + + if (prefs.hex_gui_ulist_style || fe_dark_mode_is_enabled ()) + bg = &colors[COL_BG]; + if (fe_dark_mode_is_enabled ()) + fg = &colors[COL_FG]; + if (input_style) + font = input_style->font_desc; + + gtkutil_apply_palette (gui->user_tree, bg, fg, font); + } +#else + if (prefs.hex_gui_ulist_style || fe_dark_mode_is_enabled ()) { gtk_widget_modify_base (gui->user_tree, GTK_STATE_NORMAL, &colors[COL_BG]); if (fe_dark_mode_is_enabled ()) @@ -2454,9 +2835,36 @@ setup_apply_to_sess (session_gui *gui) gtk_widget_modify_base (gui->user_tree, GTK_STATE_NORMAL, NULL); gtk_widget_modify_text (gui->user_tree, GTK_STATE_NORMAL, NULL); } +#endif if (prefs.hex_gui_input_style) { +#if HAVE_GTK3 + char buf[128]; + GtkCssProvider *provider = gtk_css_provider_new (); + GtkStyleContext *context; + char *color_string = gdk_rgba_to_string (&colors[COL_FG]); + + g_snprintf (buf, sizeof (buf), ".zoitechat-inputbox { caret-color: %s; }", + color_string); + gtk_css_provider_load_from_data (provider, buf, -1, NULL); + g_free (color_string); + + context = gtk_widget_get_style_context (gui->input_box); + gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + context = gtk_widget_get_style_context (gui->limit_entry); + gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + context = gtk_widget_get_style_context (gui->key_entry); + gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + context = gtk_widget_get_style_context (gui->topic_entry); + gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + g_object_unref (provider); +#else extern char cursor_color_rc[]; char buf[256]; sprintf (buf, cursor_color_rc, @@ -2464,6 +2872,7 @@ setup_apply_to_sess (session_gui *gui) (colors[COL_FG].green >> 8), (colors[COL_FG].blue >> 8)); gtk_rc_parse_string (buf); +#endif setup_apply_entry_style (gui->input_box); setup_apply_entry_style (gui->limit_entry); @@ -2718,27 +3127,40 @@ setup_window_open (void) g_snprintf(buf, sizeof(buf), _("Preferences - %s"), _(DISPLAY_NAME)); win = gtkutil_window_new (buf, "prefs", 0, 600, 2); - vbox = gtk_vbox_new (FALSE, 5); +#if HAVE_GTK3 + vbox = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 5); +#elif !HAVE_GTK3 + vbox = gtkutil_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 5); +#endif gtk_container_set_border_width (GTK_CONTAINER (vbox), 6); gtk_container_add (GTK_CONTAINER (win), vbox); - hbox = gtk_hbox_new (FALSE, 4); - gtk_container_add (GTK_CONTAINER (vbox), hbox); +#if HAVE_GTK3 + hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 4); +#elif !HAVE_GTK3 + hbox = gtkutil_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 4); +#endif + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); setup_create_tree (hbox, setup_create_pages (hbox)); /* prepare the button box */ +#if HAVE_GTK3 + hbbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbbox), GTK_BUTTONBOX_END); +#elif !HAVE_GTK3 hbbox = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbbox), GTK_BUTTONBOX_END); +#endif gtk_box_set_spacing (GTK_BOX (hbbox), 4); gtk_box_pack_end (GTK_BOX (vbox), hbbox, FALSE, FALSE, 0); - cancel_button = wid = gtk_button_new_from_stock (GTK_STOCK_CANCEL); + cancel_button = wid = gtkutil_button_new_from_stock ("gtk-cancel", _("_Cancel")); g_signal_connect (G_OBJECT (wid), "clicked", G_CALLBACK (gtkutil_destroy), win); gtk_box_pack_start (GTK_BOX (hbbox), wid, FALSE, FALSE, 0); - wid = gtk_button_new_from_stock (GTK_STOCK_OK); + wid = gtkutil_button_new_from_stock ("gtk-ok", _("_OK")); g_signal_connect (G_OBJECT (wid), "clicked", G_CALLBACK (setup_ok_cb), win); gtk_box_pack_start (GTK_BOX (hbbox), wid, FALSE, FALSE, 0); diff --git a/src/fe-gtk/sexy-spell-entry.c b/src/fe-gtk/sexy-spell-entry.c index 1c97837d..74a1ff8e 100644 --- a/src/fe-gtk/sexy-spell-entry.c +++ b/src/fe-gtk/sexy-spell-entry.c @@ -49,6 +49,26 @@ #include "../common/zoitechatc.h" #include "palette.h" #include "xtext.h" +#include "gtkutil.h" + +#ifndef HAVE_GTK3 +#if GTK_MAJOR_VERSION >= 3 +#define HAVE_GTK3 1 +#else +#define HAVE_GTK3 0 +#endif +#endif + +#if HAVE_GTK3 +#define ICON_ADD "list-add" +#define ICON_REMOVE "list-remove" +#define ICON_SPELL_CHECK "tools-check-spelling" +#endif +#if !HAVE_GTK3 +#define ICON_ADD GTK_STOCK_ADD +#define ICON_REMOVE GTK_STOCK_REMOVE +#define ICON_SPELL_CHECK GTK_STOCK_SPELL_CHECK +#endif /* * Bunch of poop to make enchant into a runtime dependency rather than a @@ -95,11 +115,21 @@ struct _SexySpellEntryPriv }; static void sexy_spell_entry_class_init(SexySpellEntryClass *klass); +#if HAVE_GTK3 +static void sexy_spell_entry_editable_init (GtkEditableInterface *iface); +#endif +#if !HAVE_GTK3 static void sexy_spell_entry_editable_init (GtkEditableClass *iface); +#endif static void sexy_spell_entry_init(SexySpellEntry *entry); static void sexy_spell_entry_finalize(GObject *obj); static void sexy_spell_entry_destroy(GObject *obj); +#if HAVE_GTK3 +static gboolean sexy_spell_entry_draw(GtkWidget *widget, cairo_t *cr); +#endif +#if !HAVE_GTK3 static gint sexy_spell_entry_expose(GtkWidget *widget, GdkEventExpose *event); +#endif static gint sexy_spell_entry_button_press(GtkWidget *widget, GdkEventButton *event); /* GtkEditable handlers */ @@ -243,7 +273,12 @@ sexy_spell_entry_class_init(SexySpellEntryClass *klass) object_class->dispose = sexy_spell_entry_destroy; +#if HAVE_GTK3 + widget_class->draw = sexy_spell_entry_draw; +#endif +#if !HAVE_GTK3 widget_class->expose_event = sexy_spell_entry_expose; +#endif widget_class->button_press_event = sexy_spell_entry_button_press; /** @@ -274,10 +309,19 @@ sexy_spell_entry_class_init(SexySpellEntryClass *klass) } } +#if HAVE_GTK3 +static void +sexy_spell_entry_editable_init (GtkEditableInterface *iface) +{ +} +#endif + +#if !HAVE_GTK3 static void sexy_spell_entry_editable_init (GtkEditableClass *iface) { } +#endif static gint gtk_entry_find_position (GtkEntry *entry, gint x) @@ -290,15 +334,34 @@ gtk_entry_find_position (GtkEntry *entry, gint x) gint pos; gboolean trailing; +#if HAVE_GTK3 + { + gint layout_x; + gint layout_y; + + gtk_entry_get_layout_offsets(entry, &layout_x, &layout_y); + x -= layout_x; + } +#endif +#if !HAVE_GTK3 x = x + entry->scroll_offset; +#endif layout = gtk_entry_get_layout(entry); text = pango_layout_get_text(layout); +#if HAVE_GTK3 + cursor_index = g_utf8_offset_to_pointer( + text, + gtk_editable_get_position(GTK_EDITABLE(entry))) - text; +#endif +#if !HAVE_GTK3 cursor_index = g_utf8_offset_to_pointer(text, entry->current_pos) - text; +#endif line = pango_layout_get_lines(layout)->data; pango_layout_line_x_to_index(line, x * PANGO_SCALE, &index, &trailing); +#if !HAVE_GTK3 if (index >= cursor_index && entry->preedit_length) { if (index >= cursor_index + entry->preedit_length) { index -= entry->preedit_length; @@ -307,6 +370,7 @@ gtk_entry_find_position (GtkEntry *entry, gint x) trailing = FALSE; } } +#endif pos = g_utf8_pointer_to_offset (text, text + index); pos += trailing; @@ -342,8 +406,12 @@ insert_underline_error (SexySpellEntry *entry, guint start, guint end) { PangoAttribute *ucolor; PangoAttribute *unline; + guint16 red; + guint16 green; + guint16 blue; - ucolor = pango_attr_underline_color_new (colors[COL_SPELL].red, colors[COL_SPELL].green, colors[COL_SPELL].blue); + palette_color_get_rgb16 (&colors[COL_SPELL], &red, &green, &blue); + ucolor = pango_attr_underline_color_new (red, green, blue); unline = pango_attr_underline_new (PANGO_UNDERLINE_ERROR); ucolor->start_index = start; @@ -406,22 +474,33 @@ insert_color (SexySpellEntry *entry, guint start, int fgcolor, int bgcolor) PangoAttribute *fgattr; PangoAttribute *ulattr; PangoAttribute *bgattr; + guint16 red; + guint16 green; + guint16 blue; if (fgcolor < 0 || fgcolor > MAX_COL) { - fgattr = pango_attr_foreground_new (colors[COL_FG].red, colors[COL_FG].green, colors[COL_FG].blue); - ulattr = pango_attr_underline_color_new (colors[COL_FG].red, colors[COL_FG].green, colors[COL_FG].blue); + palette_color_get_rgb16 (&colors[COL_FG], &red, &green, &blue); + fgattr = pango_attr_foreground_new (red, green, blue); + ulattr = pango_attr_underline_color_new (red, green, blue); } else { - fgattr = pango_attr_foreground_new (colors[fgcolor].red, colors[fgcolor].green, colors[fgcolor].blue); - ulattr = pango_attr_underline_color_new (colors[fgcolor].red, colors[fgcolor].green, colors[fgcolor].blue); + palette_color_get_rgb16 (&colors[fgcolor], &red, &green, &blue); + fgattr = pango_attr_foreground_new (red, green, blue); + ulattr = pango_attr_underline_color_new (red, green, blue); } if (bgcolor < 0 || bgcolor > MAX_COL) - bgattr = pango_attr_background_new (colors[COL_BG].red, colors[COL_BG].green, colors[COL_BG].blue); + { + palette_color_get_rgb16 (&colors[COL_BG], &red, &green, &blue); + bgattr = pango_attr_background_new (red, green, blue); + } else - bgattr = pango_attr_background_new (colors[bgcolor].red, colors[bgcolor].green, colors[bgcolor].blue); + { + palette_color_get_rgb16 (&colors[bgcolor], &red, &green, &blue); + bgattr = pango_attr_background_new (red, green, blue); + } fgattr->start_index = start; fgattr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END; @@ -540,7 +619,36 @@ replace_word(GtkWidget *menuitem, SexySpellEntry *entry) get_word_extents_from_position(entry, &start, &end, entry->priv->mark_character); oldword = gtk_editable_get_chars(GTK_EDITABLE(entry), start, end); - newword = gtk_label_get_text(GTK_LABEL(gtk_bin_get_child (GTK_BIN(menuitem)))); + newword = gtk_menu_item_get_label (GTK_MENU_ITEM (menuitem)); + if (!newword) + { + /* GTK3 menu items may have a box child (icon + label). */ + GtkWidget *child = gtk_bin_get_child (GTK_BIN (menuitem)); + if (GTK_IS_LABEL (child)) + { + newword = gtk_label_get_text (GTK_LABEL (child)); + } + else if (GTK_IS_CONTAINER (child)) + { + GList *kids, *l; + kids = gtk_container_get_children (GTK_CONTAINER (child)); + for (l = kids; l; l = l->next) + { + if (GTK_IS_LABEL (l->data)) + { + newword = gtk_label_get_text (GTK_LABEL (l->data)); + break; + } + } + g_list_free (kids); + } + } + if (!newword) + { + g_free (oldword); + return; + } + cursor = gtk_editable_get_position(GTK_EDITABLE(entry)); /* is the cursor at the end? If so, restore it there */ @@ -613,6 +721,39 @@ build_suggestion_menu(SexySpellEntry *entry, GtkWidget *menu, struct EnchantDict enchant_dict_free_suggestions(dict, suggestions); } +static GtkWidget * +sexy_spell_entry_icon_menu_item (const char *label, const char *stock_name) +{ + GtkWidget *item; +#if HAVE_GTK3 + const char *icon_name; + GtkWidget *box; + GtkWidget *image = NULL; + GtkWidget *label_widget; + + icon_name = gtkutil_icon_name_from_stock (stock_name); + if (!icon_name) + icon_name = stock_name; + item = gtk_menu_item_new (); + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + if (icon_name) + image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU); + label_widget = gtk_label_new_with_mnemonic (label); + if (image) + gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), label_widget, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (item), box); +#else + GtkWidget *image; + + item = gtk_image_menu_item_new_with_label (label); + image = gtk_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image); +#endif + + return item; +} + static GtkWidget * build_spelling_menu(SexySpellEntry *entry, const gchar *word) { @@ -667,11 +808,9 @@ build_spelling_menu(SexySpellEntry *entry, const gchar *word) /* + Add to Dictionary */ label = g_strdup_printf(_("Add \"%s\" to Dictionary"), word); - mi = gtk_image_menu_item_new_with_label(label); + mi = sexy_spell_entry_icon_menu_item (label, ICON_ADD); g_free(label); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU)); - if (g_slist_length(entry->priv->dict_list) == 1) { dict = (struct EnchantDict *) entry->priv->dict_list->data; g_object_set_data(G_OBJECT(mi), "enchant-dict", dict); @@ -711,8 +850,7 @@ build_spelling_menu(SexySpellEntry *entry, const gchar *word) gtk_menu_shell_append(GTK_MENU_SHELL(topmenu), mi); /* - Ignore All */ - mi = gtk_image_menu_item_new_with_label(_("Ignore All")); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), gtk_image_new_from_stock(GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU)); + mi = sexy_spell_entry_icon_menu_item (_("Ignore All"), ICON_REMOVE); g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(ignore_all), entry); gtk_widget_show_all(mi); gtk_menu_shell_append(GTK_MENU_SHELL(topmenu), mi); @@ -723,7 +861,7 @@ build_spelling_menu(SexySpellEntry *entry, const gchar *word) static void sexy_spell_entry_populate_popup(SexySpellEntry *entry, GtkMenu *menu, gpointer data) { - GtkWidget *icon, *mi; + GtkWidget *mi; gint start, end; gchar *word; @@ -745,9 +883,7 @@ sexy_spell_entry_populate_popup(SexySpellEntry *entry, GtkMenu *menu, gpointer d gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), mi); /* Above the separator, show the suggestions menu */ - icon = gtk_image_new_from_stock(GTK_STOCK_SPELL_CHECK, GTK_ICON_SIZE_MENU); - mi = gtk_image_menu_item_new_with_label(_("Spelling Suggestions")); - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), icon); + mi = sexy_spell_entry_icon_menu_item (_("Spelling Suggestions"), ICON_SPELL_CHECK); word = gtk_editable_get_chars(GTK_EDITABLE(entry), start, end); g_assert(word != NULL); @@ -1115,6 +1251,22 @@ sexy_spell_entry_recheck_all(SexySpellEntry *entry) } } +#if HAVE_GTK3 +static gboolean +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); +} +#endif + +#if !HAVE_GTK3 static gint sexy_spell_entry_expose(GtkWidget *widget, GdkEventExpose *event) { @@ -1122,7 +1274,6 @@ sexy_spell_entry_expose(GtkWidget *widget, GdkEventExpose *event) GtkEntry *gtk_entry = GTK_ENTRY(widget); PangoLayout *layout; - layout = gtk_entry_get_layout(gtk_entry); if (gtk_entry->preedit_length == 0) { @@ -1135,6 +1286,7 @@ sexy_spell_entry_expose(GtkWidget *widget, GdkEventExpose *event) return GTK_WIDGET_CLASS(parent_class)->expose_event (widget, event); } +#endif static gint sexy_spell_entry_button_press(GtkWidget *widget, GdkEventButton *event) diff --git a/src/fe-gtk/sexy-spell-entry.h b/src/fe-gtk/sexy-spell-entry.h index 1e6fd1f2..abe021d2 100644 --- a/src/fe-gtk/sexy-spell-entry.h +++ b/src/fe-gtk/sexy-spell-entry.h @@ -18,11 +18,14 @@ #ifndef _SEXY_SPELL_ENTRY_H_ #define _SEXY_SPELL_ENTRY_H_ +#include + +G_BEGIN_DECLS + typedef struct _SexySpellEntry SexySpellEntry; typedef struct _SexySpellEntryClass SexySpellEntryClass; -typedef struct _SexySpellEntryPriv SexySpellEntryPriv; -#include +GType sexy_spell_entry_get_type(void); #define SEXY_TYPE_SPELL_ENTRY (sexy_spell_entry_get_type()) #define SEXY_SPELL_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SEXY_TYPE_SPELL_ENTRY, SexySpellEntry)) @@ -31,6 +34,8 @@ typedef struct _SexySpellEntryPriv SexySpellEntryPriv; #define SEXY_IS_SPELL_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SEXY_TYPE_SPELL_ENTRY)) #define SEXY_SPELL_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), SEXY_TYPE_SPELL_ENTRY, SexySpellEntryClass)) +typedef struct _SexySpellEntryPriv SexySpellEntryPriv; + #define SEXY_SPELL_ERROR (sexy_spell_error_quark()) typedef enum { @@ -39,7 +44,11 @@ typedef enum { struct _SexySpellEntry { +#if HAVE_GTK3 + GtkEntry parent_instance; +#else GtkEntry parent_object; +#endif SexySpellEntryPriv *priv; @@ -62,9 +71,6 @@ struct _SexySpellEntryClass void (*gtk_reserved4)(void); }; -G_BEGIN_DECLS - -GType sexy_spell_entry_get_type(void); GtkWidget *sexy_spell_entry_new(void); GQuark sexy_spell_error_quark(void); diff --git a/src/fe-gtk/textgui.c b/src/fe-gtk/textgui.c index 1e9e956f..4f4f2593 100644 --- a/src/fe-gtk/textgui.c +++ b/src/fe-gtk/textgui.c @@ -38,6 +38,17 @@ #include "palette.h" #include "textgui.h" +#if HAVE_GTK3 +#define ICON_TEXTEVENT_SAVE_AS "document-save-as" +#define ICON_TEXTEVENT_OPEN "document-open" +#define ICON_TEXTEVENT_OK "dialog-ok" +#endif +#if !HAVE_GTK3 +#define ICON_TEXTEVENT_SAVE_AS GTK_STOCK_SAVE_AS +#define ICON_TEXTEVENT_OPEN GTK_STOCK_OPEN +#define ICON_TEXTEVENT_OK GTK_STOCK_OK +#endif + extern struct text_event te[]; extern char *pntevts_text[]; extern char *pntevts[]; @@ -451,7 +462,11 @@ pevent_dialog_show () TRUE, FALSE, pevent_dialog_close, NULL, 600, 455, &vbox, 0); +#if HAVE_GTK3 + pane = gtk_paned_new (GTK_ORIENTATION_VERTICAL); +#elif !HAVE_GTK3 pane = gtk_vpaned_new (); +#endif gtk_box_pack_start (GTK_BOX (vbox), pane, TRUE, TRUE, 0); pevent_dialog_list = pevent_treeview_new (pane); @@ -470,16 +485,21 @@ pevent_dialog_show () gtk_container_add (GTK_CONTAINER (wid), pevent_dialog_twid); gtk_xtext_set_font (GTK_XTEXT (pevent_dialog_twid), prefs.hex_text_font); +#if HAVE_GTK3 + hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 hbox = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD); +#endif gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 4); - gtkutil_button (hbox, GTK_STOCK_SAVE_AS, NULL, pevent_save_cb, + gtkutil_button (hbox, ICON_TEXTEVENT_SAVE_AS, NULL, pevent_save_cb, (void *) 1, _("Save As...")); - gtkutil_button (hbox, GTK_STOCK_OPEN, NULL, pevent_load_cb, + gtkutil_button (hbox, ICON_TEXTEVENT_OPEN, NULL, pevent_load_cb, NULL, _("Load From...")); gtkutil_button (hbox, NULL, NULL, pevent_test_cb, pevent_dialog_twid, _("Test All")); - gtkutil_button (hbox, GTK_STOCK_OK, NULL, pevent_ok_cb, + gtkutil_button (hbox, ICON_TEXTEVENT_OK, NULL, pevent_ok_cb, NULL, _("OK")); gtk_widget_show_all (pevent_dialog); diff --git a/src/fe-gtk/urlgrab.c b/src/fe-gtk/urlgrab.c index 4d520959..6e481924 100644 --- a/src/fe-gtk/urlgrab.c +++ b/src/fe-gtk/urlgrab.c @@ -33,6 +33,17 @@ #include "maingui.h" #include "urlgrab.h" +#if HAVE_GTK3 +#define ICON_URLGRAB_CLEAR "edit-clear" +#define ICON_URLGRAB_COPY "edit-copy" +#define ICON_URLGRAB_SAVE_AS "document-save-as" +#endif +#if !HAVE_GTK3 +#define ICON_URLGRAB_CLEAR GTK_STOCK_CLEAR +#define ICON_URLGRAB_COPY GTK_STOCK_COPY +#define ICON_URLGRAB_SAVE_AS GTK_STOCK_SAVE_AS +#endif + /* model for the URL treeview */ enum { @@ -87,13 +98,16 @@ static GtkWidget * url_treeview_new (GtkWidget *box) { GtkListStore *store; - GtkWidget *view; + GtkWidget *scroll, *view; store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING); g_return_val_if_fail (store != NULL, NULL); view = gtkutil_treeview_new (box, GTK_TREE_MODEL (store), NULL, URL_COLUMN, _("URL"), -1); + scroll = gtk_widget_get_parent (view); + gtk_widget_set_hexpand (scroll, TRUE); + gtk_widget_set_vexpand (scroll, TRUE); g_signal_connect (G_OBJECT (view), "button_press_event", G_CALLBACK (url_treeview_url_clicked_cb), NULL); /* don't want column headers */ @@ -204,17 +218,22 @@ url_opengui () g_object_set_data (G_OBJECT (urlgrabberwindow), "model", gtk_tree_view_get_model (GTK_TREE_VIEW (view))); +#if HAVE_GTK3 + hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD); +#elif !HAVE_GTK3 hbox = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD); +#endif gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); gtk_box_pack_end (GTK_BOX (vbox), hbox, 0, 0, 0); gtk_widget_show (hbox); - gtkutil_button (hbox, GTK_STOCK_CLEAR, + gtkutil_button (hbox, ICON_URLGRAB_CLEAR, _("Clear list"), url_button_clear, 0, _("Clear")); - gtkutil_button (hbox, GTK_STOCK_COPY, + gtkutil_button (hbox, ICON_URLGRAB_COPY, _("Copy selected URL"), url_button_copy, view, _("Copy")); - gtkutil_button (hbox, GTK_STOCK_SAVE_AS, + gtkutil_button (hbox, ICON_URLGRAB_SAVE_AS, _("Save list to a file"), url_button_save, 0, _("Save As...")); gtk_widget_show (urlgrabberwindow); diff --git a/src/fe-gtk/userlistgui.c b/src/fe-gtk/userlistgui.c index 4b362217..d1862daf 100644 --- a/src/fe-gtk/userlistgui.c +++ b/src/fe-gtk/userlistgui.c @@ -46,9 +46,10 @@ enum COL_NICK=1, /* char * */ COL_HOST=2, /* char * */ COL_USER=3, /* struct User * */ - COL_GDKCOLOR=4 /* GdkColor * */ + COL_GDKCOLOR=4 /* PaletteColor */ }; +static void userlist_store_color (GtkListStore *store, GtkTreeIter *iter, int color_index); GdkPixbuf * get_user_icon (server *serv, struct User *user) @@ -327,8 +328,8 @@ fe_userlist_rehash (session *sess, struct User *user) gtk_list_store_set (GTK_LIST_STORE (sess->res->user_model), iter, COL_HOST, user->hostname, - COL_GDKCOLOR, nick_color ? &colors[nick_color] : NULL, -1); + userlist_store_color (GTK_LIST_STORE (sess->res->user_model), iter, nick_color); } void @@ -362,8 +363,8 @@ fe_userlist_insert (session *sess, struct User *newuser, gboolean sel) COL_NICK, nick, COL_HOST, newuser->hostname, COL_USER, newuser, - COL_GDKCOLOR, nick_color ? &colors[nick_color] : NULL, -1); + userlist_store_color (GTK_LIST_STORE (model), &iter, nick_color); if (!prefs.hex_gui_ulist_icons) { @@ -467,6 +468,26 @@ userlist_ops_cmp (GtkTreeModel *model, GtkTreeIter *iter_a, GtkTreeIter *iter_b, return nick_cmp_az_ops (((session*)userdata)->server, user_a, user_b); } +static void +userlist_store_color (GtkListStore *store, GtkTreeIter *iter, int color_index) +{ + const PaletteColor *color = color_index ? &colors[color_index] : NULL; + +#if HAVE_GTK3 + if (color) + { + GdkRGBA rgba = *color; + gtk_list_store_set (store, iter, COL_GDKCOLOR, &rgba, -1); + } + else + { + gtk_list_store_set (store, iter, COL_GDKCOLOR, NULL, -1); + } +#else + gtk_list_store_set (store, iter, COL_GDKCOLOR, color, -1); +#endif +} + GtkListStore * userlist_create_model (session *sess) { @@ -475,7 +496,7 @@ userlist_create_model (session *sess) GtkSortType sort_type; store = gtk_list_store_new (5, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_POINTER, GDK_TYPE_COLOR); + G_TYPE_POINTER, PALETTE_GDK_TYPE); switch (prefs.hex_gui_ulist_sort) { @@ -528,7 +549,7 @@ userlist_add_columns (GtkTreeView * treeview) 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), -1, NULL, renderer, - "text", 1, "foreground-gdk", 4, NULL); + "text", 1, PALETTE_FOREGROUND_PROPERTY, 4, NULL); if (prefs.hex_gui_ulist_show_hosts) { diff --git a/src/fe-gtk/xtext.c b/src/fe-gtk/xtext.c index 8f3cc190..de908181 100644 --- a/src/fe-gtk/xtext.c +++ b/src/fe-gtk/xtext.c @@ -72,8 +72,6 @@ /* force scrolling off */ #define dontscroll(buf) (buf)->last_pixel_pos = 0x7fffffff -static GtkWidgetClass *parent_class = NULL; - struct textentry { struct textentry *next; @@ -110,8 +108,56 @@ enum TARGET_COMPOUND_TEXT }; + +/* Selection targets for PRIMARY selection / copy-paste. + * + * On Wayland, GtkWidget has no GdkWindow until it is realized. Registering + * selection targets during instance init is too early and can crash under the + * Wayland backend (window/display is NULL). + */ +static const GtkTargetEntry gtk_xtext_selection_targets[] = { + { "UTF8_STRING", 0, TARGET_UTF8_STRING }, + { "STRING", 0, TARGET_STRING }, + { "TEXT", 0, TARGET_TEXT }, + { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT } +}; + +static void +gtk_xtext_install_selection_targets_on_realize (GtkWidget *widget, gpointer user_data) +{ + (void)user_data; + + if (gtk_widget_get_window (widget) == NULL) + return; + + gtk_selection_add_targets (widget, + GDK_SELECTION_PRIMARY, + (GtkTargetEntry *)gtk_xtext_selection_targets, + (gint)G_N_ELEMENTS (gtk_xtext_selection_targets)); +} + +static void +gtk_xtext_install_selection_targets (GtkWidget *widget) +{ + if (gtk_widget_get_realized (widget) && gtk_widget_get_window (widget) != NULL) + { + gtk_selection_add_targets (widget, + GDK_SELECTION_PRIMARY, + (GtkTargetEntry *)gtk_xtext_selection_targets, + (gint)G_N_ELEMENTS (gtk_xtext_selection_targets)); + return; + } + + g_signal_connect (widget, + "realize", + G_CALLBACK (gtk_xtext_install_selection_targets_on_realize), + NULL); +} + static guint xtext_signals[LAST_SIGNAL]; +G_DEFINE_TYPE (GtkXText, gtk_xtext, GTK_TYPE_WIDGET) + char *nocasestrstr (const char *text, const char *tofind); /* util.c */ int xtext_get_stamp_str (time_t, char **); static void gtk_xtext_render_page (GtkXText * xtext); @@ -150,6 +196,18 @@ static void gtk_xtext_search_fini (xtext_buffer *); static gboolean gtk_xtext_search_init (xtext_buffer *buf, const gchar *text, gtk_xtext_search_flags flags, GError **perr); static char * gtk_xtext_get_word (GtkXText * xtext, int x, int y, textentry ** ret_ent, int *ret_off, int *ret_len, GSList **slp); +static inline void +gtk_xtext_cursor_unref (GdkCursor *cursor) +{ + if (!cursor) + return; +#if !HAVE_GTK3 + gdk_cursor_unref (cursor); +#else + g_object_unref (cursor); +#endif +} + static inline void xtext_set_source_color (cairo_t *cr, const XTextColor *color, gdouble alpha) { @@ -157,6 +215,122 @@ xtext_set_source_color (cairo_t *cr, const XTextColor *color, gdouble alpha) color->blue, color->alpha * alpha); } +static inline gdouble +xtext_adj_get_value (GtkAdjustment *adj) +{ +#if !HAVE_GTK3 + return adj->value; +#else + return gtk_adjustment_get_value (adj); +#endif +} + +static inline void +xtext_adj_set_value (GtkAdjustment *adj, gdouble value) +{ +#if !HAVE_GTK3 + adj->value = value; +#else + gtk_adjustment_set_value (adj, value); +#endif +} + +static inline gdouble +xtext_adj_get_upper (GtkAdjustment *adj) +{ +#if !HAVE_GTK3 + return adj->upper; +#else + return gtk_adjustment_get_upper (adj); +#endif +} + +static inline void +xtext_adj_set_upper (GtkAdjustment *adj, gdouble upper) +{ +#if !HAVE_GTK3 + adj->upper = upper; +#else + gtk_adjustment_set_upper (adj, upper); +#endif +} + +static inline gdouble +xtext_adj_get_lower (GtkAdjustment *adj) +{ +#if !HAVE_GTK3 + return adj->lower; +#else + return gtk_adjustment_get_lower (adj); +#endif +} + +static inline void +xtext_adj_set_lower (GtkAdjustment *adj, gdouble lower) +{ +#if !HAVE_GTK3 + adj->lower = lower; +#else + gtk_adjustment_set_lower (adj, lower); +#endif +} + +static inline gdouble +xtext_adj_get_page_size (GtkAdjustment *adj) +{ +#if !HAVE_GTK3 + return adj->page_size; +#else + return gtk_adjustment_get_page_size (adj); +#endif +} + +static inline void +xtext_adj_set_page_size (GtkAdjustment *adj, gdouble page_size) +{ +#if !HAVE_GTK3 + adj->page_size = page_size; +#else + gtk_adjustment_set_page_size (adj, page_size); +#endif +} + +static inline gdouble +xtext_adj_get_page_increment (GtkAdjustment *adj) +{ +#if !HAVE_GTK3 + return adj->page_increment; +#else + return gtk_adjustment_get_page_increment (adj); +#endif +} + +static void +xtext_adjustment_apply (GtkAdjustment *adj, gdouble lower, gdouble upper, gdouble value, gdouble page_size) +{ +#if HAVE_GTK3 + gtk_adjustment_set_lower (adj, lower); + gtk_adjustment_set_upper (adj, upper); + gtk_adjustment_set_page_size (adj, page_size); + gtk_adjustment_set_value (adj, value); +#else + adj->lower = lower; + adj->upper = upper; + adj->page_size = page_size; + adj->value = value; +#endif +} + +static inline void +xtext_adj_set_page_increment (GtkAdjustment *adj, gdouble page_increment) +{ +#if !HAVE_GTK3 + adj->page_increment = page_increment; +#else + gtk_adjustment_set_page_increment (adj, page_increment); +#endif +} + static cairo_surface_t * xtext_surface_from_window (GdkWindow *window) { @@ -165,7 +339,7 @@ xtext_surface_from_window (GdkWindow *window) int height; cairo_t *cr; - if (!window) + if (!window || !GDK_IS_WINDOW (window)) return NULL; width = gdk_window_get_width (window); @@ -193,6 +367,8 @@ xtext_create_context (GtkXText *xtext) { if (xtext->draw_surface) return cairo_create (xtext->draw_surface); + if (xtext->draw_cr) + return cairo_reference (xtext->draw_cr); return gdk_cairo_create (xtext->draw_window); } @@ -506,6 +682,7 @@ gtk_xtext_init (GtkXText * xtext) xtext->background_surface = NULL; xtext->draw_window = NULL; xtext->draw_surface = NULL; + xtext->draw_cr = NULL; xtext->io_tag = 0; xtext->add_io_tag = 0; xtext->scroll_tag = 0; @@ -538,18 +715,7 @@ gtk_xtext_init (GtkXText * xtext) xtext->dont_render2 = FALSE; gtk_xtext_scroll_adjustments (xtext, NULL, NULL); - { - static const GtkTargetEntry targets[] = { - { "UTF8_STRING", 0, TARGET_UTF8_STRING }, - { "STRING", 0, TARGET_STRING }, - { "TEXT", 0, TARGET_TEXT }, - { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT } - }; - static const gint n_targets = sizeof (targets) / sizeof (targets[0]); - - gtk_selection_add_targets (GTK_WIDGET (xtext), GDK_SELECTION_PRIMARY, - targets, n_targets); - } + gtk_xtext_install_selection_targets (GTK_WIDGET (xtext)); } static void @@ -559,27 +725,44 @@ gtk_xtext_adjustment_set (xtext_buffer *buf, int fire_signal) if (buf->xtext->buffer == buf) { - adj->lower = 0; - adj->upper = buf->num_lines; + gdouble lower = 0; + gdouble upper = buf->num_lines; + gdouble value = xtext_adj_get_value (adj); + gdouble page_size; - if (adj->upper == 0) - adj->upper = 1; + if (upper == 0) + upper = 1; - adj->page_size = GTK_WIDGET (buf->xtext)->allocation.height / +#if HAVE_GTK3 + GtkAllocation allocation; + + gtk_widget_get_allocation (GTK_WIDGET (buf->xtext), &allocation); + page_size = allocation.height / buf->xtext->fontsize; +#else + page_size = GTK_WIDGET (buf->xtext)->allocation.height / buf->xtext->fontsize; - adj->page_increment = adj->page_size; +#endif - if (adj->value > adj->upper - adj->page_size) + if (value > upper - page_size) { buf->scrollbar_down = TRUE; - adj->value = adj->upper - adj->page_size; + value = upper - page_size; } - if (adj->value < 0) - adj->value = 0; + if (value < 0) + value = 0; + + xtext_adjustment_apply (adj, lower, upper, value, page_size); + xtext_adj_set_page_increment (adj, page_size); if (fire_signal) + { +#if HAVE_GTK3 + gtk_adjustment_value_changed (adj); +#else gtk_adjustment_changed (adj); +#endif + } } } @@ -594,18 +777,22 @@ gtk_xtext_adjustment_timeout (GtkXText * xtext) static void gtk_xtext_adjustment_changed (GtkAdjustment * adj, GtkXText * xtext) { + gdouble value = xtext_adj_get_value (xtext->adj); + gdouble upper = xtext_adj_get_upper (xtext->adj); + gdouble page_size = xtext_adj_get_page_size (xtext->adj); + if (!gtk_widget_get_realized (GTK_WIDGET (xtext))) return; - if (xtext->buffer->old_value != xtext->adj->value) + if (xtext->buffer->old_value != value) { - if (xtext->adj->value >= xtext->adj->upper - xtext->adj->page_size) + if (value >= upper - page_size) xtext->buffer->scrollbar_down = TRUE; else xtext->buffer->scrollbar_down = FALSE; - if (xtext->adj->value + 1 == xtext->buffer->old_value || - xtext->adj->value - 1 == xtext->buffer->old_value) /* clicked an arrow? */ + if (value + 1 == xtext->buffer->old_value || + value - 1 == xtext->buffer->old_value) /* clicked an arrow? */ { if (xtext->io_tag) { @@ -622,7 +809,7 @@ gtk_xtext_adjustment_changed (GtkAdjustment * adj, GtkXText * xtext) xtext); } } - xtext->buffer->old_value = adj->value; + xtext->buffer->old_value = xtext_adj_get_value (adj); } GtkWidget * @@ -636,17 +823,19 @@ gtk_xtext_new (const XTextColor *palette, int separator) xtext->buffer = gtk_xtext_buffer_new (xtext); xtext->orig_buffer = xtext->buffer; +#if !HAVE_GTK3 gtk_widget_set_double_buffered (GTK_WIDGET (xtext), FALSE); +#else + /* GTK3 already uses the GTK render pipeline; no manual double-buffering toggle. */ +#endif gtk_xtext_set_palette (xtext, palette); return GTK_WIDGET (xtext); } static void -gtk_xtext_destroy (GtkObject * object) +gtk_xtext_cleanup (GtkXText *xtext) { - GtkXText *xtext = GTK_XTEXT (object); - if (xtext->add_io_tag) { g_source_remove (xtext->add_io_tag); @@ -689,13 +878,13 @@ gtk_xtext_destroy (GtkObject * object) if (xtext->hand_cursor) { - gdk_cursor_unref (xtext->hand_cursor); + gtk_xtext_cursor_unref (xtext->hand_cursor); xtext->hand_cursor = NULL; } if (xtext->resize_cursor) { - gdk_cursor_unref (xtext->resize_cursor); + gtk_xtext_cursor_unref (xtext->resize_cursor); xtext->resize_cursor = NULL; } @@ -704,21 +893,136 @@ gtk_xtext_destroy (GtkObject * object) gtk_xtext_buffer_free (xtext->orig_buffer); xtext->orig_buffer = NULL; } - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); } +#if !HAVE_GTK3 +static void +gtk_xtext_destroy (GtkObject * object) +{ + GtkXText *xtext = GTK_XTEXT (object); + + gtk_xtext_cleanup (xtext); + + if (GTK_OBJECT_CLASS (gtk_xtext_parent_class)->destroy) + (*GTK_OBJECT_CLASS (gtk_xtext_parent_class)->destroy) (object); +} +#endif + +#if HAVE_GTK3 +static void +gtk_xtext_dispose (GObject *object) +{ + GtkXText *xtext = GTK_XTEXT (object); + + gtk_xtext_cleanup (xtext); + + if (G_OBJECT_CLASS (gtk_xtext_parent_class)->dispose) + (*G_OBJECT_CLASS (gtk_xtext_parent_class)->dispose) (object); +} + +static void +gtk_xtext_finalize (GObject *object) +{ + if (G_OBJECT_CLASS (gtk_xtext_parent_class)->finalize) + (*G_OBJECT_CLASS (gtk_xtext_parent_class)->finalize) (object); +} +#endif + static void gtk_xtext_unrealize (GtkWidget * widget) { backend_deinit (GTK_XTEXT (widget)); - /* if there are still events in the queue, this'll avoid segfault */ + /* + * Keep GtkWidget/GdkWindow association intact until parent unrealize. + * GtkWidget's unrealize path unregisters the window and expects + * gdk_window_get_user_data(window) == widget. + */ +#if !HAVE_GTK3 gdk_window_set_user_data (widget->window, NULL); +#endif - if (parent_class->unrealize) - (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); + if (GTK_WIDGET_CLASS (gtk_xtext_parent_class)->unrealize) + (*GTK_WIDGET_CLASS (gtk_xtext_parent_class)->unrealize) (widget); + +#if HAVE_GTK3 + gtk_widget_set_window (widget, NULL); + gtk_widget_set_realized (widget, FALSE); +#endif +} + +static void +gtk_xtext_get_pointer (GdkWindow *window, gint *x, gint *y, GdkModifierType *mask) +{ +#if !HAVE_GTK3 + gdk_window_get_pointer (window, x, y, mask); +#else + GdkDisplay *display; + GdkSeat *seat; + GdkDevice *device; + gint root_x = 0; + gint root_y = 0; + gint win_x = 0; + gint win_y = 0; + + if (!window || !GDK_IS_WINDOW (window)) + { + if (x) + *x = 0; + if (y) + *y = 0; + if (mask) + *mask = 0; + return; + } + + display = gdk_window_get_display (window); + if (!display) + { + if (x) + *x = 0; + if (y) + *y = 0; + if (mask) + *mask = 0; + return; + } + + seat = gdk_display_get_default_seat (display); + device = gdk_seat_get_pointer (seat); + if (!device) + { + if (x) + *x = 0; + if (y) + *y = 0; + if (mask) + *mask = 0; + return; + } + + gdk_device_get_position (device, NULL, &root_x, &root_y); + gdk_window_get_origin (window, &win_x, &win_y); + + if (x) + *x = root_x - win_x; + if (y) + *y = root_y - win_y; + if (mask) + gdk_device_get_state (device, window, NULL, mask); +#endif +} + +static inline void +gtk_xtext_clear_background (GtkWidget *widget) +{ +#if !HAVE_GTK3 + gdk_window_set_back_pixmap (widget->window, NULL, FALSE); +#else + GdkWindow *window = gtk_widget_get_window (widget); + if (window) + gdk_window_set_background_pattern (window, NULL); +#endif } static void @@ -726,30 +1030,49 @@ gtk_xtext_realize (GtkWidget * widget) { GtkXText *xtext; GdkWindowAttr attributes; + GdkWindow *window; + GtkAllocation allocation; + GdkWindow *parent_window; + gint attributes_mask; - gtk_widget_set_realized (widget, TRUE); xtext = GTK_XTEXT (widget); - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; + gtk_widget_set_realized (widget, TRUE); +#if HAVE_GTK3 + gtk_widget_get_allocation (widget, &allocation); + parent_window = gtk_widget_get_parent_window (widget); + attributes.visual = gtk_widget_get_visual (widget); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; +#endif +#if !HAVE_GTK3 + allocation = widget->allocation; + parent_window = widget->parent->window; + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.visual = gtk_widget_get_visual (widget); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; +#endif + + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK; + | GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_SCROLL_MASK; + + window = gdk_window_new (parent_window, &attributes, attributes_mask); - attributes.colormap = gtk_widget_get_colormap (widget); - attributes.visual = gtk_widget_get_visual (widget); +#if HAVE_GTK3 + gtk_widget_set_window (widget, window); +#else + widget->window = window; +#endif - widget->window = gdk_window_new (widget->parent->window, &attributes, - GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | - GDK_WA_COLORMAP); + gdk_window_set_user_data (window, widget); - gdk_window_set_user_data (widget->window, widget); - - xtext->depth = gdk_window_get_visual (widget->window)->depth; + xtext->depth = gdk_visual_get_depth (gdk_window_get_visual (window)); /* for the separator bar (light) */ xtext->light_gc.red = 1.0; @@ -776,45 +1099,108 @@ gtk_xtext_realize (GtkWidget * widget) xtext_set_bg (xtext, XTEXT_BG); /* draw directly to window */ - xtext->draw_window = widget->window; + xtext->draw_window = window; if (xtext->background_surface) { xtext->ts_x = xtext->ts_y = 0; } - xtext->hand_cursor = gdk_cursor_new_for_display (gdk_window_get_display (widget->window), GDK_HAND1); - xtext->resize_cursor = gdk_cursor_new_for_display (gdk_window_get_display (widget->window), GDK_LEFT_SIDE); + if (window && GDK_IS_WINDOW (window)) + { + GdkDisplay *display = gdk_window_get_display (window); - gdk_window_set_back_pixmap (widget->window, NULL, FALSE); + if (display) + { + xtext->hand_cursor = gdk_cursor_new_for_display (display, GDK_HAND1); + xtext->resize_cursor = gdk_cursor_new_for_display (display, GDK_LEFT_SIDE); + } + } + + gtk_xtext_clear_background (widget); backend_init (xtext); } static void -gtk_xtext_size_request (GtkWidget * widget, GtkRequisition * requisition) +gtk_xtext_size_request_internal (GtkWidget *widget, GtkRequisition *requisition) { requisition->width = 200; requisition->height = 90; } +#if !HAVE_GTK3 +static void +gtk_xtext_size_request (GtkWidget *widget, GtkRequisition *requisition) +{ + gtk_xtext_size_request_internal (widget, requisition); +} +#endif + +#if HAVE_GTK3 +static void +gtk_xtext_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural) +{ + GtkRequisition requisition; + + gtk_xtext_size_request_internal (widget, &requisition); + *minimum = requisition.width; + *natural = requisition.width; +} + +static void +gtk_xtext_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) +{ + GtkRequisition requisition; + + gtk_xtext_size_request_internal (widget, &requisition); + *minimum = requisition.height; + *natural = requisition.height; +} + +static void +gtk_xtext_get_preferred_height_for_width (GtkWidget *widget, gint width, + gint *minimum, gint *natural) +{ + GtkRequisition requisition; + + (void)width; + gtk_xtext_size_request_internal (widget, &requisition); + *minimum = requisition.height; + *natural = requisition.height; +} +#endif + static void gtk_xtext_size_allocate (GtkWidget * widget, GtkAllocation * allocation) { GtkXText *xtext = GTK_XTEXT (widget); int height_only = FALSE; + GdkWindow *window; if (allocation->width == xtext->buffer->window_width) height_only = TRUE; +#if HAVE_GTK3 + gtk_widget_set_allocation (widget, allocation); +#endif +#if !HAVE_GTK3 widget->allocation = *allocation; +#endif if (gtk_widget_get_realized (GTK_WIDGET(widget))) { xtext->buffer->window_width = allocation->width; xtext->buffer->window_height = allocation->height; - gdk_window_move_resize (widget->window, allocation->x, allocation->y, - allocation->width, allocation->height); +#if HAVE_GTK3 + window = gtk_widget_get_window (widget); +#endif +#if !HAVE_GTK3 + window = widget->window; +#endif + if (window) + gdk_window_move_resize (window, allocation->x, allocation->y, + allocation->width, allocation->height); dontscroll (xtext->buffer); /* force scrolling off */ if (!height_only) gtk_xtext_calc_lines (xtext->buffer, FALSE); @@ -824,8 +1210,9 @@ gtk_xtext_size_allocate (GtkWidget * widget, GtkAllocation * allocation) gtk_xtext_adjustment_set (xtext->buffer, FALSE); } if (xtext->buffer->scrollbar_down) - gtk_adjustment_set_value (xtext->adj, xtext->adj->upper - - xtext->adj->page_size); + xtext_adj_set_value (xtext->adj, + xtext_adj_get_upper (xtext->adj) - + xtext_adj_get_page_size (xtext->adj)); } } @@ -944,7 +1331,7 @@ gtk_xtext_find_x (GtkXText * xtext, int x, textentry * ent, int subline, else indent = xtext->buffer->indent; - if (line > xtext->adj->page_size || line < 0) + if (line > xtext_adj_get_page_size (xtext->adj) || line < 0) { *out_of_bounds = TRUE; return 0; @@ -979,7 +1366,8 @@ gtk_xtext_find_char (GtkXText * xtext, int x, int y, int *off, int *out_of_bound y -= xtext->fontsize; line = (y + xtext->pixel_offset) / xtext->fontsize; - ent = gtk_xtext_nth (xtext, line + (int)xtext->adj->value, &subline); + ent = gtk_xtext_nth (xtext, + line + (int)xtext_adj_get_value (xtext->adj), &subline); if (!ent) return NULL; @@ -996,11 +1384,18 @@ gtk_xtext_draw_sep (GtkXText * xtext, int y) { int x, height; cairo_t *cr; + GtkAllocation allocation; if (y == -1) { y = 0; +#if HAVE_GTK3 + gtk_widget_get_allocation (GTK_WIDGET (xtext), &allocation); + height = allocation.height; +#endif +#if !HAVE_GTK3 height = GTK_WIDGET (xtext)->allocation.height; +#endif } else { height = xtext->fontsize; @@ -1048,6 +1443,7 @@ gtk_xtext_draw_marker (GtkXText * xtext, textentry * ent, int y) { int x, width, render_y; cairo_t *cr; + GtkAllocation allocation; if (!xtext->marker) return; @@ -1062,7 +1458,13 @@ gtk_xtext_draw_marker (GtkXText * xtext, textentry * ent, int y) else return; x = 0; - width = GTK_WIDGET (xtext)->allocation.width; +#if HAVE_GTK3 + gtk_widget_get_allocation (GTK_WIDGET (xtext), &allocation); +#endif +#if !HAVE_GTK3 + allocation = GTK_WIDGET (xtext)->allocation; +#endif + width = allocation.width; cr = xtext_create_context (xtext); xtext_draw_line (xtext, cr, &xtext->marker_gc, x, render_y, x + width, render_y); @@ -1075,19 +1477,30 @@ gtk_xtext_draw_marker (GtkXText * xtext, textentry * ent, int y) } static void -gtk_xtext_paint (GtkWidget *widget, GdkRectangle *area) +gtk_xtext_render (GtkWidget *widget, GdkRectangle *area, cairo_t *cr) { GtkXText *xtext = GTK_XTEXT (widget); textentry *ent_start, *ent_end; int x, y; + GtkAllocation allocation; + cairo_t *old_cr = xtext->draw_cr; + + xtext->draw_cr = cr; + +#if HAVE_GTK3 + gtk_widget_get_allocation (widget, &allocation); +#endif +#if !HAVE_GTK3 + allocation = widget->allocation; +#endif if (area->x == 0 && area->y == 0 && - area->height == widget->allocation.height && - area->width == widget->allocation.width) + area->height == allocation.height && + area->width == allocation.width) { dontscroll (xtext->buffer); /* force scrolling off */ gtk_xtext_render_page (xtext); - return; + goto done; } ent_start = gtk_xtext_find_char (xtext, area->x, area->y, NULL, NULL); @@ -1111,14 +1524,14 @@ gtk_xtext_paint (GtkWidget *widget, GdkRectangle *area) /* y is the last pixel y location it rendered text at */ y = gtk_xtext_render_ents (xtext, ent_start, ent_end); - if (y && y < widget->allocation.height && !ent_end->next) + if (y && y < allocation.height && !ent_end->next) { GdkRectangle rect; rect.x = 0; rect.y = y; - rect.width = widget->allocation.width; - rect.height = widget->allocation.height - y; + rect.width = allocation.width; + rect.height = allocation.height - y; /* fill any space below the last line that also intersects with the exposure rectangle */ @@ -1138,14 +1551,62 @@ xit: x = xtext->buffer->indent - ((xtext->space_width + 1) / 2); if (area->x <= x) gtk_xtext_draw_sep (xtext, -1); + +done: + xtext->draw_cr = old_cr; } +static void +gtk_xtext_paint (GtkWidget *widget, GdkRectangle *area) +{ + /* + * On GTK3/Wayland, drawing directly to the window (via a NULL cairo_t here) + * can be buffered without ever being presented. Queue a redraw instead and + * let the widget's ::draw handler do the actual painting. + */ +#if HAVE_GTK3 + if (G_LIKELY (gtk_widget_get_realized (widget))) + { + if (area) + gtk_widget_queue_draw_area (widget, area->x, area->y, area->width, area->height); + else + gtk_widget_queue_draw (widget); + } +#else + gtk_xtext_render (widget, area, NULL); +#endif +} + +#if HAVE_GTK3 +static gboolean +gtk_xtext_draw (GtkWidget *widget, cairo_t *cr) +{ + GdkRectangle area; + + if (!gdk_cairo_get_clip_rectangle (cr, &area)) + { + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + area.x = 0; + area.y = 0; + area.width = allocation.width; + area.height = allocation.height; + } + + gtk_xtext_render (widget, &area, cr); + return FALSE; +} +#endif + +#if !HAVE_GTK3 static gboolean gtk_xtext_expose (GtkWidget * widget, GdkEventExpose * event) { - gtk_xtext_paint (widget, &event->area); + gtk_xtext_render (widget, &event->area, NULL); return FALSE; } +#endif /* render a selection that has extended or contracted upward */ @@ -1466,14 +1927,24 @@ gtk_xtext_scrolldown_timeout (GtkXText * xtext) int p_y, win_height; xtext_buffer *buf = xtext->buffer; GtkAdjustment *adj = xtext->adj; + GdkWindow *window; - gdk_window_get_pointer (GTK_WIDGET (xtext)->window, 0, &p_y, 0); - win_height = gdk_window_get_height (gtk_widget_get_window (GTK_WIDGET (xtext))); +#if HAVE_GTK3 + window = gtk_widget_get_window (GTK_WIDGET (xtext)); +#endif +#if !HAVE_GTK3 + window = GTK_WIDGET (xtext)->window; +#endif + if (!window) + return 0; + gtk_xtext_get_pointer (window, NULL, &p_y, NULL); + win_height = gdk_window_get_height (window); if (buf->last_ent_end == NULL || /* If context has changed OR */ buf->pagetop_ent == NULL || /* pagetop_ent is reset OR */ p_y <= win_height || /* pointer not below bottom margin OR */ - adj->value >= adj->upper - adj->page_size) /* we're scrolled to bottom */ + xtext_adj_get_value (adj) >= + (xtext_adj_get_upper (adj) - xtext_adj_get_page_size (adj))) { xtext->scroll_tag = 0; return 0; @@ -1481,7 +1952,7 @@ gtk_xtext_scrolldown_timeout (GtkXText * xtext) xtext->select_start_y -= xtext->fontsize; xtext->select_start_adj++; - adj->value++; + xtext_adj_set_value (adj, xtext_adj_get_value (adj) + 1); gtk_adjustment_value_changed (adj); gtk_xtext_selection_draw (xtext, NULL, TRUE); gtk_xtext_render_ents (xtext, buf->pagetop_ent->next, buf->last_ent_end); @@ -1500,28 +1971,37 @@ gtk_xtext_scrollup_timeout (GtkXText * xtext) xtext_buffer *buf = xtext->buffer; GtkAdjustment *adj = xtext->adj; int delta_y; + GdkWindow *window; - gdk_window_get_pointer (GTK_WIDGET (xtext)->window, 0, &p_y, 0); +#if HAVE_GTK3 + window = gtk_widget_get_window (GTK_WIDGET (xtext)); +#endif +#if !HAVE_GTK3 + window = GTK_WIDGET (xtext)->window; +#endif + if (!window) + return 0; + gtk_xtext_get_pointer (window, NULL, &p_y, NULL); if (buf->last_ent_start == NULL || /* If context has changed OR */ buf->pagetop_ent == NULL || /* pagetop_ent is reset OR */ p_y >= 0 || /* not above top margin OR */ - adj->value == 0) /* we're scrolled to the top */ + xtext_adj_get_value (adj) == 0) /* we're scrolled to the top */ { xtext->scroll_tag = 0; return 0; } - if (adj->value < 0) + if (xtext_adj_get_value (adj) < 0) { - delta_y = adj->value * xtext->fontsize; - adj->value = 0; + delta_y = xtext_adj_get_value (adj) * xtext->fontsize; + xtext_adj_set_value (adj, 0); } else { delta_y = xtext->fontsize; - adj->value--; + xtext_adj_set_value (adj, xtext_adj_get_value (adj) - 1); } xtext->select_start_y += delta_y; - xtext->select_start_adj = adj->value; + xtext->select_start_adj = xtext_adj_get_value (adj); gtk_adjustment_value_changed (adj); gtk_xtext_selection_draw (xtext, NULL, TRUE); gtk_xtext_render_ents (xtext, buf->pagetop_ent->prev, buf->last_ent_end); @@ -1538,31 +2018,43 @@ gtk_xtext_selection_update (GtkXText * xtext, GdkEventMotion * event, int p_y, g { int win_height; int moved; + GdkWindow *window; if (xtext->scroll_tag) { return; } - win_height = gdk_window_get_height (gtk_widget_get_window (GTK_WIDGET (xtext))); +#if HAVE_GTK3 + window = gtk_widget_get_window (GTK_WIDGET (xtext)); +#endif +#if !HAVE_GTK3 + window = GTK_WIDGET (xtext)->window; +#endif + if (!window) + return; + win_height = gdk_window_get_height (window); /* selecting past top of window, scroll up! */ - if (p_y < 0 && xtext->adj->value >= 0) + if (p_y < 0 && xtext_adj_get_value (xtext->adj) >= 0) { gtk_xtext_scrollup_timeout (xtext); } /* selecting past bottom of window, scroll down! */ else if (p_y > win_height && - xtext->adj->value < (xtext->adj->upper - xtext->adj->page_size)) + xtext_adj_get_value (xtext->adj) < + (xtext_adj_get_upper (xtext->adj) - + xtext_adj_get_page_size (xtext->adj))) { gtk_xtext_scrolldown_timeout (xtext); } else { - moved = (int)xtext->adj->value - xtext->select_start_adj; + moved = (int)xtext_adj_get_value (xtext->adj) - + xtext->select_start_adj; xtext->select_start_y -= (moved * xtext->fontsize); - xtext->select_start_adj = xtext->adj->value; + xtext->select_start_adj = xtext_adj_get_value (xtext->adj); gtk_xtext_selection_draw (xtext, event, render); } } @@ -1662,6 +2154,9 @@ static gboolean gtk_xtext_leave_notify (GtkWidget * widget, GdkEventCrossing * event) { GtkXText *xtext = GTK_XTEXT (widget); +#if HAVE_GTK3 + GdkWindow *window = gtk_widget_get_window (widget); +#endif if (xtext->cursor_hand) { @@ -1669,7 +2164,13 @@ gtk_xtext_leave_notify (GtkWidget * widget, GdkEventCrossing * event) xtext->hilight_start = -1; xtext->hilight_end = -1; xtext->cursor_hand = FALSE; +#if HAVE_GTK3 + if (window) + gdk_window_set_cursor (window, 0); +#endif +#if !HAVE_GTK3 gdk_window_set_cursor (widget->window, 0); +#endif xtext->hilight_ent = NULL; } @@ -1679,7 +2180,13 @@ gtk_xtext_leave_notify (GtkWidget * widget, GdkEventCrossing * event) xtext->hilight_start = -1; xtext->hilight_end = -1; xtext->cursor_resize = FALSE; +#if HAVE_GTK3 + if (window) + gdk_window_set_cursor (window, 0); +#endif +#if !HAVE_GTK3 gdk_window_set_cursor (widget->window, 0); +#endif xtext->hilight_ent = NULL; } @@ -1768,12 +2275,25 @@ gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event) int redraw, tmp, x, y, offset, len, line_x; textentry *word_ent; int word_type; + GdkWindow *window; + GtkAllocation allocation; - gdk_window_get_pointer (widget->window, &x, &y, &mask); +#if HAVE_GTK3 + window = gtk_widget_get_window (widget); + gtk_widget_get_allocation (widget, &allocation); +#endif +#if !HAVE_GTK3 + window = widget->window; + allocation = widget->allocation; +#endif + if (!window) + return FALSE; + + gtk_xtext_get_pointer (window, &x, &y, &mask); if (xtext->moving_separator) { - if (x < (3 * widget->allocation.width) / 5 && x > 15) + if (x < (3 * allocation.width) / 5 && x > 15) { tmp = xtext->buffer->indent; xtext->buffer->indent = x; @@ -1782,8 +2302,9 @@ gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event) { gtk_xtext_recalc_widths (xtext->buffer, FALSE); if (xtext->buffer->scrollbar_down) - gtk_adjustment_set_value (xtext->adj, xtext->adj->upper - - xtext->adj->page_size); + xtext_adj_set_value (xtext->adj, + xtext_adj_get_upper (xtext->adj) - + xtext_adj_get_page_size (xtext->adj)); if (!xtext->io_tag) xtext->io_tag = g_timeout_add (REFRESH_TIMEOUT, (GSourceFunc) @@ -1823,8 +2344,7 @@ gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event) { if (!xtext->cursor_resize) { - gdk_window_set_cursor (GTK_WIDGET (xtext)->window, - xtext->resize_cursor); + gdk_window_set_cursor (window, xtext->resize_cursor); xtext->cursor_hand = FALSE; xtext->cursor_resize = TRUE; } @@ -1845,8 +2365,7 @@ gtk_xtext_motion_notify (GtkWidget * widget, GdkEventMotion * event) { if (!xtext->cursor_hand) { - gdk_window_set_cursor (GTK_WIDGET (xtext)->window, - xtext->hand_cursor); + gdk_window_set_cursor (window, xtext->hand_cursor); xtext->cursor_hand = TRUE; xtext->cursor_resize = FALSE; } @@ -1946,12 +2465,20 @@ gtk_xtext_button_release (GtkWidget * widget, GdkEventButton * event) GtkXText *xtext = GTK_XTEXT (widget); unsigned char *word; int old; + GtkAllocation allocation; + +#if HAVE_GTK3 + gtk_widget_get_allocation (widget, &allocation); +#endif +#if !HAVE_GTK3 + allocation = widget->allocation; +#endif if (xtext->moving_separator) { xtext->moving_separator = FALSE; old = xtext->buffer->indent; - if (event->x < (4 * widget->allocation.width) / 5 && event->x > 15) + if (event->x < (4 * allocation.width) / 5 && event->x > 15) xtext->buffer->indent = event->x; gtk_xtext_fix_indent (xtext->buffer); if (xtext->buffer->indent != old) @@ -2022,8 +2549,18 @@ gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event) textentry *ent; unsigned char *word; int line_x, x, y, offset, len; + GdkWindow *window; - gdk_window_get_pointer (widget->window, &x, &y, &mask); +#if HAVE_GTK3 + window = gtk_widget_get_window (widget); +#endif +#if !HAVE_GTK3 + window = widget->window; +#endif + if (!window) + return FALSE; + + gtk_xtext_get_pointer (window, &x, &y, &mask); if (event->button == 3 || event->button == 2) /* right/middle click */ { @@ -2089,7 +2626,7 @@ gtk_xtext_button_press (GtkWidget * widget, GdkEventButton * event) xtext->button_down = TRUE; xtext->select_start_x = x; xtext->select_start_y = y; - xtext->select_start_adj = xtext->adj->value; + xtext->select_start_adj = xtext_adj_get_value (xtext->adj); return FALSE; } @@ -2251,7 +2788,19 @@ gtk_xtext_selection_get (GtkWidget * widget, case TARGET_COMPOUND_TEXT: #ifdef GDK_WINDOWING_X11 { - GdkDisplay *display = gdk_window_get_display (widget->window); + GdkDisplay *display; +#if HAVE_GTK3 + GdkWindow *window = gtk_widget_get_window (widget); + + if (!window || !GDK_IS_WINDOW (window)) + break; + display = gdk_window_get_display (window); + if (!display) + break; +#endif +#if !HAVE_GTK3 + display = gdk_window_get_display (widget->window); +#endif GdkAtom encoding; gint format; gint new_length; @@ -2283,17 +2832,21 @@ gtk_xtext_scroll (GtkWidget *widget, GdkEventScroll *event) if (event->direction == GDK_SCROLL_UP) /* mouse wheel pageUp */ { - new_value = xtext->adj->value - (xtext->adj->page_increment / 10); - if (new_value < xtext->adj->lower) - new_value = xtext->adj->lower; - gtk_adjustment_set_value (xtext->adj, new_value); + new_value = xtext_adj_get_value (xtext->adj) - + (xtext_adj_get_page_increment (xtext->adj) / 10); + if (new_value < xtext_adj_get_lower (xtext->adj)) + new_value = xtext_adj_get_lower (xtext->adj); + xtext_adj_set_value (xtext->adj, new_value); } else if (event->direction == GDK_SCROLL_DOWN) /* mouse wheel pageDn */ { - new_value = xtext->adj->value + (xtext->adj->page_increment / 10); - if (new_value > (xtext->adj->upper - xtext->adj->page_size)) - new_value = xtext->adj->upper - xtext->adj->page_size; - gtk_adjustment_set_value (xtext->adj, new_value); + new_value = xtext_adj_get_value (xtext->adj) + + (xtext_adj_get_page_increment (xtext->adj) / 10); + if (new_value > (xtext_adj_get_upper (xtext->adj) - + xtext_adj_get_page_size (xtext->adj))) + new_value = xtext_adj_get_upper (xtext->adj) - + xtext_adj_get_page_size (xtext->adj); + xtext_adj_set_value (xtext->adj, new_value); } return FALSE; @@ -2320,7 +2873,15 @@ gtk_xtext_scroll_adjustments (GtkXText *xtext, GtkAdjustment *hadj, GtkAdjustmen if (xtext->adj != vadj) { xtext->adj = vadj; +#if HAVE_GTK3 + if (g_object_is_floating (xtext->adj)) + g_object_ref_sink (xtext->adj); + else + g_object_ref (xtext->adj); +#endif +#if !HAVE_GTK3 g_object_ref_sink (xtext->adj); +#endif xtext->vc_signal_tag = g_signal_connect (xtext->adj, "value-changed", G_CALLBACK (gtk_xtext_adjustment_changed), @@ -2333,16 +2894,24 @@ gtk_xtext_scroll_adjustments (GtkXText *xtext, GtkAdjustment *hadj, GtkAdjustmen static void gtk_xtext_class_init (GtkXTextClass * class) { - GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkXTextClass *xtext_class; +#if HAVE_GTK3 + GObjectClass *object_class; +#endif +#if !HAVE_GTK3 + GtkObjectClass *object_class; +#endif +#if HAVE_GTK3 + object_class = G_OBJECT_CLASS (class); +#endif +#if !HAVE_GTK3 object_class = (GtkObjectClass *) class; +#endif widget_class = (GtkWidgetClass *) class; xtext_class = (GtkXTextClass *) class; - parent_class = g_type_class_peek (gtk_widget_get_type ()); - xtext_signals[WORD_CLICK] = g_signal_new ("word_click", G_TYPE_FROM_CLASS (object_class), @@ -2362,53 +2931,43 @@ gtk_xtext_class_init (GtkXTextClass * class) G_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT); +#if HAVE_GTK3 + object_class->dispose = gtk_xtext_dispose; + object_class->finalize = gtk_xtext_finalize; +#else object_class->destroy = gtk_xtext_destroy; +#endif widget_class->realize = gtk_xtext_realize; widget_class->unrealize = gtk_xtext_unrealize; +#if !HAVE_GTK3 widget_class->size_request = gtk_xtext_size_request; +#endif widget_class->size_allocate = gtk_xtext_size_allocate; widget_class->button_press_event = gtk_xtext_button_press; widget_class->button_release_event = gtk_xtext_button_release; widget_class->motion_notify_event = gtk_xtext_motion_notify; widget_class->selection_clear_event = (void *)gtk_xtext_selection_kill; widget_class->selection_get = gtk_xtext_selection_get; +#if HAVE_GTK3 + widget_class->draw = gtk_xtext_draw; + widget_class->get_preferred_width = gtk_xtext_get_preferred_width; + widget_class->get_preferred_height = gtk_xtext_get_preferred_height; + widget_class->get_preferred_height_for_width = gtk_xtext_get_preferred_height_for_width; +#endif +#if !HAVE_GTK3 widget_class->expose_event = gtk_xtext_expose; +#endif widget_class->scroll_event = gtk_xtext_scroll; widget_class->leave_notify_event = gtk_xtext_leave_notify; +#if !HAVE_GTK3 widget_class->set_scroll_adjustments_signal = xtext_signals[SET_SCROLL_ADJUSTMENTS]; +#endif xtext_class->word_click = NULL; xtext_class->set_scroll_adjustments = gtk_xtext_scroll_adjustments; } -GType -gtk_xtext_get_type (void) -{ - static GType xtext_type = 0; - - if (!xtext_type) - { - static const GTypeInfo xtext_info = - { - sizeof (GtkXTextClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_xtext_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GtkXText), - 0, /* n_preallocs */ - (GInstanceInitFunc) gtk_xtext_init, - }; - - xtext_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkXText", - &xtext_info, 0); - } - - return xtext_type; -} - /* strip MIRC colors and other attribs. */ /* CL: needs to strip hidden when called by gtk_xtext_text_width, but not when copying text */ @@ -2591,6 +3150,9 @@ gtk_xtext_render_flush (GtkXText * xtext, int x, int y, unsigned char *str, int dest_x = 0, dest_y = 0; int tile_x = xtext->ts_x; int tile_y = xtext->ts_y; +#if HAVE_GTK3 + GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (xtext)); +#endif if (xtext->dont_render || len < 1 || xtext->hidden) return 0; @@ -2614,8 +3176,16 @@ gtk_xtext_render_flush (GtkXText * xtext, int x, int y, unsigned char *str, goto dounder; } +#if HAVE_GTK3 + if (!window) + return str_width; + surface = gdk_window_create_similar_surface (window, + CAIRO_CONTENT_COLOR_ALPHA, str_width, xtext->fontsize); +#endif +#if !HAVE_GTK3 surface = gdk_window_create_similar_surface (GTK_WIDGET (xtext)->window, CAIRO_CONTENT_COLOR_ALPHA, str_width, xtext->fontsize); +#endif if (surface) { dest_x = x; @@ -3660,9 +4230,18 @@ gtk_xtext_calc_lines (xtext_buffer *buf, int fire_signal) int width; int height; int lines; + GdkWindow *window; - height = gdk_window_get_height (gtk_widget_get_window (GTK_WIDGET (buf->xtext))); - width = gdk_window_get_width (gtk_widget_get_window (GTK_WIDGET (buf->xtext))); +#if HAVE_GTK3 + window = gtk_widget_get_window (GTK_WIDGET (buf->xtext)); +#endif +#if !HAVE_GTK3 + window = GTK_WIDGET (buf->xtext)->window; +#endif + if (!window) + return; + height = gdk_window_get_height (window); + width = gdk_window_get_width (window); width -= MARGIN; if (width < 30 || height < buf->xtext->fontsize || width < buf->indent + 30) @@ -3752,12 +4331,21 @@ gtk_xtext_render_ents (GtkXText * xtext, textentry * enta, textentry * entb) int height; int subline; int drawing = FALSE; + GdkWindow *window; if (xtext->buffer->indent < MARGIN) xtext->buffer->indent = MARGIN; /* 2 pixels is our left margin */ - height = gdk_window_get_height (gtk_widget_get_window (GTK_WIDGET (xtext))); - width = gdk_window_get_width (gtk_widget_get_window (GTK_WIDGET (xtext))); +#if HAVE_GTK3 + window = gtk_widget_get_window (GTK_WIDGET (xtext)); +#endif +#if !HAVE_GTK3 + window = GTK_WIDGET (xtext)->window; +#endif + if (!window) + return 0; + height = gdk_window_get_height (window); + width = gdk_window_get_width (window); width -= MARGIN; if (width < 32 || height < xtext->fontsize || width < xtext->buffer->indent + 30) @@ -3830,14 +4418,35 @@ gtk_xtext_render_ents (GtkXText * xtext, textentry * enta, textentry * entb) static void gtk_xtext_render_page (GtkXText * xtext) { + /* + * GTK3/Wayland is frame-driven. Drawing directly to a GdkWindow outside the + * widget's ::draw handler can result in the compositor never presenting the + * new buffer. Symptom: chat only updates after you move/resize the window. + * + * If we're not currently inside ::draw, xtext->draw_cr is NULL. In that case + * just request a redraw and let the normal GTK paint cycle do the work. + */ +#if HAVE_GTK3 + if (xtext->draw_cr == NULL) + { + GtkWidget *w = GTK_WIDGET (xtext); + if (gtk_widget_get_realized (w)) + gtk_widget_queue_draw (w); + return; + } +#endif + textentry *ent; int line; int lines_max; int width; int height; int subline; - int startline = xtext->adj->value; + gdouble adj_value = xtext_adj_get_value (xtext->adj); + gdouble adj_page_size = xtext_adj_get_page_size (xtext->adj); + int startline = adj_value; int pos, overlap; + GdkWindow *window; if(!gtk_widget_get_realized(GTK_WIDGET(xtext))) return; @@ -3845,13 +4454,22 @@ gtk_xtext_render_page (GtkXText * xtext) if (xtext->buffer->indent < MARGIN) xtext->buffer->indent = MARGIN; /* 2 pixels is our left margin */ - width = gdk_window_get_width (GTK_WIDGET (xtext)->window); - height = gdk_window_get_height (GTK_WIDGET (xtext)->window); +#if HAVE_GTK3 + window = gtk_widget_get_window (GTK_WIDGET (xtext)); +#endif +#if !HAVE_GTK3 + window = GTK_WIDGET (xtext)->window; +#endif + if (!window) + return; + width = gdk_window_get_width (window); + height = gdk_window_get_height (window); if (width < 34 || height < xtext->fontsize || width < xtext->buffer->indent + 32) return; - xtext->pixel_offset = (xtext->adj->value - startline) * xtext->fontsize; + xtext->pixel_offset = (adj_value - startline) * + xtext->fontsize; subline = line = 0; ent = xtext->buffer->text_first; @@ -3863,10 +4481,10 @@ gtk_xtext_render_page (GtkXText * xtext) xtext->buffer->pagetop_subline = subline; xtext->buffer->pagetop_line = startline; - if (xtext->buffer->num_lines <= xtext->adj->page_size) + if (xtext->buffer->num_lines <= adj_page_size) dontscroll (xtext->buffer); - pos = xtext->adj->value * xtext->fontsize; + pos = adj_value * xtext->fontsize; overlap = xtext->buffer->last_pixel_pos - pos; xtext->buffer->last_pixel_pos = pos; @@ -3892,7 +4510,12 @@ gtk_xtext_render_page (GtkXText * xtext) cr = xtext_create_context (xtext); cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); +#if HAVE_GTK3 + surface = xtext_surface_from_window (window); +#endif +#if !HAVE_GTK3 surface = xtext_surface_from_window (GTK_WIDGET (xtext)->window); +#endif if (!surface) { cairo_restore (cr); @@ -3919,7 +4542,12 @@ gtk_xtext_render_page (GtkXText * xtext) cr = xtext_create_context (xtext); cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); +#if HAVE_GTK3 + surface = xtext_surface_from_window (window); +#endif +#if !HAVE_GTK3 surface = xtext_surface_from_window (GTK_WIDGET (xtext)->window); +#endif if (!surface) { cairo_restore (cr); @@ -4047,7 +4675,9 @@ gtk_xtext_remove_top (xtext_buffer *buffer) buffer->old_value -= g_slist_length (ent->sublines); if (buffer->xtext->buffer == buffer) /* is it the current buffer? */ { - buffer->xtext->adj->value -= g_slist_length (ent->sublines); + xtext_adj_set_value (buffer->xtext->adj, + xtext_adj_get_value (buffer->xtext->adj) - + g_slist_length (ent->sublines)); buffer->xtext->select_start_adj -= g_slist_length (ent->sublines); } @@ -4182,13 +4812,22 @@ gtk_xtext_check_ent_visibility (GtkXText * xtext, textentry *find_ent, int add) int lines; xtext_buffer *buf = xtext->buffer; int height; + GdkWindow *window; if (find_ent == NULL) { return FALSE; } - height = gdk_window_get_height (gtk_widget_get_window (GTK_WIDGET (xtext))); +#if HAVE_GTK3 + window = gtk_widget_get_window (GTK_WIDGET (xtext)); +#endif +#if !HAVE_GTK3 + window = GTK_WIDGET (xtext)->window; +#endif + if (!window) + return FALSE; + height = gdk_window_get_height (window); ent = buf->pagetop_ent; /* If top line not completely displayed return FALSE */ @@ -4589,19 +5228,20 @@ gtk_xtext_search (GtkXText * xtext, const gchar *text, gtk_xtext_search_flags fl { value += g_slist_length (ent->sublines); } - if (value > adj->upper - adj->page_size) + if (value > xtext_adj_get_upper (adj) - xtext_adj_get_page_size (adj)) { - value = adj->upper - adj->page_size; + value = xtext_adj_get_upper (adj) - xtext_adj_get_page_size (adj); } else if ((flags & backward) && ent) { - value -= adj->page_size - g_slist_length (ent->sublines); + value -= xtext_adj_get_page_size (adj) - + g_slist_length (ent->sublines); if (value < 0) { value = 0; } } - gtk_adjustment_set_value (adj, value); + xtext_adj_set_value (adj, value); } gtk_widget_queue_draw (GTK_WIDGET (xtext)); @@ -4620,18 +5260,19 @@ gtk_xtext_render_page_timeout (GtkXText * xtext) xtext->add_io_tag = 0; /* less than a complete page? */ - if (xtext->buffer->num_lines <= adj->page_size) + if (xtext->buffer->num_lines <= xtext_adj_get_page_size (adj)) { xtext->buffer->old_value = 0; - adj->value = 0; + xtext_adj_set_value (adj, 0); gtk_xtext_render_page (xtext); } else if (xtext->buffer->scrollbar_down) { g_signal_handler_block (xtext->adj, xtext->vc_signal_tag); gtk_xtext_adjustment_set (xtext->buffer, FALSE); - gtk_adjustment_set_value (adj, adj->upper - adj->page_size); + xtext_adj_set_value (adj, + xtext_adj_get_upper (adj) - xtext_adj_get_page_size (adj)); g_signal_handler_unblock (xtext->adj, xtext->vc_signal_tag); - xtext->buffer->old_value = adj->value; + xtext->buffer->old_value = xtext_adj_get_value (adj); gtk_xtext_render_page (xtext); } else { @@ -4703,7 +5344,7 @@ gtk_xtext_append_entry (xtext_buffer *buf, textentry * ent, time_t stamp) if (buf->xtext->buffer == buf) { /* this could be improved */ - if ((buf->num_lines - 1) <= buf->xtext->adj->page_size) + if ((buf->num_lines - 1) <= xtext_adj_get_page_size (buf->xtext->adj)) dontscroll (buf); if (!buf->xtext->add_io_tag) @@ -4722,7 +5363,8 @@ gtk_xtext_append_entry (xtext_buffer *buf, textentry * ent, time_t stamp) } if (buf->scrollbar_down) { - buf->old_value = buf->num_lines - buf->xtext->adj->page_size; + buf->old_value = buf->num_lines - + xtext_adj_get_page_size (buf->xtext->adj); if (buf->old_value < 0) buf->old_value = 0; } @@ -5004,14 +5646,15 @@ gtk_xtext_moveto_marker_pos (GtkXText *xtext) value += g_slist_length (ent->sublines); ent = ent->next; } - if (value >= adj->value && value < adj->value + adj->page_size) + if (value >= xtext_adj_get_value (adj) && + value < xtext_adj_get_value (adj) + xtext_adj_get_page_size (adj)) return MARKER_IS_SET; - value -= adj->page_size / 2; + value -= xtext_adj_get_page_size (adj) / 2; if (value < 0) value = 0; - if (value > adj->upper - adj->page_size) - value = adj->upper - adj->page_size; - gtk_adjustment_set_value (adj, value); + if (value > xtext_adj_get_upper (adj) - xtext_adj_get_page_size (adj)) + value = xtext_adj_get_upper (adj) - xtext_adj_get_page_size (adj); + xtext_adj_set_value (adj, value); gtk_xtext_render_page (xtext); } @@ -5027,6 +5670,7 @@ void gtk_xtext_buffer_show (GtkXText *xtext, xtext_buffer *buf, int render) { int w, h; + GdkWindow *window; buf->xtext = xtext; @@ -5050,8 +5694,16 @@ gtk_xtext_buffer_show (GtkXText *xtext, xtext_buffer *buf, int render) if (!gtk_widget_get_realized (GTK_WIDGET (xtext))) gtk_widget_realize (GTK_WIDGET (xtext)); - h = gdk_window_get_height (gtk_widget_get_window (GTK_WIDGET (xtext))); - w = gdk_window_get_width (gtk_widget_get_window (GTK_WIDGET (xtext))); +#if HAVE_GTK3 + window = gtk_widget_get_window (GTK_WIDGET (xtext)); +#endif +#if !HAVE_GTK3 + window = GTK_WIDGET (xtext)->window; +#endif + if (!window) + return; + h = gdk_window_get_height (window); + w = gdk_window_get_width (window); /* after a font change */ if (buf->needs_recalc) @@ -5063,25 +5715,28 @@ gtk_xtext_buffer_show (GtkXText *xtext, xtext_buffer *buf, int render) /* now change to the new buffer */ xtext->buffer = buf; dontscroll (buf); /* force scrolling off */ - xtext->adj->value = buf->old_value; - xtext->adj->upper = buf->num_lines; - - /* if the scrollbar was down, keep it down */ - if (xtext->buffer->scrollbar_down && xtext->adj->value < - xtext->adj->upper - xtext->adj->page_size) { - xtext->adj->value = xtext->adj->upper - xtext->adj->page_size; - } + gdouble lower = 0; + gdouble value = buf->old_value; + gdouble upper = buf->num_lines; + gdouble page_size = xtext_adj_get_page_size (xtext->adj); - if (xtext->adj->upper == 0) - xtext->adj->upper = 1; - /* sanity check */ - else if (xtext->adj->value > xtext->adj->upper - xtext->adj->page_size) - { - /*buf->pagetop_ent = NULL;*/ - xtext->adj->value = xtext->adj->upper - xtext->adj->page_size; - if (xtext->adj->value < 0) - xtext->adj->value = 0; + /* if the scrollbar was down, keep it down */ + if (xtext->buffer->scrollbar_down && value < upper - page_size) + value = upper - page_size; + + if (upper == 0) + upper = 1; + /* sanity check */ + else if (value > upper - page_size) + { + /*buf->pagetop_ent = NULL;*/ + value = upper - page_size; + if (value < 0) + value = 0; + } + + xtext_adjustment_apply (xtext->adj, lower, upper, value, page_size); } if (render) @@ -5093,19 +5748,50 @@ gtk_xtext_buffer_show (GtkXText *xtext, xtext_buffer *buf, int render) buf->window_height = h; gtk_xtext_calc_lines (buf, FALSE); if (buf->scrollbar_down) - gtk_adjustment_set_value (xtext->adj, xtext->adj->upper - - xtext->adj->page_size); + xtext_adj_set_value (xtext->adj, + xtext_adj_get_upper (xtext->adj) - + xtext_adj_get_page_size (xtext->adj)); } else if (buf->window_height != h) { buf->window_height = h; buf->pagetop_ent = NULL; if (buf->scrollbar_down) - xtext->adj->value = xtext->adj->upper; + xtext_adj_set_value (xtext->adj, + xtext_adj_get_upper (xtext->adj)); gtk_xtext_adjustment_set (buf, FALSE); } gtk_xtext_render_page (xtext); +#if HAVE_GTK3 + { + GtkAllocation allocation; + gdouble lower = 0; + gdouble upper = buf->num_lines; + gdouble value = gtk_adjustment_get_value (xtext->adj); + gdouble page_size; + + if (upper == 0) + upper = 1; + + gtk_widget_get_allocation (GTK_WIDGET (xtext), &allocation); + page_size = allocation.height / xtext->fontsize; + + if (value > upper - page_size) + { + buf->scrollbar_down = TRUE; + value = upper - page_size; + } + + if (value < 0) + value = 0; + + xtext_adjustment_apply (xtext->adj, lower, upper, value, page_size); + gtk_adjustment_set_page_increment (xtext->adj, page_size); + gtk_adjustment_value_changed (xtext->adj); + } +#else gtk_adjustment_changed (xtext->adj); +#endif } } diff --git a/src/fe-gtk/xtext.h b/src/fe-gtk/xtext.h index c7ddedaa..5cbb6b07 100644 --- a/src/fe-gtk/xtext.h +++ b/src/fe-gtk/xtext.h @@ -21,9 +21,15 @@ #define ZOITECHAT_XTEXT_H #include +#if !defined(GTK_MAJOR_VERSION) || GTK_MAJOR_VERSION < 3 +#include +#endif #include #include "xtext-color.h" +typedef struct _GtkXText GtkXText; +typedef struct _GtkXTextClass GtkXTextClass; + #define GTK_TYPE_XTEXT (gtk_xtext_get_type ()) #define GTK_XTEXT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GTK_TYPE_XTEXT, GtkXText)) #define GTK_XTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_XTEXT, GtkXTextClass)) @@ -31,6 +37,8 @@ #define GTK_IS_XTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_XTEXT)) #define GTK_XTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_XTEXT, GtkXTextClass)) +GType gtk_xtext_get_type (void); + #define ATTR_BOLD '\002' #define ATTR_COLOR '\003' #define ATTR_BLINK '\006' @@ -52,9 +60,6 @@ #define XTEXT_BG 35 #define XTEXT_MARKER 36 /* for marker line */ #define XTEXT_MAX_COLOR 41 - -typedef struct _GtkXText GtkXText; -typedef struct _GtkXTextClass GtkXTextClass; typedef struct textentry textentry; /* @@ -125,7 +130,11 @@ typedef struct { struct _GtkXText { - GtkWidget widget; +#if HAVE_GTK3 + GtkWidget parent_instance; +#else + GtkWidget parent; +#endif xtext_buffer *buffer; xtext_buffer *orig_buffer; @@ -135,6 +144,7 @@ struct _GtkXText cairo_surface_t *background_surface; /* 0 = use palette[19] */ GdkWindow *draw_window; /* points to ->window */ cairo_surface_t *draw_surface; /* temporary surface for offscreen draws */ + cairo_t *draw_cr; /* GTK3 draw context */ GdkCursor *hand_cursor; GdkCursor *resize_cursor; @@ -293,6 +303,5 @@ xtext_buffer *gtk_xtext_buffer_new (GtkXText *xtext); void gtk_xtext_buffer_free (xtext_buffer *buf); void gtk_xtext_buffer_show (GtkXText *xtext, xtext_buffer *buf, int render); void gtk_xtext_copy_selection (GtkXText *xtext); -GType gtk_xtext_get_type (void); #endif diff --git a/src/fe-gtk/zoitechat.rc.tt b/src/fe-gtk/zoitechat.rc.tt index f964896b..64930d67 100644 --- a/src/fe-gtk/zoitechat.rc.tt +++ b/src/fe-gtk/zoitechat.rc.tt @@ -1,7 +1,7 @@ #include #include "config.h" -#define COMMA_VERSION <#= [string]::Join(',', $versionParts) #>,0 +#define COMMA_VERSION <#= [string]::Join(',', ($versionParts | %{ ($_ -split '[^0-9]')[0] })) #>,0 XC_ICON ICON "<#= $env:SOLUTIONDIR -replace '\\', '/' #>data/icons/zoitechat.ico" diff --git a/src/fe-text/fe-text.vcxproj b/src/fe-text/fe-text.vcxproj index f43d5dd0..5ff288cf 100644 --- a/src/fe-text/fe-text.vcxproj +++ b/src/fe-text/fe-text.vcxproj @@ -30,7 +30,7 @@ WIN32;NDEBUG;_CONSOLE;$(OwnFlags);%(PreprocessorDefinitions) - $(ZoiteChatLib);$(DepsRoot)\include;$(Glib);%(AdditionalIncludeDirectories) + $(ZoiteChatLib);$(DepsRoot)\include;$(OpenSslInclude);$(Glib);%(AdditionalIncludeDirectories) Console @@ -44,7 +44,7 @@ WIN32;_WIN64;_AMD64_;NDEBUG;_CONSOLE;$(OwnFlags);%(PreprocessorDefinitions) - $(ZoiteChatLib);$(DepsRoot)\include;$(Glib);%(AdditionalIncludeDirectories) + $(ZoiteChatLib);$(DepsRoot)\include;$(OpenSslInclude);$(Glib);%(AdditionalIncludeDirectories) Console diff --git a/src/libenchant_win8/libenchant_win8.vcxproj b/src/libenchant_win8/libenchant_win8.vcxproj index 94adb153..9a0228e9 100644 --- a/src/libenchant_win8/libenchant_win8.vcxproj +++ b/src/libenchant_win8/libenchant_win8.vcxproj @@ -32,7 +32,7 @@ - ..\common;$(ZoiteChatLib);$(DepsRoot)\include\enchant;$(DepsRoot)\include;$(Glib);%(AdditionalIncludeDirectories) + ..\common;$(ZoiteChatLib);$(DepsRoot)\include\enchant;$(DepsRoot)\include;$(OpenSslInclude);$(Glib);%(AdditionalIncludeDirectories) $(DepLibs);%(AdditionalDependencies) diff --git a/win32/copy/copy.vcxproj b/win32/copy/copy.vcxproj index e8bfbd02..3053ba91 100644 --- a/win32/copy/copy.vcxproj +++ b/win32/copy/copy.vcxproj @@ -1,102 +1,118 @@ - - - - v142 - Application - - - - Release - Win32 - - - Release - x64 - - - - {C9B735E4-75BC-45AC-A5E3-39A6D076F912} - copy - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + v143 + Application + + + + Release + Win32 + + + Release + x64 + + + + {C9B735E4-75BC-45AC-A5E3-39A6D076F912} + copy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/win32/installer/installer.vcxproj b/win32/installer/installer.vcxproj index 56760abd..24cf1c71 100644 --- a/win32/installer/installer.vcxproj +++ b/win32/installer/installer.vcxproj @@ -1,7 +1,7 @@ - v142 + v143 Application @@ -25,6 +25,11 @@ $(ZoiteChatRel) + + "$(ProgramFiles(x86))\Inno Setup 6\ISCC.exe" + "$(ProgramFiles)\Inno Setup 6\ISCC.exe" + ISCC.exe + @@ -37,6 +42,7 @@ @@ -46,9 +52,14 @@ $(IsccPath) /dPROJECTDIR="$(ProjectDir)" /dAPPARCH="$(Platform)" "$(ZoiteChatBin - + + + + + + diff --git a/win32/installer/installer.vcxproj.filters b/win32/installer/installer.vcxproj.filters index bb41f83d..d8df542d 100644 --- a/win32/installer/installer.vcxproj.filters +++ b/win32/installer/installer.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -7,10 +7,7 @@ - - Resource Files - - + Resource Files @@ -20,4 +17,4 @@ Resource Files - \ No newline at end of file + diff --git a/win32/installer/zoitechat.iss.tt b/win32/installer/zoitechat.iss.tt index 14de669c..c06df2e4 100644 --- a/win32/installer/zoitechat.iss.tt +++ b/win32/installer/zoitechat.iss.tt @@ -5,7 +5,10 @@ ;#define PROJECTDIR "C:\...\zoitechat\win32\installer\" ;http://mitrich.net23.net/?/inno-download-plugin.html +#ifexist "idp.iss" +#define USE_INNO_DOWNLOAD_PLUGIN #include +#endif [Setup] AppName=ZoiteChat @@ -110,62 +113,59 @@ Source: "readme.url"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "cert.pem"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "share\xml\*"; DestDir: "{app}\share\xml"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs Source: "share\doc\*"; DestDir: "{app}\share\doc"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs -Source: "share\themes\MS-Windows\*"; DestDir: "{app}\share\themes\MS-Windows"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs +Source: "share\themes\MS-Windows\*"; DestDir: "{app}\share\themes\MS-Windows"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs +Source: "share\glib-2.0\schemas\*"; DestDir: "{app}\share\glib-2.0\schemas"; Flags: ignoreversion createallsubdirs recursesubdirs skipifsourcedoesntexist; Components: libs Source: "share\locale\*"; DestDir: "{app}\share\locale"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: translations Source: "etc\fonts\*"; DestDir: "{app}\etc\fonts"; Flags: ignoreversion createallsubdirs recursesubdirs; Components: libs Source: "atk-1.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -Source: "cairo.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -Source: "freetype.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "cairo-2.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "freetype-6.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "fribidi-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -Source: "fontconfig.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "fontconfig-1.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "gdk_pixbuf-2.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -Source: "gdk-win32-2.0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "gdk-3-vs17.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "epoxy-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "gio-2.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "glib-2.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "gmodule-2.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "gobject-2.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -#if APPARCH == "x64" Source: "gspawn-win64-helper.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "gspawn-win64-helper-console.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -#else -Source: "gspawn-win32-helper.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -Source: "gspawn-win32-helper-console.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -#endif Source: "gthread-2.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -Source: "gtk-win32-2.0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "iconv.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -#if APPARCH == "x64" -Source: "libcrypto-1_1-x64.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -Source: "libssl-1_1-x64.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -#else -Source: "libcrypto-1_1.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -Source: "libssl-1_1.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -#endif +Source: "libcrypto-3-x64.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "libssl-3-x64.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "libenchant.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -Source: "ffi-7.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "ffi-8.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "intl.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "libpng16.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs -Source: "libxml2.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "xml2-16.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "pango-1.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "pangocairo-1.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "cairo-gobject-2.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "pangoft2-1.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "pangowin32-1.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "zlib1.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "jpeg62.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "harfbuzz.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "gtk-3-vs17.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "libexpat.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "pcre2-8-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "pixman-1-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs +Source: "tiff.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: libs Source: "plugins\hcnotifications-winrt.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: libs Source: "lib\enchant\*"; DestDir: "{app}\lib\enchant"; Flags: ignoreversion; Components: libs -Source: "lib\gtk-2.0\i686-pc-vs14\engines\*"; DestDir: "{app}\lib\gtk-2.0\i686-pc-vs14\engines"; Flags: ignoreversion; Components: libs - -Source: "girepository-1.0-1.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: langs\lua +Source: "girepository-2.0-0.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: langs\lua Source: "lua51.dll"; DestDir: "{app}"; Flags: ignoreversion; Components: langs\lua -Source: "lib\lua\lgi\*.dll"; DestDir: "{app}\lib\lua\lgi"; Flags: ignoreversion; Components: langs\lua +Source: "lib\lua\2.1\lgi\*.dll"; DestDir: "{app}\lib\lua\lgi"; Flags: ignoreversion; Components: langs\lua Source: "lib\girepository-1.0\*.typelib"; DestDir: "{app}\lib\girepository-1.0"; Flags: ignoreversion; Components: langs\lua -Source: "share\lua\*.lua"; DestDir: "{app}\share\lua"; Flags: ignoreversion; Components: langs\lua -Source: "share\lua\lgi\*.lua"; DestDir: "{app}\share\lua\lgi"; Flags: ignoreversion; Components: langs\lua -Source: "share\lua\lgi\override\*.lua"; DestDir: "{app}\share\lua\lgi\override"; Flags: ignoreversion; Components: langs\lua +Source: "share\lua\2.1\*.lua"; DestDir: "{app}\share\lua"; Flags: ignoreversion; Components: langs\lua +Source: "share\lua\2.1\lgi\*.lua"; DestDir: "{app}\share\lua\lgi"; Flags: ignoreversion; Components: langs\lua +Source: "share\lua\2.1\lgi\override\*.lua"; DestDir: "{app}\share\lua\lgi\override"; Flags: ignoreversion; Components: langs\lua Source: "plugins\hclua.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: langs\lua Source: "plugins\hcchecksum.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion; Components: plugins\checksum @@ -203,6 +203,22 @@ Name: "{commonappdata}\Microsoft\Internet Explorer\Quick Launch\ZoiteChat"; File BeveledLabel= {#APPNAM} [Code] +#ifndef USE_INNO_DOWNLOAD_PLUGIN +// The Inno Download Plugin isn't always installed in CI environments. +// Provide no-op fallback procedures so installer compilation still succeeds. +procedure idpDownloadAfter(PageID: Integer); +begin +end; + +procedure idpClearFiles; +begin +end; + +procedure idpAddFile(URL: String; Filename: String); +begin +end; +#endif + ///////////////////////////////////////////////////////////////////// procedure InitializeWizard; begin @@ -310,8 +326,8 @@ begin idpAddFile(PERL, ExpandConstant('{tmp}\perl.msi')) end; - if IsComponentSelected('langs\python\python3') and not CheckDLL('python314.dll') then - idpAddFile(PY3, ExpandConstant('{tmp}\python.exe')); + if IsComponentSelected('langs\python') and not CheckDLL('python314.dll') then + idpAddFile(PY3, ExpandConstant('{tmp}\python.exe')); end; end; end; diff --git a/win32/nls/nls.vcxproj b/win32/nls/nls.vcxproj index b0f169d7..13143bfb 100644 --- a/win32/nls/nls.vcxproj +++ b/win32/nls/nls.vcxproj @@ -1,7 +1,7 @@ - v142 + v143 Application @@ -28,7 +28,7 @@ cd ..\..\po -rmdir /q /s "$(OutDir)\locale" +if exist "$(OutDir)\locale" rmdir /q /s "$(OutDir)\locale" mkdir "$(OutDir)\locale" for %%A in (*.po) do ( mkdir "$(OutDir)\locale\%%~nA\LC_MESSAGES" @@ -40,3 +40,4 @@ mkdir "$(OutDir)\locale\%%~nA\LC_MESSAGES" + diff --git a/win32/version.txt b/win32/version.txt index b92cdb1d..9d466af9 100644 --- a/win32/version.txt +++ b/win32/version.txt @@ -1 +1 @@ -2.17.4 +2.18.0-pre1 diff --git a/win32/zoitechat.props b/win32/zoitechat.props index 3ae6f0b0..d1641f3e 100644 --- a/win32/zoitechat.props +++ b/win32/zoitechat.props @@ -1,83 +1,181 @@ - - - - - - - c:\gtk-build\gtk - c:\gtk-build\gendef - c:\gtk-build\perl-5.20 - c:\gtk-build\python-3.14 - c:\gtk-build\WinSparkle - - - - - - GTK_DISABLE_DEPRECATED;GDK_PIXBUF_DISABLE_DEPRECATED;G_DISABLE_SINGLE_INCLUDES;GDK_PIXBUF_DISABLE_SINGLE_INCLUDES;GTK_DISABLE_SINGLE_INCLUDES;HAVE_X509_GET_SIGNATURE_NID;HAVE_SSL_CTX_GET_SSL_METHOD;DEFAULT_CERT_FILE="cert.pem";HAVE_STRTOULL;strtoull=_strtoui64;strcasecmp=stricmp;strncasecmp=strnicmp;__inline__=__inline - - $(YourDepsPath)\$(PlatformName)\release - $(YourGendefPath) - $(YourWinSparklePath)\$(PlatformName) - $(YourPerlPath)\$(PlatformName) - perl520 - $(YourPython3Path)\$(PlatformName) - python314 - hcpython3 - $(DepsRoot)\include\luajit-2.1 - hclua - lua51 - $(DepsRoot)\include\glib-2.0;$(DepsRoot)\lib\glib-2.0\include;$(DepsRoot)\include\libxml2 - $(DepsRoot)\include\gtk-2.0;$(DepsRoot)\lib\gtk-2.0\include;$(DepsRoot)\include\atk-1.0;$(DepsRoot)\include\cairo;$(DepsRoot)\include\pango-1.0;$(DepsRoot)\include\gdk-pixbuf-2.0 - gtk-win32-2.0.lib;gdk-win32-2.0.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;intl.lib;libxml2.lib;libcrypto.lib;libssl.lib;ssleay32.lib;wininet.lib;winmm.lib;ws2_32.lib - $(SolutionDir)..\data\\ - $(SolutionDir)..\..\zoitechat-build - $(ZoiteChatBuild)\$(PlatformName)\bin\ - $(ZoiteChatBuild)\$(PlatformName)\obj\ - $(ZoiteChatBuild)\$(PlatformName)\lib\ - $(ZoiteChatBuild)\$(PlatformName)\pdb\ - $(ZoiteChatBuild)\$(PlatformName)\rel\ - "$(ProgramFiles)\Inno Setup 5\iscc.exe" - - - - false - $(ZoiteChatObj)$(ProjectName)\ - false - true - MultiByte - - - - - Level3 - NotUsing - 4996 - /d2Zi+ %(AdditionalOptions) - true - - - MaxSpeed - - - true - true - true - NTDDI_VERSION=NTDDI_WIN8;_WIN32_WINNT=_WIN32_WINNT_WIN8;%(PreProcessorDefinitions) - - - true - - - $(ZoiteChatLib)$(TargetName).lib - $(ZoiteChatPdb)$(TargetName).pdb - Windows - Debug - true - true - UseLinkTimeCodeGeneration - - - - - + + + + + + + c:\gtk-build\gtk + c:\gtk-build\gendef + c:\gtk-build\perl-5.20 + c:\gtk-build\python-3.14 + c:\gtk-build\WinSparkle + + + + + x64 + + + + GTK_DISABLE_DEPRECATED;GDK_PIXBUF_DISABLE_DEPRECATED;G_DISABLE_SINGLE_INCLUDES;GDK_PIXBUF_DISABLE_SINGLE_INCLUDES;GTK_DISABLE_SINGLE_INCLUDES;HAVE_X509_GET_SIGNATURE_NID;HAVE_SSL_CTX_GET_SSL_METHOD;DEFAULT_CERT_FILE="cert.pem";HAVE_STRTOULL;strtoull=_strtoui64;strcasecmp=stricmp;strncasecmp=strnicmp;__inline__=__inline;$(GtkDefines) + + + $(YourDepsPath)\$(ZoiteChatPlatform)\release + $(YourGendefPath) + $(YourWinSparklePath)\$(ZoiteChatPlatform) + $(YourPerlPath)\$(ZoiteChatPlatform) + perl520 + + $(YourPython3Path)\$(ZoiteChatPlatform) + python314 + hcpython3 + true + false + + true + false + + true + false + + $(DepsRoot)\include\luajit-2.1 + $(DepsRoot)\include\luajit + $(DepsRoot)\include\lua5.1 + $(DepsRoot)\include\lua51 + hclua + + lua51 + luajit-5.1 + luajit + true + + lua51.dll + luajit-5.1.dll + luajit.dll + + $(DepsRoot)\share\lua\2.1 + $(DepsRoot)\share\lua\5.1 + + $(DepsRoot)\lib\lua\2.1 + $(DepsRoot)\lib\lua\5.1 + + false + + "$(DepsRoot)\bin\glib-genmarshal.exe" + "$(Python3Path)\python.exe" "$(DepsRoot)\bin\glib-genmarshal" + + $(DepsRoot)\include\glib-2.0;$(DepsRoot)\lib\glib-2.0\include;$(DepsRoot)\include\libxml2 + + true + HAVE_GTK3 + $(DepsRoot)\include\gtk-3.0;$(DepsRoot)\lib\gtk-3.0\include + $(DepsRoot)\include\atk-1.0;$(DepsRoot)\include\cairo;$(DepsRoot)\include\pango-1.0;$(DepsRoot)\include\gdk-pixbuf-2.0;$(DepsRoot)\include\harfbuzz + $(Gtk3);$(GtkCommon) + + ssleay32.lib + libeay32.lib + libssl.lib + libcrypto.lib + + $(SslModernLib);$(CryptoModernLib) + $(SslLegacyLib);$(CryptoLegacyLib) + $(DepsRoot)\include + + + gtk-3.lib + gtk-3.0.lib + libgtk-3.lib + libgtk-3.0.lib + + gdk-3.lib + gdk-3.0.lib + libgdk-3.lib + libgdk-3.0.lib + + intl.lib + libintl.lib + + iconv.lib + libiconv.lib + + zlib1.lib + zlib.lib + + libxml2.lib + xml2.lib + libxml2-2.lib + + jpeg.lib + libjpeg.lib + libjpeg-8.lib + libjpeg-9.lib + + libpng16.lib + libpng16_static.lib + libpng.lib + + $(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);$(OpenSslLibs) + + $(SolutionDir)..\data\\ + $(SolutionDir)..\..\zoitechat-build + $(ZoiteChatBuild)\$(ZoiteChatPlatform)\bin\ + $(ZoiteChatBuild)\$(ZoiteChatPlatform)\obj\ + $(ZoiteChatBuild)\$(ZoiteChatPlatform)\lib\ + $(ZoiteChatBuild)\$(ZoiteChatPlatform)\pdb\ + $(ZoiteChatBuild)\$(ZoiteChatPlatform)\rel\ + + "$(ProgramFiles(x86))\Inno Setup 6\ISCC.exe" + "$(ProgramFiles)\Inno Setup 6\ISCC.exe" + + + + + <_ZoiteChatPlatformMismatch Condition="'$(Platform)'!='x64' and '$(PlatformName)'!='x64'">true + + + + + + + false + $(ZoiteChatObj)$(ProjectName)\ + false + true + MultiByte + + + + + Level3 + NotUsing + 4996 + Default + false + /d2Zi+ %(AdditionalOptions) + false + + + + + Full + true + true + true + NTDDI_VERSION=NTDDI_WIN8;_WIN32_WINNT=_WIN32_WINNT_WIN8;%(PreProcessorDefinitions) + + + true + + + $(ZoiteChatLib)$(TargetName).lib + $(ZoiteChatPdb)$(TargetName).pdb + Windows + Debug + true + true + UseLinkTimeCodeGeneration + + + + + diff --git a/win32/zoitechat.sln b/win32/zoitechat.sln index 5a54d943..b45029fa 100644 --- a/win32/zoitechat.sln +++ b/win32/zoitechat.sln @@ -1,7 +1,6 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "..\src\common\common.vcxproj", "{87554B59-006C-4D94-9714-897B27067BA3}" EndProject @@ -201,3 +200,4 @@ Global {4C0F3940-2EEE-4646-82F7-6CE75B9A72F4} = {D237DA6B-BD5F-46C0-8BEA-50E9A1340240} EndGlobalSection EndGlobal +